3 * TAutoComplete class file.
5 * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
6 * @link http://www.pradosoft.com/
7 * @copyright Copyright © 2005-2014 PradoSoft
8 * @license http://www.pradosoft.com/license/
9 * @package System.Web.UI.ActiveControls
13 * Load active text box.
15 Prado::using('System.Web.UI.ActiveControls.TActiveTextBox');
16 Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter');
19 * TAutoComplete class.
21 * TAutoComplete is a textbox that provides a list of suggestion on
22 * the current partial word typed in the textbox. The suggestions are
23 * requested using callbacks, and raises the {@link onSuggestion OnSuggestion}
24 * event. The events of the TActiveText (from which TAutoComplete is extended from)
25 * and {@link onSuggestion OnSuggestion} are mutually exculsive. That is,
26 * if {@link onTextChange OnTextChange} and/or {@link onCallback OnCallback}
27 * events are raise, then {@link onSuggestion OnSuggestion} will not be raise, and
30 * The list of suggestions should be set in the {@link onSuggestion OnSuggestion}
31 * event handler. The partial word to match the suggestion is in the
32 * {@link TCallbackEventParameter::getCallbackParameter TCallbackEventParameter::CallbackParameter}
33 * property. The datasource of the TAutoComplete must be set using {@link setDataSource}
34 * method. This sets the datasource for the suggestions repeater, available through
35 * the {@link getSuggestions Suggestions} property. Header, footer templates and
36 * other properties of the repeater can be access via the {@link getSuggestions Suggestions}
37 * property and its sub-properties.
39 * The {@link setTextCssClass TextCssClass} property if set is used to find
40 * the element within the Suggestions.ItemTemplate and Suggestions.AlternatingItemTemplate
41 * that contains the actual text for the suggestion selected. That is,
42 * only text inside elements with CSS class name equal to {@link setTextCssClass TextCssClass}
43 * will be used as suggestions.
45 * To return the list of suggestions back to the browser, supply a non-empty data source
46 * and call databind. For example,
48 * function autocomplete_suggestion($sender, $param)
50 * $token = $param->getToken(); //the partial word to match
51 * $sender->setDataSource($this->getSuggestionsFor($token)); //set suggestions
52 * $sender->dataBind();
56 * The suggestion will be rendered when the {@link dataBind()} method is called
57 * <strong>during a callback request</strong>.
59 * When an suggestion is selected, that is, when the use has clicked, pressed
60 * the "Enter" key, or pressed the "Tab" key, the {@link onSuggestionSelected OnSuggestionSelected}
61 * event is raised. The
62 * {@link TCallbackEventParameter::getCallbackParameter TCallbackEventParameter::CallbackParameter}
63 * property contains the index of the selected suggestion.
65 * TAutoComplete allows multiple suggestions within one textbox with each
66 * word or phrase separated by any characters specified in the
67 * {@link setSeparator Separator} property. The {@link setFrequency Frequency}
68 * and {@link setMinChars MinChars} properties sets the delay and minimum number
69 * of characters typed, respectively, before requesting for sugggestions.
71 * Use {@link onTextChange OnTextChange} and/or {@link onCallback OnCallback} events
72 * to handle post backs due to {@link setAutoPostBack AutoPostBack}.
74 * In the {@link getSuggestions Suggestions} TRepater item template, all HTML text elements
75 * are considered as text for the suggestion. Text within HTML elements with CSS class name
76 * "informal" are ignored as text for suggestions.
78 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
79 * @package System.Web.UI.ActiveControls
82 class TAutoComplete extends TActiveTextBox implements INamingContainer
85 * @var ITemplate template for repeater items
87 private $_repeater=null;
89 * @var TPanel result panel holding the suggestion items.
91 private $_resultPanel=null;
94 * @return string word or token separators (delimiters).
96 public function getSeparator()
98 return $this->getViewState('tokens', '');
102 * @return string word or token separators (delimiters).
104 public function setSeparator($value)
106 $this->setViewState('tokens', TPropertyValue::ensureString($value), '');
110 * @return float maximum delay (in seconds) before requesting a suggestion.
112 public function getFrequency()
114 return $this->getViewState('frequency', '');
118 * @param float maximum delay (in seconds) before requesting a suggestion.
121 public function setFrequency($value)
123 $this->setViewState('frequency', TPropertyValue::ensureFloat($value),'');
127 * @return integer minimum number of characters before requesting a suggestion.
129 public function getMinChars()
131 return $this->getViewState('minChars','');
135 * @param integer minimum number of characters before requesting a suggestion.
137 public function setMinChars($value)
139 $this->setViewState('minChars', TPropertyValue::ensureInteger($value), '');
143 * @param string Css class name of the element to use for suggestion.
145 public function setTextCssClass($value)
147 $this->setViewState('TextCssClass', $value);
151 * @return string Css class name of the element to use for suggestion.
153 public function getTextCssClass()
155 return $this->getViewState('TextCssClass');
159 * Raises the callback event. This method is overrides the parent implementation.
160 * If {@link setAutoPostBack AutoPostBack} is enabled it will raise
161 * {@link onTextChanged OnTextChanged} event event and then the
162 * {@link onCallback OnCallback} event. The {@link onSuggest OnSuggest} event is
163 * raise if the request is to find sugggestions, the {@link onTextChanged OnTextChanged}
164 * and {@link onCallback OnCallback} events are <b>NOT</b> raised.
165 * This method is mainly used by framework and control developers.
166 * @param TCallbackEventParameter the event parameter
168 public function raiseCallbackEvent($param)
170 $token = $param->getCallbackParameter();
171 if(is_array($token) && count($token) == 2)
173 if($token[1] === '__TAutoComplete_onSuggest__')
175 $parameter = new TAutoCompleteEventParameter($this->getResponse(), $token[0]);
176 $this->onSuggest($parameter);
178 else if($token[1] === '__TAutoComplete_onSuggestionSelected__')
180 $parameter = new TAutoCompleteEventParameter($this->getResponse(), null, $token[0]);
181 $this->onSuggestionSelected($parameter);
184 else if($this->getAutoPostBack())
185 parent::raiseCallbackEvent($param);
189 * This method is invoked when an autocomplete suggestion is requested.
190 * The method raises 'OnSuggest' event. If you override this
191 * method, be sure to call the parent implementation so that the event
192 * handler can be invoked.
193 * @param TCallbackEventParameter event parameter to be passed to the event handlers
195 public function onSuggest($param)
197 $this->raiseEvent('OnSuggest', $this, $param);
201 * This method is invoked when an autocomplete suggestion is selected.
202 * The method raises 'OnSuggestionSelected' event. If you override this
203 * method, be sure to call the parent implementation so that the event
204 * handler can be invoked.
205 * @param TCallbackEventParameter event parameter to be passed to the event handlers
207 public function onSuggestionSelected($param)
209 $this->raiseEvent('OnSuggestionSelected', $this, $param);
213 * @param array data source for suggestions.
215 public function setDataSource($data)
217 $this->getSuggestions()->setDataSource($data);
221 * Overrides parent implementation. Callback {@link renderSuggestions()} when
222 * page's IsCallback property is true.
224 public function dataBind()
227 if($this->getPage()->getIsCallback())
228 $this->renderSuggestions($this->getResponse()->createHtmlWriter());
232 * @return TPanel suggestion results panel.
234 public function getResultPanel()
236 if($this->_resultPanel===null)
237 $this->_resultPanel = $this->createResultPanel();
238 return $this->_resultPanel;
242 * @return TPanel new instance of result panel. Default uses TPanel.
244 protected function createResultPanel()
246 $panel = Prado::createComponent('System.Web.UI.WebControls.TPanel');
247 $this->getControls()->add($panel);
248 $panel->setID('result');
253 * @return TRepeater suggestion list repeater
255 public function getSuggestions()
257 if($this->_repeater===null)
258 $this->_repeater = $this->createRepeater();
259 return $this->_repeater;
263 * @return TRepeater new instance of TRepater to render the list of suggestions.
265 protected function createRepeater()
267 $repeater = Prado::createComponent('System.Web.UI.WebControls.TRepeater');
268 $repeater->setHeaderTemplate(new TAutoCompleteTemplate('<ul>'));
269 $repeater->setFooterTemplate(new TAutoCompleteTemplate('</ul>'));
270 $repeater->setItemTemplate(new TTemplate('<li><%# $this->DataItem %></li>',null));
271 $repeater->setEmptyTemplate(new TAutoCompleteTemplate('<ul></ul>'));
272 $this->getControls()->add($repeater);
277 * Renders the end tag and registers javascript effects library.
279 public function renderEndTag($writer)
281 $this->getPage()->getClientScript()->registerPradoScript('effects');
282 parent::renderEndTag($writer);
283 $this->renderResultPanel($writer);
287 * Renders the result panel.
288 * @param THtmlWriter the renderer.
290 protected function renderResultPanel($writer)
292 $this->getResultPanel()->render($writer);
296 * Renders the suggestions during a callback respones.
297 * @param THtmlWriter the renderer.
299 public function renderCallback($writer)
301 $this->renderSuggestions($writer);
305 * Renders the suggestions repeater.
306 * @param THtmlWriter the renderer.
308 public function renderSuggestions($writer)
310 if($this->getActiveControl()->canUpdateClientSide())
312 $this->getSuggestions()->render($writer);
313 $boundary = $writer->getWriter()->getBoundary();
314 $this->getResponse()->getAdapter()->setResponseData($boundary);
319 * @return array list of callback options.
321 protected function getPostBackOptions()
323 //disallow page state update ?
324 //$this->getActiveControl()->getClientSide()->setEnablePageStateUpdate(false);
326 if(strlen($string = $this->getSeparator()))
328 $string = strtr($string,array('\t'=>"\t",'\n'=>"\n",'\r'=>"\r"));
329 $token = preg_split('//', $string, -1, PREG_SPLIT_NO_EMPTY);
330 $options['tokens'] = $token;
332 if($this->getAutoPostBack())
334 $options = array_merge($options,parent::getPostBackOptions());
335 $options['AutoPostBack'] = true;
337 if(strlen($select = $this->getTextCssClass()))
338 $options['select'] = $select;
339 $options['ResultPanel'] = $this->getResultPanel()->getClientID();
340 $options['ID'] = $this->getClientID();
341 $options['EventTarget'] = $this->getUniqueID();
342 if(($minchars=$this->getMinChars())!=='')
343 $options['minChars'] = $minchars;
344 if(($frequency=$this->getFrequency())!=='')
345 $options['frequency'] = $frequency;
346 $options['CausesValidation'] = $this->getCausesValidation();
347 $options['ValidationGroup'] = $this->getValidationGroup();
352 * Override parent implementation, no javascript is rendered here instead
353 * the javascript required for active control is registered in {@link addAttributesToRender}.
355 protected function renderClientControlScript($writer)
360 * @return string corresponding javascript class name for this TActiveButton.
362 protected function getClientClassName()
364 return 'Prado.WebUI.TAutoComplete';
369 * TAutCompleteEventParameter contains the {@link getToken Token} requested by
370 * the user for a partial match of the suggestions.
372 * The {@link getSelectedIndex SelectedIndex} is a zero-based index of the
373 * suggestion selected by the user, -1 if not suggestion is selected.
375 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
376 * @package System.Web.UI.ActiveControls
379 class TAutoCompleteEventParameter extends TCallbackEventParameter
381 private $_selectedIndex=-1;
384 * Creates a new TCallbackEventParameter.
386 public function __construct($response, $parameter, $index=-1)
388 parent::__construct($response, $parameter);
389 $this->_selectedIndex=$index;
393 * @return int selected suggestion zero-based index, -1 if not selected.
395 public function getSelectedIndex()
397 return $this->_selectedIndex;
401 * @return string token for matching a list of suggestions.
403 public function getToken()
405 return $this->getCallbackParameter();
410 * TAutoCompleteTemplate class.
412 * TAutoCompleteTemplate is the default template for TAutoCompleteTemplate
415 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
416 * @package System.Web.UI.ActiveControls
419 class TAutoCompleteTemplate extends TComponent implements ITemplate
423 public function __construct($template)
425 $this->_template = $template;
428 * Instantiates the template.
429 * It creates a {@link TDataList} control.
430 * @param TControl parent to hold the content within the template
432 public function instantiateIn($parent)
434 $parent->getControls()->add($this->_template);