summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xdemos/quickstart/protected/pages/ActiveControls/Samples/TAutoComplete/Home.page19
-rwxr-xr-xdemos/quickstart/protected/pages/ActiveControls/Samples/TAutoComplete/Home.php3
-rw-r--r--framework/Web/Javascripts/source/prado/activecontrols/autocomplete.js84
-rw-r--r--framework/Web/UI/ActiveControls/TAutoComplete.php442
4 files changed, 536 insertions, 12 deletions
diff --git a/demos/quickstart/protected/pages/ActiveControls/Samples/TAutoComplete/Home.page b/demos/quickstart/protected/pages/ActiveControls/Samples/TAutoComplete/Home.page
index 81d53e13..3790d74b 100755
--- a/demos/quickstart/protected/pages/ActiveControls/Samples/TAutoComplete/Home.page
+++ b/demos/quickstart/protected/pages/ActiveControls/Samples/TAutoComplete/Home.page
@@ -2,7 +2,7 @@
<style type="text/css">
<!--
-.acomplete { position: relative; }
+.acomplete { position: relative; z-index: 5; background-color: #EDF5FF; border: 1px solid #243356; }
.acomplete ul, .acomplete li { margin: 0px; padding: 0px; list-style: none; color: #333; }
.acomplete li { padding: 4px; border-top: 1px solid #ccc; }
.acomplete .selected { background-color: #ffc; }
@@ -16,7 +16,7 @@
<tr><td class="samplenote">
Simple Autocompleter:
</td><td class="sampleaction">
-<com:TJuiAutoComplete
+<com:TAutoComplete
ID="AutoComplete"
OnSuggest="suggestNames"
OnSuggestionSelected="suggestionSelected1"
@@ -24,32 +24,31 @@ Simple Autocompleter:
Suggestions.DataKeyField="id" >
<prop:Suggestions.ItemTemplate>
- <%# $this->Data['name'] %>
+ <li><%# $this->Data['name'] %></li>
</prop:Suggestions.ItemTemplate>
-</com:TJuiAutoComplete>
+</com:TAutoComplete>
<com:TActiveLabel ID="Selection1" />
</td></tr>
<tr><td class="samplenote">
Autocompleter with multiple selection:
</td><td class="sampleaction">
-<com:TJuiAutoComplete
+<com:TAutoComplete
ID="AutoComplete2"
OnSuggest="suggestNames"
OnSuggestionSelected="suggestionSelected2"
+ Separator=","
ResultPanel.CssClass="acomplete"
Suggestions.DataKeyField="id" >
<prop:Suggestions.ItemTemplate>
- <%# $this->Data['name'] %>
+ <li><%# $this->Data['name'] %></li>
</prop:Suggestions.ItemTemplate>
-</com:TJuiAutoComplete>
+</com:TAutoComplete>
(Use ',' to separate the selected suggestions)
<com:TActiveLabel ID="Selection2" />
</td></tr>
</table>
-<com:TJavascriptLogger />
-
-</com:TContent>
+</com:TContent> \ No newline at end of file
diff --git a/demos/quickstart/protected/pages/ActiveControls/Samples/TAutoComplete/Home.php b/demos/quickstart/protected/pages/ActiveControls/Samples/TAutoComplete/Home.php
index f8cd904f..a3b9529b 100755
--- a/demos/quickstart/protected/pages/ActiveControls/Samples/TAutoComplete/Home.php
+++ b/demos/quickstart/protected/pages/ActiveControls/Samples/TAutoComplete/Home.php
@@ -1,5 +1,4 @@
<?php
-Prado::using('System.Web.UI.JuiControls.*');
// $Id: Home.php 3189 2012-07-12 12:16:21Z ctrlaltca $
class Home extends TPage
{
@@ -8,7 +7,7 @@ class Home extends TPage
$token=$param->getToken();
// Sender is the Suggestions repeater
$sender->DataSource=$this->getDummyData($token);
- $sender->dataBind();
+ $sender->dataBind();
}
public function suggestionSelected1($sender,$param) {
diff --git a/framework/Web/Javascripts/source/prado/activecontrols/autocomplete.js b/framework/Web/Javascripts/source/prado/activecontrols/autocomplete.js
new file mode 100644
index 00000000..180ceecf
--- /dev/null
+++ b/framework/Web/Javascripts/source/prado/activecontrols/autocomplete.js
@@ -0,0 +1,84 @@
+jQuery.noConflict();
+
+/**
+ * TAutoComplete control.
+ */
+Prado.WebUI.TAutoComplete = Class.create(Autocompleter.Base, Prado.WebUI.TActiveTextBox.prototype);
+Prado.WebUI.TAutoComplete = Class.create(Prado.WebUI.TAutoComplete,
+{
+ initialize : function(options)
+ {
+ this.options = options;
+ this.observers = new Array();
+ this.hasResults = false;
+ this.baseInitialize(options.ID, options.ResultPanel, options);
+ Object.extend(this.options,
+ {
+ onSuccess : this.onComplete.bind(this)
+ });
+
+ if(options.AutoPostBack)
+ this.onInit(options);
+
+ Prado.Registry[options.ID] = this;
+ },
+
+ doCallback : function(event, options)
+ {
+ if(!this.active)
+ {
+ var request = new Prado.CallbackRequest(this.options.EventTarget, options);
+ request.dispatch();
+ Event.stop(event);
+ }
+ },
+
+ //Overrides parent implementation, fires onchange event.
+ onClick: function(event)
+ {
+ var element = Event.findElement(event, 'LI');
+ this.index = element.autocompleteIndex;
+ this.selectEntry();
+ this.hide();
+ Event.fire(this.element, "change");
+ },
+
+ getUpdatedChoices : function()
+ {
+ var options = new Array(this.getToken(),"__TAutoComplete_onSuggest__");
+ Prado.Callback(this.options.EventTarget, options, null, this.options);
+ },
+
+ /**
+ * Overrides parent implements, don't update if no results.
+ */
+ selectEntry: function()
+ {
+ if(this.hasResults)
+ {
+ this.active = false;
+ this.updateElement(this.getCurrentEntry());
+ var options = [this.index, "__TAutoComplete_onSuggestionSelected__"];
+ Prado.Callback(this.options.EventTarget, options, null, this.options);
+ }
+ },
+
+ onComplete : function(request, boundary)
+ {
+ var result = request.extractContent(boundary);
+ if(typeof(result) == "string")
+ {
+ if(result.length > 0)
+ {
+ this.hasResults = true;
+ this.updateChoices(result);
+ }
+ else
+ {
+ this.active = false;
+ this.hasResults = false;
+ this.hide();
+ }
+ }
+ }
+}); \ No newline at end of file
diff --git a/framework/Web/UI/ActiveControls/TAutoComplete.php b/framework/Web/UI/ActiveControls/TAutoComplete.php
new file mode 100644
index 00000000..58df9235
--- /dev/null
+++ b/framework/Web/UI/ActiveControls/TAutoComplete.php
@@ -0,0 +1,442 @@
+<?php
+/**
+ * TAutoComplete class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2013 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id: TAutoComplete.php 3245 2013-01-07 20:23:32Z ctrlaltca $
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active text box.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveTextBox');
+Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter');
+
+/**
+ * TAutoComplete class.
+ *
+ * TAutoComplete is a textbox that provides a list of suggestion on
+ * the current partial word typed in the textbox. The suggestions are
+ * requested using callbacks, and raises the {@link onSuggestion OnSuggestion}
+ * event. The events of the TActiveText (from which TAutoComplete is extended from)
+ * and {@link onSuggestion OnSuggestion} are mutually exculsive. That is,
+ * if {@link onTextChange OnTextChange} and/or {@link onCallback OnCallback}
+ * events are raise, then {@link onSuggestion OnSuggestion} will not be raise, and
+ * vice versa.
+ *
+ * The list of suggestions should be set in the {@link onSuggestion OnSuggestion}
+ * event handler. The partial word to match the suggestion is in the
+ * {@link TCallbackEventParameter::getCallbackParameter TCallbackEventParameter::CallbackParameter}
+ * property. The datasource of the TAutoComplete must be set using {@link setDataSource}
+ * method. This sets the datasource for the suggestions repeater, available through
+ * the {@link getSuggestions Suggestions} property. Header, footer templates and
+ * other properties of the repeater can be access via the {@link getSuggestions Suggestions}
+ * property and its sub-properties.
+ *
+ * The {@link setTextCssClass TextCssClass} property if set is used to find
+ * the element within the Suggestions.ItemTemplate and Suggestions.AlternatingItemTemplate
+ * that contains the actual text for the suggestion selected. That is,
+ * only text inside elements with CSS class name equal to {@link setTextCssClass TextCssClass}
+ * will be used as suggestions.
+ *
+ * To return the list of suggestions back to the browser, supply a non-empty data source
+ * and call databind. For example,
+ * <code>
+ * function autocomplete_suggestion($sender, $param)
+ * {
+ * $token = $param->getToken(); //the partial word to match
+ * $sender->setDataSource($this->getSuggestionsFor($token)); //set suggestions
+ * $sender->dataBind();
+ * }
+ * </code>
+ *
+ * The suggestion will be rendered when the {@link dataBind()} method is called
+ * <strong>during a callback request</strong>.
+ *
+ * When an suggestion is selected, that is, when the use has clicked, pressed
+ * the "Enter" key, or pressed the "Tab" key, the {@link onSuggestionSelected OnSuggestionSelected}
+ * event is raised. The
+ * {@link TCallbackEventParameter::getCallbackParameter TCallbackEventParameter::CallbackParameter}
+ * property contains the index of the selected suggestion.
+ *
+ * TAutoComplete allows multiple suggestions within one textbox with each
+ * word or phrase separated by any characters specified in the
+ * {@link setSeparator Separator} property. The {@link setFrequency Frequency}
+ * and {@link setMinChars MinChars} properties sets the delay and minimum number
+ * of characters typed, respectively, before requesting for sugggestions.
+ *
+ * Use {@link onTextChange OnTextChange} and/or {@link onCallback OnCallback} events
+ * to handle post backs due to {@link setAutoPostBack AutoPostBack}.
+ *
+ * In the {@link getSuggestions Suggestions} TRepater item template, all HTML text elements
+ * are considered as text for the suggestion. Text within HTML elements with CSS class name
+ * "informal" are ignored as text for suggestions.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id: TAutoComplete.php 3245 2013-01-07 20:23:32Z ctrlaltca $
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TAutoComplete extends TActiveTextBox implements INamingContainer
+{
+ /**
+ * @var ITemplate template for repeater items
+ */
+ private $_repeater=null;
+ /**
+ * @var TPanel result panel holding the suggestion items.
+ */
+ private $_resultPanel=null;
+
+ /**
+ * @return string word or token separators (delimiters).
+ */
+ public function getSeparator()
+ {
+ return $this->getViewState('tokens', '');
+ }
+
+ /**
+ * @return string word or token separators (delimiters).
+ */
+ public function setSeparator($value)
+ {
+ $this->setViewState('tokens', TPropertyValue::ensureString($value), '');
+ }
+
+ /**
+ * @return float maximum delay (in seconds) before requesting a suggestion.
+ */
+ public function getFrequency()
+ {
+ return $this->getViewState('frequency', '');
+ }
+
+ /**
+ * @param float maximum delay (in seconds) before requesting a suggestion.
+ * Default is 0.4.
+ */
+ public function setFrequency($value)
+ {
+ $this->setViewState('frequency', TPropertyValue::ensureFloat($value),'');
+ }
+
+ /**
+ * @return integer minimum number of characters before requesting a suggestion.
+ */
+ public function getMinChars()
+ {
+ return $this->getViewState('minChars','');
+ }
+
+ /**
+ * @param integer minimum number of characters before requesting a suggestion.
+ */
+ public function setMinChars($value)
+ {
+ $this->setViewState('minChars', TPropertyValue::ensureInteger($value), '');
+ }
+
+ /**
+ * @param string Css class name of the element to use for suggestion.
+ */
+ public function setTextCssClass($value)
+ {
+ $this->setViewState('TextCssClass', $value);
+ }
+
+ /**
+ * @return string Css class name of the element to use for suggestion.
+ */
+ public function getTextCssClass()
+ {
+ return $this->getViewState('TextCssClass');
+ }
+
+ /**
+ * Raises the callback event. This method is overrides the parent implementation.
+ * If {@link setAutoPostBack AutoPostBack} is enabled it will raise
+ * {@link onTextChanged OnTextChanged} event event and then the
+ * {@link onCallback OnCallback} event. The {@link onSuggest OnSuggest} event is
+ * raise if the request is to find sugggestions, the {@link onTextChanged OnTextChanged}
+ * and {@link onCallback OnCallback} events are <b>NOT</b> raised.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $token = $param->getCallbackParameter();
+ if(is_array($token) && count($token) == 2)
+ {
+ if($token[1] === '__TAutoComplete_onSuggest__')
+ {
+ $parameter = new TAutoCompleteEventParameter($this->getResponse(), $token[0]);
+ $this->onSuggest($parameter);
+ }
+ else if($token[1] === '__TAutoComplete_onSuggestionSelected__')
+ {
+ $parameter = new TAutoCompleteEventParameter($this->getResponse(), null, $token[0]);
+ $this->onSuggestionSelected($parameter);
+ }
+ }
+ else if($this->getAutoPostBack())
+ parent::raiseCallbackEvent($param);
+ }
+
+ /**
+ * This method is invoked when an autocomplete suggestion is requested.
+ * The method raises 'OnSuggest' event. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onSuggest($param)
+ {
+ $this->raiseEvent('OnSuggest', $this, $param);
+ }
+
+ /**
+ * This method is invoked when an autocomplete suggestion is selected.
+ * The method raises 'OnSuggestionSelected' event. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onSuggestionSelected($param)
+ {
+ $this->raiseEvent('OnSuggestionSelected', $this, $param);
+ }
+
+ /**
+ * @param array data source for suggestions.
+ */
+ public function setDataSource($data)
+ {
+ $this->getSuggestions()->setDataSource($data);
+ }
+
+ /**
+ * Overrides parent implementation. Callback {@link renderSuggestions()} when
+ * page's IsCallback property is true.
+ */
+ public function dataBind()
+ {
+ parent::dataBind();
+ if($this->getPage()->getIsCallback())
+ $this->renderSuggestions($this->getResponse()->createHtmlWriter());
+ }
+
+ /**
+ * @return TPanel suggestion results panel.
+ */
+ public function getResultPanel()
+ {
+ if($this->_resultPanel===null)
+ $this->_resultPanel = $this->createResultPanel();
+ return $this->_resultPanel;
+ }
+
+ /**
+ * @return TPanel new instance of result panel. Default uses TPanel.
+ */
+ protected function createResultPanel()
+ {
+ $panel = Prado::createComponent('System.Web.UI.WebControls.TPanel');
+ $this->getControls()->add($panel);
+ $panel->setID('result');
+ return $panel;
+ }
+
+ /**
+ * @return TRepeater suggestion list repeater
+ */
+ public function getSuggestions()
+ {
+ if($this->_repeater===null)
+ $this->_repeater = $this->createRepeater();
+ return $this->_repeater;
+ }
+
+ /**
+ * @return TRepeater new instance of TRepater to render the list of suggestions.
+ */
+ protected function createRepeater()
+ {
+ $repeater = Prado::createComponent('System.Web.UI.WebControls.TRepeater');
+ $repeater->setHeaderTemplate(new TAutoCompleteTemplate('<ul>'));
+ $repeater->setFooterTemplate(new TAutoCompleteTemplate('</ul>'));
+ $repeater->setItemTemplate(new TTemplate('<li><%# $this->DataItem %></li>',null));
+ $repeater->setEmptyTemplate(new TAutoCompleteTemplate('<ul></ul>'));
+ $this->getControls()->add($repeater);
+ return $repeater;
+ }
+
+ /**
+ * Renders the end tag and registers the needed javascript library.
+ */
+ public function renderEndTag($writer)
+ {
+ $cs=$this->getPage()->getClientScript();
+ $cs->registerPradoScript('autocomplete');
+ parent::renderEndTag($writer);
+ $this->renderResultPanel($writer);
+ }
+
+ /**
+ * Renders the result panel.
+ * @param THtmlWriter the renderer.
+ */
+ protected function renderResultPanel($writer)
+ {
+ $this->getResultPanel()->render($writer);
+ }
+
+ /**
+ * Renders the suggestions during a callback respones.
+ * @param THtmlWriter the renderer.
+ */
+ public function renderCallback($writer)
+ {
+ $this->renderSuggestions($writer);
+ }
+
+ /**
+ * Renders the suggestions repeater.
+ * @param THtmlWriter the renderer.
+ */
+ public function renderSuggestions($writer)
+ {
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ $this->getSuggestions()->render($writer);
+ $boundary = $writer->getWriter()->getBoundary();
+ $this->getResponse()->getAdapter()->setResponseData($boundary);
+ }
+ }
+
+ /**
+ * @return array list of callback options.
+ */
+ protected function getPostBackOptions()
+ {
+ //disallow page state update ?
+ //$this->getActiveControl()->getClientSide()->setEnablePageStateUpdate(false);
+ $options = array();
+ if(strlen($string = $this->getSeparator()))
+ {
+ $string = strtr($string,array('\t'=>"\t",'\n'=>"\n",'\r'=>"\r"));
+ $token = preg_split('//', $string, -1, PREG_SPLIT_NO_EMPTY);
+ $options['tokens'] = $token;
+ }
+ if($this->getAutoPostBack())
+ {
+ $options = array_merge($options,parent::getPostBackOptions());
+ $options['AutoPostBack'] = true;
+ }
+ if(strlen($select = $this->getTextCssClass()))
+ $options['select'] = $select;
+ $options['ResultPanel'] = $this->getResultPanel()->getClientID();
+ $options['ID'] = $this->getClientID();
+ $options['EventTarget'] = $this->getUniqueID();
+ if(($minchars=$this->getMinChars())!=='')
+ $options['minChars'] = $minchars;
+ if(($frequency=$this->getFrequency())!=='')
+ $options['frequency'] = $frequency;
+ $options['CausesValidation'] = $this->getCausesValidation();
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ return $options;
+ }
+
+ /**
+ * Override parent implementation, no javascript is rendered here instead
+ * the javascript required for active control is registered in {@link addAttributesToRender}.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+
+ /**
+ * @return string corresponding javascript class name for this TActiveButton.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TAutoComplete';
+ }
+}
+
+/**
+ * TAutCompleteEventParameter contains the {@link getToken Token} requested by
+ * the user for a partial match of the suggestions.
+ *
+ * The {@link getSelectedIndex SelectedIndex} is a zero-based index of the
+ * suggestion selected by the user, -1 if not suggestion is selected.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id: TAutoComplete.php 3245 2013-01-07 20:23:32Z ctrlaltca $
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TAutoCompleteEventParameter extends TCallbackEventParameter
+{
+ private $_selectedIndex=-1;
+
+ /**
+ * Creates a new TCallbackEventParameter.
+ */
+ public function __construct($response, $parameter, $index=-1)
+ {
+ parent::__construct($response, $parameter);
+ $this->_selectedIndex=$index;
+ }
+
+ /**
+ * @return int selected suggestion zero-based index, -1 if not selected.
+ */
+ public function getSelectedIndex()
+ {
+ return $this->_selectedIndex;
+ }
+
+ /**
+ * @return string token for matching a list of suggestions.
+ */
+ public function getToken()
+ {
+ return $this->getCallbackParameter();
+ }
+}
+
+/**
+ * TAutoCompleteTemplate class.
+ *
+ * TAutoCompleteTemplate is the default template for TAutoCompleteTemplate
+ * item template.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id: TAutoComplete.php 3245 2013-01-07 20:23:32Z ctrlaltca $
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TAutoCompleteTemplate extends TComponent implements ITemplate
+{
+ private $_template;
+
+ public function __construct($template)
+ {
+ $this->_template = $template;
+ }
+ /**
+ * Instantiates the template.
+ * It creates a {@link TDataList} control.
+ * @param TControl parent to hold the content within the template
+ */
+ public function instantiateIn($parent)
+ {
+ $parent->getControls()->add($this->_template);
+ }
+}
+