]> git.sur5r.net Git - bacula/bacula/blob - gui/baculum/framework/Web/UI/ActiveControls/TAutoComplete.php
baculum: Update PRADO framework from v3.2.3 to v3.2.4
[bacula/bacula] / gui / baculum / framework / Web / UI / ActiveControls / TAutoComplete.php
1 <?php
2 /**
3  * TAutoComplete class file.
4  *
5  * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
6  * @link http://www.pradosoft.com/
7  * @copyright Copyright &copy; 2005-2014 PradoSoft
8  * @license http://www.pradosoft.com/license/
9  * @package System.Web.UI.ActiveControls
10  */
11
12 /**
13  * Load active text box.
14  */
15 Prado::using('System.Web.UI.ActiveControls.TActiveTextBox');
16 Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter');
17
18 /**
19  * TAutoComplete class.
20  *
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
28  * vice versa.
29  *
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.
38  *
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.
44  *
45  * To return the list of suggestions back to the browser, supply a non-empty data source
46  * and call databind. For example,
47  * <code>
48  * function autocomplete_suggestion($sender, $param)
49  * {
50  *   $token = $param->getToken(); //the partial word to match
51  *   $sender->setDataSource($this->getSuggestionsFor($token)); //set suggestions
52  *   $sender->dataBind();
53  * }
54  * </code>
55  *
56  * The suggestion will be rendered when the {@link dataBind()} method is called
57  * <strong>during a callback request</strong>.
58  *
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.
64  *
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.
70  *
71  * Use {@link onTextChange OnTextChange} and/or {@link onCallback OnCallback} events
72  * to handle post backs due to {@link setAutoPostBack AutoPostBack}.
73  *
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.
77  *
78  * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
79  * @package System.Web.UI.ActiveControls
80  * @since 3.1
81  */
82 class TAutoComplete extends TActiveTextBox implements INamingContainer
83 {
84         /**
85          * @var ITemplate template for repeater items
86          */
87         private $_repeater=null;
88         /**
89          * @var TPanel result panel holding the suggestion items.
90          */
91         private $_resultPanel=null;
92
93         /**
94          * @return string word or token separators (delimiters).
95          */
96         public function getSeparator()
97         {
98                 return $this->getViewState('tokens', '');
99         }
100
101         /**
102          * @return string word or token separators (delimiters).
103          */
104         public function setSeparator($value)
105         {
106                 $this->setViewState('tokens', TPropertyValue::ensureString($value), '');
107         }
108
109         /**
110          * @return float maximum delay (in seconds) before requesting a suggestion.
111          */
112         public function getFrequency()
113         {
114                 return $this->getViewState('frequency', '');
115         }
116
117         /**
118          * @param float maximum delay (in seconds) before requesting a suggestion.
119          * Default is 0.4.
120          */
121         public function setFrequency($value)
122         {
123                 $this->setViewState('frequency', TPropertyValue::ensureFloat($value),'');
124         }
125
126         /**
127          * @return integer minimum number of characters before requesting a suggestion.
128          */
129         public function getMinChars()
130         {
131                 return $this->getViewState('minChars','');
132         }
133
134         /**
135          * @param integer minimum number of characters before requesting a suggestion.
136          */
137         public function setMinChars($value)
138         {
139                 $this->setViewState('minChars', TPropertyValue::ensureInteger($value), '');
140         }
141
142         /**
143          * @param string Css class name of the element to use for suggestion.
144          */
145         public function setTextCssClass($value)
146         {
147                 $this->setViewState('TextCssClass', $value);
148         }
149
150         /**
151          * @return string Css class name of the element to use for suggestion.
152          */
153         public function getTextCssClass()
154         {
155                 return $this->getViewState('TextCssClass');
156         }
157
158         /**
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
167          */
168         public function raiseCallbackEvent($param)
169         {
170                 $token = $param->getCallbackParameter();
171                 if(is_array($token) && count($token) == 2)
172                 {
173                         if($token[1] === '__TAutoComplete_onSuggest__')
174                         {
175                                 $parameter = new TAutoCompleteEventParameter($this->getResponse(), $token[0]);
176                                 $this->onSuggest($parameter);
177                         }
178                         else if($token[1] === '__TAutoComplete_onSuggestionSelected__')
179                         {
180                                 $parameter = new TAutoCompleteEventParameter($this->getResponse(), null, $token[0]);
181                                 $this->onSuggestionSelected($parameter);
182                         }
183                 }
184                 else if($this->getAutoPostBack())
185                         parent::raiseCallbackEvent($param);
186         }
187
188         /**
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
194          */
195         public function onSuggest($param)
196         {
197                 $this->raiseEvent('OnSuggest', $this, $param);
198         }
199
200         /**
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
206          */
207         public function onSuggestionSelected($param)
208         {
209                 $this->raiseEvent('OnSuggestionSelected', $this, $param);
210         }
211
212         /**
213          * @param array data source for suggestions.
214          */
215         public function setDataSource($data)
216         {
217                 $this->getSuggestions()->setDataSource($data);
218         }
219
220         /**
221          * Overrides parent implementation. Callback {@link renderSuggestions()} when
222          * page's IsCallback property is true.
223          */
224         public function dataBind()
225         {
226                 parent::dataBind();
227                 if($this->getPage()->getIsCallback())
228                         $this->renderSuggestions($this->getResponse()->createHtmlWriter());
229         }
230
231         /**
232          * @return TPanel suggestion results panel.
233          */
234         public function getResultPanel()
235         {
236                 if($this->_resultPanel===null)
237                         $this->_resultPanel = $this->createResultPanel();
238                 return $this->_resultPanel;
239         }
240
241         /**
242          * @return TPanel new instance of result panel. Default uses TPanel.
243          */
244         protected function createResultPanel()
245         {
246                 $panel = Prado::createComponent('System.Web.UI.WebControls.TPanel');
247                 $this->getControls()->add($panel);
248                 $panel->setID('result');
249                 return $panel;
250         }
251
252         /**
253          * @return TRepeater suggestion list repeater
254          */
255         public function getSuggestions()
256         {
257                 if($this->_repeater===null)
258                         $this->_repeater = $this->createRepeater();
259                 return $this->_repeater;
260         }
261
262         /**
263          * @return TRepeater new instance of TRepater to render the list of suggestions.
264          */
265         protected function createRepeater()
266         {
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);
273                 return $repeater;
274         }
275
276         /**
277          * Renders the end tag and registers javascript effects library.
278          */
279         public function renderEndTag($writer)
280         {
281                 $this->getPage()->getClientScript()->registerPradoScript('effects');
282                 parent::renderEndTag($writer);
283                 $this->renderResultPanel($writer);
284         }
285
286         /**
287          * Renders the result panel.
288          * @param THtmlWriter the renderer.
289          */
290         protected function renderResultPanel($writer)
291         {
292                 $this->getResultPanel()->render($writer);
293         }
294
295         /**
296          * Renders the suggestions during a callback respones.
297          * @param THtmlWriter the renderer.
298          */
299         public function renderCallback($writer)
300         {
301                 $this->renderSuggestions($writer);
302         }
303
304         /**
305          * Renders the suggestions repeater.
306          * @param THtmlWriter the renderer.
307          */
308         public function renderSuggestions($writer)
309         {
310                 if($this->getActiveControl()->canUpdateClientSide())
311                 {
312                         $this->getSuggestions()->render($writer);
313                         $boundary = $writer->getWriter()->getBoundary();
314                         $this->getResponse()->getAdapter()->setResponseData($boundary);
315                 }
316         }
317
318         /**
319          * @return array list of callback options.
320          */
321         protected function getPostBackOptions()
322         {
323                 //disallow page state update ?
324                 //$this->getActiveControl()->getClientSide()->setEnablePageStateUpdate(false);
325                 $options = array();
326                 if(strlen($string = $this->getSeparator()))
327                 {
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;
331                 }
332                 if($this->getAutoPostBack())
333                 {
334                         $options = array_merge($options,parent::getPostBackOptions());
335                         $options['AutoPostBack'] = true;
336                 }
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();
348                 return $options;
349         }
350
351         /**
352          * Override parent implementation, no javascript is rendered here instead
353          * the javascript required for active control is registered in {@link addAttributesToRender}.
354          */
355         protected function renderClientControlScript($writer)
356         {
357         }
358
359         /**
360          * @return string corresponding javascript class name for this TActiveButton.
361          */
362         protected function getClientClassName()
363         {
364                 return 'Prado.WebUI.TAutoComplete';
365         }
366 }
367
368 /**
369  * TAutCompleteEventParameter contains the {@link getToken Token} requested by
370  * the user for a partial match of the suggestions.
371  *
372  * The {@link getSelectedIndex SelectedIndex} is a zero-based index of the
373  * suggestion selected by the user, -1 if not suggestion is selected.
374  *
375  * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
376  * @package System.Web.UI.ActiveControls
377  * @since 3.1
378  */
379 class TAutoCompleteEventParameter extends TCallbackEventParameter
380 {
381         private $_selectedIndex=-1;
382
383         /**
384          * Creates a new TCallbackEventParameter.
385          */
386         public function __construct($response, $parameter, $index=-1)
387         {
388                 parent::__construct($response, $parameter);
389                 $this->_selectedIndex=$index;
390         }
391
392         /**
393          * @return int selected suggestion zero-based index, -1 if not selected.
394          */
395         public function getSelectedIndex()
396         {
397                 return $this->_selectedIndex;
398         }
399
400         /**
401          * @return string token for matching a list of suggestions.
402          */
403         public function getToken()
404         {
405                 return $this->getCallbackParameter();
406         }
407 }
408
409 /**
410  * TAutoCompleteTemplate class.
411  *
412  * TAutoCompleteTemplate is the default template for TAutoCompleteTemplate
413  * item template.
414  *
415  * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
416  * @package System.Web.UI.ActiveControls
417  * @since 3.1
418  */
419 class TAutoCompleteTemplate extends TComponent implements ITemplate
420 {
421         private $_template;
422
423         public function __construct($template)
424         {
425                 $this->_template = $template;
426         }
427         /**
428          * Instantiates the template.
429          * It creates a {@link TDataList} control.
430          * @param TControl parent to hold the content within the template
431          */
432         public function instantiateIn($parent)
433         {
434                 $parent->getControls()->add($this->_template);
435         }
436 }
437