Subversion-Projekte lars-tiefland.prado

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 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-2008 PradoSoft
8
 * @license http://www.pradosoft.com/license/
9
 * @version $Id: TAutoComplete.php 2564 2008-11-11 21:56:02Z carlgmathisen $
10
 * @package System.Web.UI.ActiveControls
11
 */
12
 
13
/**
14
 * Load active text box.
15
 */
16
Prado::using('System.Web.UI.ActiveControls.TActiveTextBox');
17
Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter');
18
 
19
/**
20
 * TAutoComplete class.
21
 *
22
 * TAutoComplete is a textbox that provides a list of suggestion on
23
 * the current partial word typed in the textbox. The suggestions are
24
 * requested using callbacks, and raises the {@link onSuggestion OnSuggestion}
25
 * event. The events of the TActiveText (from which TAutoComplete is extended from)
26
 * and {@link onSuggestion OnSuggestion} are mutually exculsive. That is,
27
 * if {@link onTextChange OnTextChange} and/or {@link onCallback OnCallback}
28
 * events are raise, then {@link onSuggestion OnSuggestion} will not be raise, and
29
 * vice versa.
30
 *
31
 * The list of suggestions should be set in the {@link onSuggestion OnSuggestion}
32
 * event handler. The partial word to match the suggestion is in the
33
 * {@link TCallbackEventParameter::getCallbackParameter TCallbackEventParameter::CallbackParameter}
34
 * property. The datasource of the TAutoComplete must be set using {@link setDataSource}
35
 * method. This sets the datasource for the suggestions repeater, available through
36
 * the {@link getSuggestions Suggestions} property. Header, footer templates and
37
 * other properties of the repeater can be access via the {@link getSuggestions Suggestions}
38
 * property and its sub-properties.
39
 *
40
 * The {@link setTextCssClass TextCssClass} property if set is used to find
41
 * the element within the Suggestions.ItemTemplate and Suggestions.AlternatingItemTemplate
42
 * that contains the actual text for the suggestion selected. That is,
43
 * only text inside elements with CSS class name equal to {@link setTextCssClass TextCssClass}
44
 * will be used as suggestions.
45
 *
46
 * To return the list of suggestions back to the browser, supply a non-empty data source
47
 * and call databind. For example,
48
 * <code>
49
 * function autocomplete_suggestion($sender, $param)
50
 * {
51
 *   $token = $param->getToken(); //the partial word to match
52
 *   $sender->setDataSource($this->getSuggestionsFor($token)); //set suggestions
53
 *   $sender->dataBind();
54
 * }
55
 * </code>
56
 *
57
 * The suggestion will be rendered when the {@link dataBind()} method is called
58
 * <strong>during a callback request</strong>.
59
 *
60
 * When an suggestion is selected, that is, when the use has clicked, pressed
61
 * the "Enter" key, or pressed the "Tab" key, the {@link onSuggestionSelected OnSuggestionSelected}
62
 * event is raised. The
63
 * {@link TCallbackEventParameter::getCallbackParameter TCallbackEventParameter::CallbackParameter}
64
 * property contains the index of the selected suggestion.
65
 *
66
 * TAutoComplete allows multiple suggestions within one textbox with each
67
 * word or phrase separated by any characters specified in the
68
 * {@link setSeparator Separator} property. The {@link setFrequency Frequency}
69
 * and {@link setMinChars MinChars} properties sets the delay and minimum number
70
 * of characters typed, respectively, before requesting for sugggestions.
71
 *
72
 * Use {@link onTextChange OnTextChange} and/or {@link onCallback OnCallback} events
73
 * to handle post backs due to {@link setAutoPostBack AutoPostBack}.
74
 *
75
 * In the {@link getSuggestions Suggestions} TRepater item template, all HTML text elements
76
 * are considered as text for the suggestion. Text within HTML elements with CSS class name
77
 * "informal" are ignored as text for suggestions.
78
 *
79
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
80
 * @version $Id: TAutoComplete.php 2564 2008-11-11 21:56:02Z carlgmathisen $
81
 * @package System.Web.UI.ActiveControls
82
 * @since 3.1
83
 */
84
class TAutoComplete extends TActiveTextBox implements INamingContainer
85
{
86
	/**
87
	 * @var ITemplate template for repeater items
88
	 */
89
	private $_repeater=null;
90
	/**
91
	 * @var TPanel result panel holding the suggestion items.
92
	 */
93
	private $_resultPanel=null;
94
 
95
	/**
96
	 * @return string word or token separators (delimiters).
97
	 */
98
	public function getSeparator()
99
	{
100
		return $this->getViewState('tokens', '');
101
	}
102
 
103
	/**
104
	 * @return string word or token separators (delimiters).
105
	 */
106
	public function setSeparator($value)
107
	{
108
		$this->setViewState('tokens', TPropertyValue::ensureString($value), '');
109
	}
110
 
111
	/**
112
	 * @return float maximum delay (in seconds) before requesting a suggestion.
113
	 */
114
	public function getFrequency()
115
	{
116
		return $this->getViewState('frequency', '');
117
	}
118
 
119
	/**
120
	 * @param float maximum delay (in seconds) before requesting a suggestion.
121
	 * Default is 0.4.
122
	 */
123
	public function setFrequency($value)
124
	{
125
		$this->setViewState('frequency', TPropertyValue::ensureFloat($value),'');
126
	}
127
 
128
	/**
129
	 * @return integer minimum number of characters before requesting a suggestion.
130
	 */
131
	public function getMinChars()
132
	{
133
		return $this->getViewState('minChars','');
134
	}
135
 
136
	/**
137
	 * @param integer minimum number of characters before requesting a suggestion.
138
	 */
139
	public function setMinChars($value)
140
	{
141
		$this->setViewState('minChars', TPropertyValue::ensureInteger($value), '');
142
	}
143
 
144
	/**
145
	 * @param string Css class name of the element to use for suggestion.
146
	 */
147
	public function setTextCssClass($value)
148
	{
149
		$this->setViewState('TextCssClass', $value);
150
	}
151
 
152
	/**
153
	 * @return string Css class name of the element to use for suggestion.
154
	 */
155
	public function getTextCssClass()
156
	{
157
		return $this->getViewState('TextCssClass');
158
	}
159
 
160
	/**
161
	 * Raises the callback event. This method is overrides the parent implementation.
162
	 * If {@link setAutoPostBack AutoPostBack} is enabled it will raise
163
	 * {@link onTextChanged OnTextChanged} event event and then the
164
	 * {@link onCallback OnCallback} event. The {@link onSuggest OnSuggest} event is
165
	 * raise if the request is to find sugggestions, the {@link onTextChanged OnTextChanged}
166
	 * and {@link onCallback OnCallback} events are <b>NOT</b> raised.
167
	 * This method is mainly used by framework and control developers.
168
	 * @param TCallbackEventParameter the event parameter
169
	 */
170
 	public function raiseCallbackEvent($param)
171
	{
172
		$token = $param->getCallbackParameter();
173
		if(is_array($token) && count($token) == 2)
174
		{
175
			if($token[1] === '__TAutoComplete_onSuggest__')
176
			{
177
				$parameter = new TAutoCompleteEventParameter($this->getResponse(), $token[0]);
178
				$this->onSuggest($parameter);
179
			}
180
			else if($token[1] === '__TAutoComplete_onSuggestionSelected__')
181
			{
182
				$parameter = new TAutoCompleteEventParameter($this->getResponse(), null, $token[0]);
183
				$this->onSuggestionSelected($parameter);
184
			}
185
		}
186
		else if($this->getAutoPostBack())
187
			parent::raiseCallbackEvent($param);
188
	}
189
 
190
	/**
191
	 * This method is invoked when an autocomplete suggestion is requested.
192
	 * The method raises 'OnSuggest' event. If you override this
193
	 * method, be sure to call the parent implementation so that the event
194
	 * handler can be invoked.
195
	 * @param TCallbackEventParameter event parameter to be passed to the event handlers
196
	 */
197
	public function onSuggest($param)
198
	{
199
		$this->raiseEvent('OnSuggest', $this, $param);
200
	}
201
 
202
	/**
203
	 * This method is invoked when an autocomplete suggestion is selected.
204
	 * The method raises 'OnSuggestionSelected' event. If you override this
205
	 * method, be sure to call the parent implementation so that the event
206
	 * handler can be invoked.
207
	 * @param TCallbackEventParameter event parameter to be passed to the event handlers
208
	 */
209
	public function onSuggestionSelected($param)
210
	{
211
		$this->raiseEvent('OnSuggestionSelected', $this, $param);
212
	}
213
 
214
	/**
215
	 * @param array data source for suggestions.
216
	 */
217
	public function setDataSource($data)
218
	{
219
		$this->getSuggestions()->setDataSource($data);
220
	}
221
 
222
	/**
223
	 * Overrides parent implementation. Callback {@link renderSuggestions()} when
224
	 * page's IsCallback property is true.
225
	 */
226
	public function dataBind()
227
	{
228
		parent::dataBind();
229
		if($this->getPage()->getIsCallback())
230
			$this->renderSuggestions($this->getResponse()->createHtmlWriter());
231
	}
232
 
233
	/**
234
	 * @return TPanel suggestion results panel.
235
	 */
236
	public function getResultPanel()
237
	{
238
		if(is_null($this->_resultPanel))
239
			$this->_resultPanel = $this->createResultPanel();
240
		return $this->_resultPanel;
241
	}
242
 
243
	/**
244
	 * @return TPanel new instance of result panel. Default uses TPanel.
245
	 */
246
	protected function createResultPanel()
247
	{
248
		$panel = Prado::createComponent('System.Web.UI.WebControls.TPanel');
249
		$this->getControls()->add($panel);
250
		$panel->setID('result');
251
		return $panel;
252
	}
253
 
254
	/**
255
	 * @return TRepeater suggestion list repeater
256
	 */
257
	public function getSuggestions()
258
	{
259
		if(is_null($this->_repeater))
260
			$this->_repeater = $this->createRepeater();
261
		return $this->_repeater;
262
	}
263
 
264
	/**
265
	 * @return TRepeater new instance of TRepater to render the list of suggestions.
266
	 */
267
	protected function createRepeater()
268
	{
269
		$repeater = Prado::createComponent('System.Web.UI.WebControls.TRepeater');
270
		$repeater->setHeaderTemplate(new TAutoCompleteTemplate('<ul>'));
271
		$repeater->setFooterTemplate(new TAutoCompleteTemplate('</ul>'));
272
		$repeater->setItemTemplate(new TTemplate('<li><%# $this->DataItem %></li>',null));
273
		$this->getControls()->add($repeater);
274
		return $repeater;
275
	}
276
 
277
	/**
278
	 * Renders the end tag and registers javascript effects library.
279
	 */
280
	public function renderEndTag($writer)
281
	{
282
		$this->getPage()->getClientScript()->registerPradoScript('effects');
283
		parent::renderEndTag($writer);
284
		$this->renderResultPanel($writer);
285
	}
286
 
287
	/**
288
	 * Renders the result panel.
289
	 * @param THtmlWriter the renderer.
290
	 */
291
	protected function renderResultPanel($writer)
292
	{
293
		$this->getResultPanel()->render($writer);
294
	}
295
 
296
	/**
297
	 * Renders the suggestions during a callback respones.
298
	 * @param THtmlWriter the renderer.
299
	 */
300
	public function renderCallback($writer)
301
	{
302
		$this->renderSuggestions($writer);
303
	}
304
 
305
	/**
306
	 * Renders the suggestions repeater.
307
	 * @param THtmlWriter the renderer.
308
	 */
309
	public function renderSuggestions($writer)
310
	{
311
		if($this->getActiveControl()->canUpdateClientSide())
312
		{
313
			$this->getSuggestions()->render($writer);
314
			$boundary = $writer->getWriter()->getBoundary();
315
			$this->getResponse()->getAdapter()->setResponseData($boundary);
316
		}
317
	}
318
 
319
	/**
320
	 * @return array list of callback options.
321
	 */
322
	protected function getPostBackOptions()
323
	{
324
		//disallow page state update ?
325
		//$this->getActiveControl()->getClientSide()->setEnablePageStateUpdate(false);
326
		$options = array();
327
		if(strlen($string = $this->getSeparator()))
328
		{
329
			$string = strtr($string,array('\t'=>"\t",'\n'=>"\n",'\r'=>"\r"));
330
			$token = preg_split('//', $string, -1, PREG_SPLIT_NO_EMPTY);
331
			$options['tokens'] = TJavaScript::encode($token,false);
332
		}
333
		if($this->getAutoPostBack())
334
		{
335
			$options = array_merge($options,parent::getPostBackOptions());
336
			$options['AutoPostBack'] = true;
337
		}
338
		if(strlen($select = $this->getTextCssClass()))
339
			$options['select'] = $select;
340
		$options['ResultPanel'] = $this->getResultPanel()->getClientID();
341
		$options['ID'] = $this->getClientID();
342
		$options['EventTarget'] = $this->getUniqueID();
343
		if(($minchars=$this->getMinChars())!=='')
344
			$options['minChars'] = $minchars;
345
		if(($frequency=$this->getFrequency())!=='')
346
			$options['frequency'] = $frequency;
347
		$options['CausesValidation'] = $this->getCausesValidation();
348
		$options['ValidationGroup'] = $this->getValidationGroup();
349
		return $options;
350
	}
351
 
352
	/**
353
	 * Override parent implementation, no javascript is rendered here instead
354
	 * the javascript required for active control is registered in {@link addAttributesToRender}.
355
	 */
356
	protected function renderClientControlScript($writer)
357
	{
358
	}
359
 
360
	/**
361
	 * @return string corresponding javascript class name for this TActiveButton.
362
	 */
363
	protected function getClientClassName()
364
	{
365
		return 'Prado.WebUI.TAutoComplete';
366
	}
367
}
368
 
369
/**
370
 * TAutCompleteEventParameter contains the {@link getToken Token} requested by
371
 * the user for a partial match of the suggestions.
372
 *
373
 * The {@link getSelectedIndex SelectedIndex} is a zero-based index of the
374
 * suggestion selected by the user, -1 if not suggestion is selected.
375
 *
376
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
377
 * @version $Id: TAutoComplete.php 2564 2008-11-11 21:56:02Z carlgmathisen $
378
 * @package System.Web.UI.ActiveControls
379
 * @since 3.1
380
 */
381
class TAutoCompleteEventParameter extends TCallbackEventParameter
382
{
383
	private $_selectedIndex=-1;
384
 
385
	/**
386
	 * Creates a new TCallbackEventParameter.
387
	 */
388
	public function __construct($response, $parameter, $index=-1)
389
	{
390
		parent::__construct($response, $parameter);
391
		$this->_selectedIndex=$index;
392
	}
393
 
394
	/**
395
	 * @int selected suggestion zero-based index, -1 if not selected.
396
	 */
397
	public function getSelectedIndex()
398
	{
399
		return $this->_selectedIndex;
400
	}
401
 
402
	/**
403
	 * @return string token for matching a list of suggestions.
404
	 */
405
	public function getToken()
406
	{
407
		return $this->getCallbackParameter();
408
	}
409
}
410
 
411
/**
412
 * TAutoCompleteTemplate class.
413
 *
414
 * TAutoCompleteTemplate is the default template for TAutoCompleteTemplate
415
 * item template.
416
 *
417
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
418
 * @version $Id: TAutoComplete.php 2564 2008-11-11 21:56:02Z carlgmathisen $
419
 * @package System.Web.UI.ActiveControls
420
 * @since 3.1
421
 */
422
class TAutoCompleteTemplate extends TComponent implements ITemplate
423
{
424
	private $_template;
425
 
426
	public function __construct($template)
427
	{
428
		$this->_template = $template;
429
	}
430
	/**
431
	 * Instantiates the template.
432
	 * It creates a {@link TDataList} control.
433
	 * @param TControl parent to hold the content within the template
434
	 */
435
	public function instantiateIn($parent)
436
	{
437
		$parent->getControls()->add($this->_template);
438
	}
439
}
440