CAutoComplete.php 10.2 KB
Newer Older
JULIO JARAMILLO's avatar
JULIO JARAMILLO committed
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 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
<?php
/**
 * CAutoComplete class file.
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @link http://www.yiiframework.com/
 * @copyright 2008-2013 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

/**
 * CAutoComplete generates an auto-complete text field.
 *
 * CAutoComplete is based on the {@link http://plugins.jquery.com/project/autocompletex jQuery Autocomplete}.
 *
 * This class is deprecated since Yii 1.1.3. Consider using CJuiAutoComplete.
 * There is {@link http://www.learningjquery.com/2010/06/autocomplete-migration-guide a good migration guide from the author of both JavaScript solutions}.
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @package system.web.widgets
 * @since 1.0
 * @deprecated in 1.1.3
 */
class CAutoComplete extends CInputWidget
{
	/**
	 * @var boolean whether to show the autocomplete using a text area. Defaults to false,
	 * meaning a text field is used.
	 */
	public $textArea=false;
	/**
	 * @var array data that would be saved as client-side data to provide candidate selections.
	 * Each array element can be string or an associative array.
	 * The {@link url} property will be ignored if this property is set.
	 * @see url
	 */
	public $data;
	/**
	 * @var string|array the URL that can return the candidate selections.
	 * A 'q' GET parameter will be sent with the URL which contains what the user has entered so far.
	 * If the URL is given as an array, it is considered as a route to a controller action and will
	 * be used to generate a URL using {@link CController::createUrl};
	 * If the URL is an empty string, the currently requested URL is used.
	 * This property will be ignored if {@link data} is set.
	 * @see data
 	 */
	public $url='';
	/**
	 * @var mixed the CSS file used for the widget. Defaults to null, meaning
	 * using the default CSS file included together with the widget.
	 * If false, no CSS file will be used. Otherwise, the specified CSS file
	 * will be included when using this widget.
	 */
	public $cssFile;
	/**
	 * @var integer the minimum number of characters a user has to type before
	 * the autocompleter activates. Defaults to 1.
	 */
	public $minChars;
	/**
	 * @var integer the delay in milliseconds the autocompleter waits after
	 * a keystroke to activate itself. Defaults to 400.
	 */
	public $delay;
	/**
	 * @var integer the number of backend query results to store in cache.
	 * If set to 1 (the current result), no caching will happen. Must be >= 1. Defaults to 10.
	 */
	public $cacheLength;
	/**
	 * @var boolean whether or not the autocompleter can use a cache for more
	 * specific queries. This means that all matches of "foot" are a subset
	 * of all matches for "foo". Usually this is true, and using this options
	 * decreases server load and increases performance. Only useful with
	 * cacheLength settings bigger than one, like 10. Defaults to true.
	 */
	public $matchSubset;
	/**
	 * @var boolean whether or not the comparison is case sensitive. Important
	 * only if you use caching. Defaults to false.
	 */
	public $matchCase;
	/**
	 * @var boolean whether or not the comparison looks inside
	 * (i.e. does "ba" match "foo bar") the search results. Important only if
	 * you use caching. Don't mix with autofill. Defaults to false.
	 */
	public $matchContains;
	/**
	 * @var boolean if set to true, the autocompleter will only allow results that
	 * are presented by the backend. Note that illegal values result in an empty
	 * input box. Defaults to false.
	 */
	public $mustMatch;
	/**
	 * @var boolean if this is set to true, the first autocomplete value will
	 * be automatically selected on tab/return, even if it has not been handpicked
	 * by keyboard or mouse action. If there is a handpicked (highlighted) result,
	 * that result will take precedence. Defaults to true.
	 */
	public $selectFirst;
	/**
	 * @var array extra parameters for the backend. If you were to specify
	 * array('bar'=>4), the autocompleter would call the backend with a GET
	 * parameter 'bar' 4. The param can be a function that is called to calculate
	 * the param before each request.
	 */
	public $extraParams;
	/**
	 * @var string a javascript function that provides advanced markup for an item.
	 * For each row of results, this function will be called. The returned value will
	 * be displayed inside an LI element in the results list. Autocompleter will
	 * provide 4 parameters: the results row, the position of the row in the list of
	 * results (starting at 1), the number of items in the list of results and the search term.
	 * The default behavior assumes that a single row contains a single value.
	 */
	public $formatItem;
	/**
	 * @var string a javascript function that can be used to limit the data that autocomplete
	 * searches for matches. For example, there may be items you want displayed to the user,
	 * but don't want included in the data that's searched. The function is called with the same arguments
	 * as {@link formatItem}. Defaults to formatItem.
	 */
	public $formatMatch;
	/**
	 * @var string a javascript function that provides the formatting for the value to be
	 * put into the input field. Again three arguments: Data, position (starting with one) and
	 * total number of data. The default behavior assumes either plain data to use as result
	 * or uses the same value as provided by formatItem.
	 */
	public $formatResult;
	/**
	 * @var boolean whether to allow more than one autocompleted-value to enter. Defaults to false.
	 */
	public $multiple;
	/**
	 * @var string seperator to put between values when using multiple option. Defaults to ", ".
	 */
	public $multipleSeparator;
	/**
	 * @var integer specify a custom width for the select box. Defaults to the width of the input element.
	 */
	public $width;
	/**
	 * @var boolean fill the textinput while still selecting a value, replacing the value
	 * if more is typed or something else is selected. Defaults to false.
	 */
	public $autoFill;
	/**
	 * @var integer limit the number of items in the select box. Is also sent as
	 * a "limit" parameter with a remote request. Defaults to 10.
	 */
	public $max;
	/**
	 * @var boolean|string Whether and how to highlight matches in the select box.
	 * Set to false to disable. Set to a javascript function to customize.
	 * The function gets the value as the first argument and the search term as the
	 * second and must return the formatted value. Defaults to Wraps the search term in a &lt;strong&gt; element.
	 */
	public $highlight;
	/**
	 * @var boolean whether to scroll when more results than configured via scrollHeight are available. Defaults to true.
	 */
	public $scroll;
	/**
	 * @var integer height of scrolled autocomplete control in pixels. Defaults to 180.
	 */
	public $scrollHeight;
	/**
	 * @var string the CSS class for the input element. Defaults to "ac_input".
	 */
	public $inputClass;
	/**
	 * @var string the CSS class for the dropdown list. Defaults to "ac_results".
	 */
	public $resultsClass;
	/**
	 * @var string the CSS class used when the data is being loaded from backend. Defaults to "ac_loading".
	 */
	public $loadingClass;
	/**
	 * @var array additional options that can be passed to the constructor of the autocomplete js object.
	 * This allows you to override existing functions of the autocomplete js class (e.g. the parse() function)
	 *
	 * If you want to provide JavaScript native code, you have to wrap the string with {@link CJavaScriptExpression} otherwise it will
	 * be enclosed by quotes.
	 */
	public $options=array();
	/**
	 * @var string the chain of method calls that would be appended at the end of the autocomplete constructor.
	 * For example, ".result(function(...){})" would cause the specified js function to execute
	 * when the user selects an option.
	 */
	public $methodChain;

	/**
	 * Initializes the widget.
	 * This method registers all needed client scripts and renders
	 * the autocomplete input.
	 */
	public function init()
	{
		list($name,$id)=$this->resolveNameID();
		if(isset($this->htmlOptions['id']))
			$id=$this->htmlOptions['id'];
		else
			$this->htmlOptions['id']=$id;
		if(isset($this->htmlOptions['name']))
			$name=$this->htmlOptions['name'];

		$this->registerClientScript();

		if($this->hasModel())
		{
			$field=$this->textArea ? 'activeTextArea' : 'activeTextField';
			echo CHtml::$field($this->model,$this->attribute,$this->htmlOptions);
		}
		else
		{
			$field=$this->textArea ? 'textArea' : 'textField';
			echo CHtml::$field($name,$this->value,$this->htmlOptions);
		}
	}

	/**
	 * Registers the needed CSS and JavaScript.
	 */
	public function registerClientScript()
	{
		$id=$this->htmlOptions['id'];

		$acOptions=$this->getClientOptions();
		$options=$acOptions===array()?'{}' : CJavaScript::encode($acOptions);

		$cs=Yii::app()->getClientScript();
		$cs->registerCoreScript('autocomplete');
		if($this->data!==null)
			$data=CJavaScript::encode($this->data);
		else
		{
			$url=CHtml::normalizeUrl($this->url);
			$data='"'.$url.'"';
		}
		$cs->registerScript('Yii.CAutoComplete#'.$id,"jQuery(\"#{$id}\").legacyautocomplete($data,{$options}){$this->methodChain};");

		if($this->cssFile!==false)
			self::registerCssFile($this->cssFile);
	}

	/**
	 * Registers the needed CSS file.
	 * @param string $url the CSS URL. If null, a default CSS URL will be used.
	 */
	public static function registerCssFile($url=null)
	{
		$cs=Yii::app()->getClientScript();
		if($url===null)
			$url=$cs->getCoreScriptUrl().'/autocomplete/jquery.autocomplete.css';
		$cs->registerCssFile($url);
	}

	/**
	 * @return array the javascript options
	 */
	protected function getClientOptions()
	{
		static $properties=array(
			'minChars', 'delay', 'cacheLength', 'matchSubset',
			'matchCase', 'matchContains', 'mustMatch', 'selectFirst',
			'extraParams', 'multiple', 'multipleSeparator', 'width',
			'autoFill', 'max', 'scroll', 'scrollHeight', 'inputClass',
			'resultsClass', 'loadingClass');
		static $functions=array('formatItem', 'formatMatch', 'formatResult', 'highlight');

		$options=$this->options;
		foreach($properties as $property)
		{
			if($this->$property!==null)
				$options[$property]=$this->$property;
		}
		foreach($functions as $func)
		{
			if($this->$func!==null)
			{
				if($this->$func instanceof CJavaScriptExpression)
					$options[$func]=$this->$func;
				else
					$options[$func]=new CJavaScriptExpression($this->$func);
			}
		}

		return $options;
	}
}