MaskedInput.php 3.74 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace yii\widgets;

use yii\base\InvalidConfigException;
use yii\helpers\Html;
use yii\helpers\Json;
use yii\web\JsExpression;

/**
 * MaskedInput generates a masked text input.
 *
 * MaskedInput is similar to [[Html::textInput()]] except that
 * an input mask will be used to force users to enter properly formatted data,
 * such as phone numbers, social security numbers.
 * 
 * To use MaskedInput, you must set the [[mask]] property. The following example
 * shows how to use MaskedInput to collect phone numbers:
 * 
 * ~~~
 * echo MaskedInput::widget(array(
 *     'name' => 'phone',
 *     'mask' => '999-999-9999',
 * ));
 * ~~~
 * 
 * The masked text field is implemented based on the [jQuery masked input plugin](http://digitalbush.com/projects/masked-input-plugin).
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
class MaskedInput extends InputWidget
{
	/**
	 * @var string the input mask (e.g. '99/99/9999' for date input). The following characters are predefined:
	 *
	 * - `a`: represents an alpha character (A-Z,a-z)
	 * - `9`: represents a numeric character (0-9)
	 * - `*`: represents an alphanumeric character (A-Z,a-z,0-9)
	 * - `?`: anything listed after '?' within the mask is considered optional user input
	 *
	 * Additional characters can be defined by specifying the [[charMap]] property.
	 */
	public $mask;
	/**
	 * @var array the mapping between mask characters and the corresponding patterns.
	 * For example, `array('~' => '[+-]')` specifies that the '~' character expects '+' or '-' input.
	 * Defaults to null, meaning using the map as described in [[mask]].
	 */
	public $charMap;
	/**
	 * @var string the character prompting for user input. Defaults to underscore '_'.
	 */
	public $placeholder;
	/**
	 * @var string a JavaScript function callback that will be invoked when user finishes the input.
	 */
	public $completed;
	/**
	 * @var array the HTML attributes for the input tag.
	 */
	public $options = array();


	/**
	 * Initializes the widget.
	 * @throws InvalidConfigException if the "mask" property is not set.
	 */
	public function init()
	{
		parent::init();
		if (empty($this->mask)) {
			throw new InvalidConfigException('The "mask" property must be set.');
		}

		if (!isset($this->options['id'])) {
			$this->options['id'] = $this->hasModel() ? Html::getInputId($this->model, $this->attribute) : $this->getId();
		}
	}

	/**
	 * Runs the widget.
	 */
	public function run()
	{
		if ($this->hasModel()) {
			echo Html::activeTextInput($this->model, $this->attribute, $this->options);
		} else {
			echo Html::textInput($this->name, $this->value, $this->options);
		}
		$this->registerClientScript();
	}

	/**
	 * Registers the needed JavaScript.
	 */
	public function registerClientScript()
	{
		$options = $this->getClientOptions();
		$options = empty($options) ? '' : ',' . Json::encode($options);
		$js = '';
		if (is_array($this->charMap) && !empty($this->charMap)) {
			$js .= 'jQuery.mask.definitions=' . Json::encode($this->charMap) . ";\n";
		}
		$id = $this->options['id'];
		$js .= "jQuery(\"#{$id}\").mask(\"{$this->mask}\"{$options});";
		$this->getView()->registerAssetBundle('yii/maskedinput');
		$this->getView()->registerJs($js);
	}

	/**
	 * @return array the options for the text field
	 */
	protected function getClientOptions()
	{
		$options = array();
		if ($this->placeholder !== null) {
			$options['placeholder'] = $this->placeholder;
		}

		if ($this->completed !== null) {
			if ($this->completed instanceof JsExpression) {
				$options['completed'] = $this->completed;
			} else {
				$options['completed'] = new JsExpression($this->completed);
			}
		}

		return $options;
	}
}