1: <?php
2: /**
3: * Triggered when the field is blurred, if the value has changed.
4: *
5: * * event Type: Event
6: *
7: * * ui Type: Object
8: *
9: * * item Type: Object The item selected from the menu, if any.
10: * Otherwise the property is null.
11: *
12: */
13: class QAutocomplete_ChangeEvent extends QJqUiEvent {
14: const EventName = 'autocompletechange';
15: }
16: /**
17: * Triggered when the menu is hidden. Not every close event will be
18: * accompanied by a change event.
19: *
20: * * event Type: Event
21: * * ui Type: Object
22: *
23: * _Note: The ui object is empty but included for consistency with other
24: * events._ */
25: class QAutocomplete_CloseEvent extends QJqUiEvent {
26: const EventName = 'autocompleteclose';
27: }
28: /**
29: * Triggered when the autocomplete is created.
30: *
31: * * event Type: Event
32: * * ui Type: Object
33: *
34: * _Note: The ui object is empty but included for consistency with other
35: * events._ */
36: class QAutocomplete_CreateEvent extends QJqUiEvent {
37: const EventName = 'autocompletecreate';
38: }
39: /**
40: * Triggered when focus is moved to an item (not selecting). The default
41: * action is to replace the text fields value with the value of the
42: * focused item, though only if the event was triggered by a keyboard
43: * interaction.
44: *
45: * Canceling this event prevents the value from being updated, but does
46: * not prevent the menu item from being focused.
47: *
48: * * event Type: Event
49: *
50: * * ui Type: Object
51: *
52: * * item Type: Object The focused item.
53: *
54: */
55: class QAutocomplete_FocusEvent extends QJqUiEvent {
56: const EventName = 'autocompletefocus';
57: }
58: /**
59: * Triggered when the suggestion menu is opened or updated.
60: *
61: * * event Type: Event
62: * * ui Type: Object
63: *
64: * _Note: The ui object is empty but included for consistency with other
65: * events._ */
66: class QAutocomplete_OpenEvent extends QJqUiEvent {
67: const EventName = 'autocompleteopen';
68: }
69: /**
70: * Triggered after a search completes, before the menu is shown. Useful
71: * for local manipulation of suggestion data, where a custom source
72: * option callback is not required. This event is always triggered when a
73: * search completes, even if the menu will not be shown because there are
74: * no results or the Autocomplete is disabled.
75: *
76: * * event Type: Event
77: *
78: * * ui Type: Object
79: *
80: * * content Type: Array Contains the response data and can be modified
81: * to change the results that will be shown. This data is already
82: * normalized, so if you modify the data, make sure to include both value
83: * and label properties for each item.
84: *
85: */
86: class QAutocomplete_ResponseEvent extends QJqUiEvent {
87: const EventName = 'autocompleteresponse';
88: }
89: /**
90: * Triggered before a search is performed, after minLength and delay are
91: * met. If canceled, then no request will be started and no items
92: * suggested.
93: *
94: * * event Type: Event
95: * * ui Type: Object
96: *
97: * _Note: The ui object is empty but included for consistency with other
98: * events._ */
99: class QAutocomplete_SearchEvent extends QJqUiEvent {
100: const EventName = 'autocompletesearch';
101: }
102: /**
103: * Triggered when an item is selected from the menu. The default action
104: * is to replace the text fields value with the value of the selected
105: * item.
106: *
107: * Canceling this event prevents the value from being updated, but does
108: * not prevent the menu from closing.
109: *
110: * * event Type: Event
111: *
112: * * ui Type: Object
113: *
114: * * item Type: Object An Object with label and value properties for the
115: * selected option.
116: *
117: */
118: class QAutocomplete_SelectEvent extends QJqUiEvent {
119: const EventName = 'autocompleteselect';
120: }
121:
122: /* Custom "property" event classes for this control */
123:
124: /**
125: * Generated QAutocompleteGen class.
126: *
127: * This is the QAutocompleteGen class which is automatically generated
128: * by scraping the JQuery UI documentation website. As such, it includes all the options
129: * as listed by the JQuery UI website, which may or may not be appropriate for QCubed. See
130: * the QAutocompleteBase class for any glue code to make this class more
131: * usable in QCubed.
132: *
133: * @see QAutocompleteBase
134: * @package Controls\Base
135: * @property mixed $AppendTo
136: * Which element the menu should be appended to. When the value is null,
137: * the parents of the input field will be checked for a class of
138: * ui-front. If an element with the ui-front class is found, the menu
139: * will be appended to that element. Regardless of the value, if no
140: * element is found, the menu will be appended to the body. Note: The
141: * appendTo option should not be changed while the suggestions menu is
142: * open.
143: *
144: * @property boolean $AutoFocus
145: * If set to true the first item will automatically be focused when the
146: * menu is shown.
147: *
148: * @property integer $Delay
149: * The delay in milliseconds between when a keystroke occurs and when a
150: * search is performed. A zero-delay makes sense for local data (more
151: * responsive), but can produce a lot of load for remote data, while
152: * being less responsive.
153: *
154: * @property boolean $Disabled
155: * Disables the autocomplete if set to true.
156: *
157: * @property integer $MinLength
158: * The minimum number of characters a user must type before a search is
159: * performed. Zero is useful for local data with just a few items, but a
160: * higher value should be used when a single character search could match
161: * a few thousand items.
162: *
163: * @property mixed $Position
164: * Identifies the position of the suggestions menu in relation to the
165: * associated input element. The of option defaults to the input element,
166: * but you can specify another element to position against. You can refer
167: * to the jQuery UI Position utility for more details about the various
168: * options.
169: *
170: * @property mixed $Source
171: * Defines the data to use, must be specified.
172: *
173: * Independent of the variant you use, the label is always treated as
174: * text. If you want the label to be treated as html you can use Scott
175: * González html extension. The demos all focus on different variations
176: * of the source option - look for one that matches your use case, and
177: * check out the code.Multiple types supported:
178: *
179: * * Array: An array can be used for local data. There are two supported
180: * formats:
181: *
182: * * An array of strings: [ "Choice1", "Choice2" ]
183: * * An array of objects with label and value properties: [ { label:
184: * "Choice1", value: "value1" }, ... ]
185: *
186: * The label property is displayed in the suggestion menu. The value
187: * will be inserted into the input element when a user selects an item.
188: * If just one property is specified, it will be used for both, e.g., if
189: * you provide only value properties, the value will also be used as the
190: * label. * String: When a string is used, the Autocomplete plugin
191: * expects that string to point to a URL resource that will return JSON
192: * data. It can be on the same host or on a different one (must provide
193: * JSONP). The Autocomplete plugin does not filter the results, instead a
194: * query string is added with a term field, which the server-side script
195: * should use for filtering the results. For example, if the source
196: * option is set to "http://example.com" and the user types foo, a GET
197: * request would be made to http://example.com?term=foo. The data itself
198: * can be in the same format as the local data described above.
199: *
200: * * Function: The third variation, a callback, provides the most
201: * flexibility and can be used to connect any data source to
202: * Autocomplete. The callback gets two arguments:
203: *
204: * * A request object, with a single term property, which refers to the
205: * value currently in the text input. For example, if the user enters
206: * "new yo" in a city field, the Autocomplete term will equal "new yo".
207: * * A response callback, which expects a single argument: the data to
208: * suggest to the user. This data should be filtered based on the
209: * provided term, and can be in any of the formats described above for
210: * simple local data. Its important when providing a custom source
211: * callback to handle errors during the request. You must always call the
212: * response callback even if you encounter an error. This ensures that
213: * the widget always has the correct state.
214: *
215: * When filtering data locally, you can make use of the built-in
216: * $.ui.autocomplete.escapeRegex function. Itll take a single string
217: * argument and escape all regex characters, making the result safe to
218: * pass to new RegExp().
219: *
220:
221: *
222: */
223:
224: class QAutocompleteGen extends QTextBox {
225: protected $strJavaScripts = __JQUERY_EFFECTS__;
226: protected $strStyleSheets = __JQUERY_CSS__;
227: /** @var mixed */
228: protected $mixAppendTo = null;
229: /** @var boolean */
230: protected $blnAutoFocus = null;
231: /** @var integer */
232: protected $intDelay = null;
233: /** @var boolean */
234: protected $blnDisabled = null;
235: /** @var integer */
236: protected $intMinLength = null;
237: /** @var mixed */
238: protected $mixPosition = null;
239: /** @var mixed */
240: protected $mixSource;
241:
242: /**
243: * Builds the option array to be sent to the widget constructor.
244: *
245: * @return array key=>value array of options
246: */
247: protected function MakeJqOptions() {
248: $jqOptions = null;
249: if (!is_null($val = $this->AppendTo)) {$jqOptions['appendTo'] = $val;}
250: if (!is_null($val = $this->AutoFocus)) {$jqOptions['autoFocus'] = $val;}
251: if (!is_null($val = $this->Delay)) {$jqOptions['delay'] = $val;}
252: if (!is_null($val = $this->Disabled)) {$jqOptions['disabled'] = $val;}
253: if (!is_null($val = $this->MinLength)) {$jqOptions['minLength'] = $val;}
254: if (!is_null($val = $this->Position)) {$jqOptions['position'] = $val;}
255: if (!is_null($val = $this->Source)) {$jqOptions['source'] = $val;}
256: return $jqOptions;
257: }
258:
259: /**
260: * Return the JavaScript function to call to associate the widget with the control.
261: *
262: * @return string
263: */
264: public function GetJqSetupFunction() {
265: return 'autocomplete';
266: }
267:
268: /**
269: * Returns the script that attaches the JQueryUI widget to the html object.
270: *
271: * @return string
272: */
273: public function GetEndScript() {
274: $strId = $this->GetJqControlId();
275: $jqOptions = $this->makeJqOptions();
276: $strFunc = $this->getJqSetupFunction();
277:
278: if ($strId !== $this->ControlId && QApplication::$RequestMode == QRequestMode::Ajax) {
279: // If events are not attached to the actual object being drawn, then the old events will not get
280: // deleted during redraw. We delete the old events here. This must happen before any other event processing code.
281: QApplication::ExecuteControlCommand($strId, 'off', QJsPriority::High);
282: }
283:
284: // Attach the javascript widget to the html object
285: if (empty($jqOptions)) {
286: QApplication::ExecuteControlCommand($strId, $strFunc, QJsPriority::High);
287: } else {
288: QApplication::ExecuteControlCommand($strId, $strFunc, $jqOptions, QJsPriority::High);
289: }
290:
291: return parent::GetEndScript();
292: }
293:
294: /**
295: * Closes the Autocomplete menu. Useful in combination with the search
296: * method, to close the open menu.
297: *
298: * * This method does not accept any arguments.
299: */
300: public function Close() {
301: QApplication::ExecuteControlCommand($this->getJqControlId(), $this->getJqSetupFunction(), "close", QJsPriority::Low);
302: }
303: /**
304: * Removes the autocomplete functionality completely. This will return
305: * the element back to its pre-init state.
306: *
307: * * This method does not accept any arguments.
308: */
309: public function Destroy() {
310: QApplication::ExecuteControlCommand($this->getJqControlId(), $this->getJqSetupFunction(), "destroy", QJsPriority::Low);
311: }
312: /**
313: * Disables the autocomplete.
314: *
315: * * This method does not accept any arguments.
316: */
317: public function Disable() {
318: QApplication::ExecuteControlCommand($this->getJqControlId(), $this->getJqSetupFunction(), "disable", QJsPriority::Low);
319: }
320: /**
321: * Enables the autocomplete.
322: *
323: * * This method does not accept any arguments.
324: */
325: public function Enable() {
326: QApplication::ExecuteControlCommand($this->getJqControlId(), $this->getJqSetupFunction(), "enable", QJsPriority::Low);
327: }
328: /**
329: * Retrieves the autocompletes instance object. If the element does not
330: * have an associated instance, undefined is returned.
331: *
332: * Unlike other widget methods, instance() is safe to call on any element
333: * after the autocomplete plugin has loaded.
334: *
335: * * This method does not accept any arguments.
336: */
337: public function Instance() {
338: QApplication::ExecuteControlCommand($this->getJqControlId(), $this->getJqSetupFunction(), "instance", QJsPriority::Low);
339: }
340: /**
341: * Gets the value currently associated with the specified optionName.
342: *
343: * Note: For options that have objects as their value, you can get the
344: * value of a specific key by using dot notation. For example, "foo.bar"
345: * would get the value of the bar property on the foo option.
346: *
347: * * optionName Type: String The name of the option to get.
348: * @param $optionName
349: */
350: public function Option($optionName) {
351: QApplication::ExecuteControlCommand($this->getJqControlId(), $this->getJqSetupFunction(), "option", $optionName, QJsPriority::Low);
352: }
353: /**
354: * Gets an object containing key/value pairs representing the current
355: * autocomplete options hash.
356: *
357: * * This signature does not accept any arguments.
358: */
359: public function Option1() {
360: QApplication::ExecuteControlCommand($this->getJqControlId(), $this->getJqSetupFunction(), "option", QJsPriority::Low);
361: }
362: /**
363: * Sets the value of the autocomplete option associated with the
364: * specified optionName.
365: *
366: * Note: For options that have objects as their value, you can set the
367: * value of just one property by using dot notation for optionName. For
368: * example, "foo.bar" would update only the bar property of the foo
369: * option.
370: *
371: * * optionName Type: String The name of the option to set.
372: * * value Type: Object A value to set for the option.
373: * @param $optionName
374: * @param $value
375: */
376: public function Option2($optionName, $value) {
377: QApplication::ExecuteControlCommand($this->getJqControlId(), $this->getJqSetupFunction(), "option", $optionName, $value, QJsPriority::Low);
378: }
379: /**
380: * Sets one or more options for the autocomplete.
381: *
382: * * options Type: Object A map of option-value pairs to set.
383: * @param $options
384: */
385: public function Option3($options) {
386: QApplication::ExecuteControlCommand($this->getJqControlId(), $this->getJqSetupFunction(), "option", $options, QJsPriority::Low);
387: }
388: /**
389: * Triggers a search event and invokes the data source if the event is
390: * not canceled. Can be used by a selectbox-like button to open the
391: * suggestions when clicked. When invoked with no parameters, the current
392: * inputs value is used. Can be called with an empty string and
393: * minLength: 0 to display all items.
394: *
395: * * value Type: String
396: * @param $value
397: */
398: public function Search($value = null) {
399: QApplication::ExecuteControlCommand($this->getJqControlId(), $this->getJqSetupFunction(), "search", $value, QJsPriority::Low);
400: }
401:
402:
403: public function __get($strName) {
404: switch ($strName) {
405: case 'AppendTo': return $this->mixAppendTo;
406: case 'AutoFocus': return $this->blnAutoFocus;
407: case 'Delay': return $this->intDelay;
408: case 'Disabled': return $this->blnDisabled;
409: case 'MinLength': return $this->intMinLength;
410: case 'Position': return $this->mixPosition;
411: case 'Source': return $this->mixSource;
412: default:
413: try {
414: return parent::__get($strName);
415: } catch (QCallerException $objExc) {
416: $objExc->IncrementOffset();
417: throw $objExc;
418: }
419: }
420: }
421:
422: public function __set($strName, $mixValue) {
423: switch ($strName) {
424: case 'AppendTo':
425: $this->mixAppendTo = $mixValue;
426: $this->AddAttributeScript($this->getJqSetupFunction(), 'option', 'appendTo', $mixValue);
427: break;
428:
429: case 'AutoFocus':
430: try {
431: $this->blnAutoFocus = QType::Cast($mixValue, QType::Boolean);
432: $this->AddAttributeScript($this->getJqSetupFunction(), 'option', 'autoFocus', $this->blnAutoFocus);
433: break;
434: } catch (QInvalidCastException $objExc) {
435: $objExc->IncrementOffset();
436: throw $objExc;
437: }
438:
439: case 'Delay':
440: try {
441: $this->intDelay = QType::Cast($mixValue, QType::Integer);
442: $this->AddAttributeScript($this->getJqSetupFunction(), 'option', 'delay', $this->intDelay);
443: break;
444: } catch (QInvalidCastException $objExc) {
445: $objExc->IncrementOffset();
446: throw $objExc;
447: }
448:
449: case 'Disabled':
450: try {
451: $this->blnDisabled = QType::Cast($mixValue, QType::Boolean);
452: $this->AddAttributeScript($this->getJqSetupFunction(), 'option', 'disabled', $this->blnDisabled);
453: break;
454: } catch (QInvalidCastException $objExc) {
455: $objExc->IncrementOffset();
456: throw $objExc;
457: }
458:
459: case 'MinLength':
460: try {
461: $this->intMinLength = QType::Cast($mixValue, QType::Integer);
462: $this->AddAttributeScript($this->getJqSetupFunction(), 'option', 'minLength', $this->intMinLength);
463: break;
464: } catch (QInvalidCastException $objExc) {
465: $objExc->IncrementOffset();
466: throw $objExc;
467: }
468:
469: case 'Position':
470: $this->mixPosition = $mixValue;
471: $this->AddAttributeScript($this->getJqSetupFunction(), 'option', 'position', $mixValue);
472: break;
473:
474: case 'Source':
475: $this->mixSource = $mixValue;
476: $this->AddAttributeScript($this->getJqSetupFunction(), 'option', 'source', $mixValue);
477: break;
478:
479:
480: case 'Enabled':
481: $this->Disabled = !$mixValue; // Tie in standard QCubed functionality
482: parent::__set($strName, $mixValue);
483: break;
484:
485: default:
486: try {
487: parent::__set($strName, $mixValue);
488: break;
489: } catch (QCallerException $objExc) {
490: $objExc->IncrementOffset();
491: throw $objExc;
492: }
493: }
494: }
495:
496: /**
497: * If this control is attachable to a codegenerated control in a ModelConnector, this function will be
498: * used by the ModelConnector designer dialog to display a list of options for the control.
499: * @return QModelConnectorParam[]
500: **/
501: public static function GetModelConnectorParams() {
502: return array_merge(parent::GetModelConnectorParams(), array(
503: new QModelConnectorParam (get_called_class(), 'AutoFocus', 'If set to true the first item will automatically be focused when themenu is shown.', QType::Boolean),
504: new QModelConnectorParam (get_called_class(), 'Delay', 'The delay in milliseconds between when a keystroke occurs and when asearch is performed. A zero-delay makes sense for local data (moreresponsive), but can produce a lot of load for remote data, whilebeing less responsive.', QType::Integer),
505: new QModelConnectorParam (get_called_class(), 'Disabled', 'Disables the autocomplete if set to true.', QType::Boolean),
506: new QModelConnectorParam (get_called_class(), 'MinLength', 'The minimum number of characters a user must type before a search isperformed. Zero is useful for local data with just a few items, but ahigher value should be used when a single character search could matcha few thousand items.', QType::Integer),
507: ));
508: }
509: }