From 2d32c6aa8f682771839531537334250cf4a731bc Mon Sep 17 00:00:00 2001 From: wei <> Date: Sat, 31 Mar 2007 11:35:00 +0000 Subject: add inplacetext onkeypress suggestions --- framework/Web/Javascripts/js/compressed/ajax.js | 19 ++-- framework/Web/Javascripts/js/debug/ajax.js | 30 +++++- .../prado/activecontrols/activecontrols3.js | 2 + .../prado/activecontrols/inlineeditor.js | 28 +++++- .../Web/UI/ActiveControls/TActivePageAdapter.php | 78 +-------------- framework/Web/UI/ActiveControls/TAutoComplete.php | 105 +++++++++++++++++++-- .../UI/ActiveControls/TCallbackEventParameter.php | 88 +++++++++++++++++ .../Web/UI/ActiveControls/TInPlaceTextBox.php | 13 +++ 8 files changed, 264 insertions(+), 99 deletions(-) create mode 100644 framework/Web/UI/ActiveControls/TCallbackEventParameter.php (limited to 'framework') diff --git a/framework/Web/Javascripts/js/compressed/ajax.js b/framework/Web/Javascripts/js/compressed/ajax.js index b6387293..d8536c50 100644 --- a/framework/Web/Javascripts/js/compressed/ajax.js +++ b/framework/Web/Javascripts/js/compressed/ajax.js @@ -231,7 +231,7 @@ this.onInit(options);},doCallback:function(event,options) {var element=Event.findElement(event,'LI');this.index=element.autocompleteIndex;this.selectEntry();this.hide();Event.fireEvent(this.element,"change");},getUpdatedChoices:function() {var options=new Array(this.getToken(),"__TAutoComplete_onSuggest__");Prado.Callback(this.options.EventTarget,options,null,this.options);},selectEntry:function() {if(this.hasResults) -{this.active=false;this.updateElement(this.getCurrentEntry());}},onComplete:function(request,boundary) +{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=Prado.Element.extractContent(request.transport.responseText,boundary);if(typeof(result)=="string") {if(result.length>0) {this.hasResults=true;this.updateChoices(result);} @@ -268,8 +268,8 @@ this.count=this.count+this.options.Decay;if(this.observing) this.time=setTimeout(this.checkChanges.bind(this),parseInt(this.options.Interval*1000*this.count));}},doCallback:function(oldValue,newValue) {var request=new Prado.CallbackRequest(this.options.EventTarget,this.options);var param={'OldValue':oldValue,'NewValue':newValue};request.setCallbackParameter(param);request.dispatch();}},{timers:{},register:function(timer) {Prado.WebUI.TValueTriggeredCallback.timers[timer.options.ID]=timer;},stop:function(id) -{Prado.WebUI.TValueTriggeredCallback.timers[id].stopObserving();}});Prado.WebUI.TInPlaceTextBox=Base.extend({isSaving:false,isEditing:false,editField:null,constructor:function(options) -{this.options=Object.extend({LoadTextFromSource:false,TextMode:'SingleLine'},options||{});this.element=$(this.options.ID);Prado.WebUI.TInPlaceTextBox.register(this);this.createEditorInput();this.initializeListeners();},initializeListeners:function() +{Prado.WebUI.TValueTriggeredCallback.timers[id].stopObserving();}});Prado.WebUI.TInPlaceTextBox=Base.extend({constructor:function(options) +{this.isSaving=false;this.isEditing=false;this.editField=null;this.options=Object.extend({LoadTextFromSource:false,TextMode:'SingleLine'},options||{});this.element=$(this.options.ID);Prado.WebUI.TInPlaceTextBox.register(this);this.createEditorInput();this.initializeListeners();},initializeListeners:function() {this.onclickListener=this.enterEditMode.bindAsEventListener(this);Event.observe(this.element,'click',this.onclickListener);if(this.options.ExternalControl) Event.observe($(this.options.ExternalControl),'click',this.onclickListener);},enterEditMode:function(evt) {if(this.isSaving||this.isEditing)return;this.isEditing=true;this.onEnterEditMode();this.createEditorInput();this.showTextBox();this.editField.disabled=false;if(this.options.LoadTextOnEdit) @@ -295,14 +295,21 @@ if(this.options.TextMode=='SingleLine') {if(Event.keyCode(e)==Event.KEY_RETURN) {var target=Event.element(e);if(target) {Event.fireEvent(target,"blur");Event.stop(e);}}});} -Event.observe(this.editField,"blur",this.onTextBoxBlur.bind(this));},getText:function() +Event.observe(this.editField,"blur",this.onTextBoxBlur.bind(this));Event.observe(this.editField,"keypress",this.onKeyPressed.bind(this));},getText:function() {return this.element.innerHTML;},onEnterEditMode:function() {if(typeof(this.options.onEnterEditMode)=="function") this.options.onEnterEditMode(this,null);},onTextBoxBlur:function(e) {text=this.element.innerHTML;if(this.options.AutoPostBack&&text!=this.editField.value) -this.onTextChanged(text);else +{if(this.isEditing) +this.onTextChanged(text);} +else {this.element.innerHTML=this.editField.value;this.isEditing=false;if(this.options.AutoHide) -this.showLabel();}},onTextChanged:function(text) +this.showLabel();}},onKeyPressed:function(e) +{if(Event.keyCode(e)==Event.KEY_ESC) +{this.editField.value=this.getText();this.isEditing=false;if(this.options.AutoHide) +this.showLabel();} +else if(Event.keyCode(e)==Event.KEY_RETURN) +Event.stop(e);},onTextChanged:function(text) {request=new Prado.CallbackRequest(this.options.EventTarget,this.options);request.setCallbackParameter(text);request.ActiveControl.onSuccess=this.onTextChangedSuccess.bind(this);request.ActiveControl.onFailure=this.onTextChangedFailure.bind(this);if(request.dispatch()) {this.isSaving=true;this.editField.disabled=true;}},onLoadingText:function() {},onloadExternalTextSuccess:function(request,parameter) diff --git a/framework/Web/Javascripts/js/debug/ajax.js b/framework/Web/Javascripts/js/debug/ajax.js index 936f50e4..5b36b2d1 100644 --- a/framework/Web/Javascripts/js/debug/ajax.js +++ b/framework/Web/Javascripts/js/debug/ajax.js @@ -2024,6 +2024,8 @@ Prado.WebUI.TAutoComplete = Class.extend(Prado.WebUI.TAutoComplete, { this.active = false; this.updateElement(this.getCurrentEntry()); + var options = [this.index, "__TAutoComplete_onSuggestionSelected__"]; + Prado.Callback(this.options.EventTarget, options, null, this.options); } }, @@ -2239,12 +2241,13 @@ Prado.WebUI.TValueTriggeredCallback = Base.extend( Prado.WebUI.TInPlaceTextBox = Base.extend( { - isSaving : false, - isEditing : false, - editField : null, - constructor : function(options) { + + this.isSaving = false; + this.isEditing = false; + this.editField = null; + this.options = Object.extend( { LoadTextFromSource : false, @@ -2379,6 +2382,7 @@ Prado.WebUI.TInPlaceTextBox = Base.extend( } Event.observe(this.editField, "blur", this.onTextBoxBlur.bind(this)); + Event.observe(this.editField, "keypress", this.onKeyPressed.bind(this)); }, /** @@ -2402,7 +2406,10 @@ Prado.WebUI.TInPlaceTextBox = Base.extend( { text = this.element.innerHTML; if(this.options.AutoPostBack && text != this.editField.value) - this.onTextChanged(text); + { + if(this.isEditing) + this.onTextChanged(text); + } else { this.element.innerHTML = this.editField.value; @@ -2412,6 +2419,19 @@ Prado.WebUI.TInPlaceTextBox = Base.extend( } }, + onKeyPressed : function(e) + { + if (Event.keyCode(e) == Event.KEY_ESC) + { + this.editField.value = this.getText(); + this.isEditing = false; + if(this.options.AutoHide) + this.showLabel(); + } + else if (Event.keyCode(e) == Event.KEY_RETURN) + Event.stop(e); + }, + /** * When the text input value has changed. * @param {String} original text diff --git a/framework/Web/Javascripts/prado/activecontrols/activecontrols3.js b/framework/Web/Javascripts/prado/activecontrols/activecontrols3.js index 675aabf2..444f3ab2 100644 --- a/framework/Web/Javascripts/prado/activecontrols/activecontrols3.js +++ b/framework/Web/Javascripts/prado/activecontrols/activecontrols3.js @@ -144,6 +144,8 @@ Prado.WebUI.TAutoComplete = Class.extend(Prado.WebUI.TAutoComplete, { this.active = false; this.updateElement(this.getCurrentEntry()); + var options = [this.index, "__TAutoComplete_onSuggestionSelected__"]; + Prado.Callback(this.options.EventTarget, options, null, this.options); } }, diff --git a/framework/Web/Javascripts/prado/activecontrols/inlineeditor.js b/framework/Web/Javascripts/prado/activecontrols/inlineeditor.js index fdf0e9f5..f8b8b412 100644 --- a/framework/Web/Javascripts/prado/activecontrols/inlineeditor.js +++ b/framework/Web/Javascripts/prado/activecontrols/inlineeditor.js @@ -1,11 +1,12 @@ Prado.WebUI.TInPlaceTextBox = Base.extend( { - isSaving : false, - isEditing : false, - editField : null, - constructor : function(options) { + + this.isSaving = false; + this.isEditing = false; + this.editField = null; + this.options = Object.extend( { LoadTextFromSource : false, @@ -140,6 +141,7 @@ Prado.WebUI.TInPlaceTextBox = Base.extend( } Event.observe(this.editField, "blur", this.onTextBoxBlur.bind(this)); + Event.observe(this.editField, "keypress", this.onKeyPressed.bind(this)); }, /** @@ -163,7 +165,10 @@ Prado.WebUI.TInPlaceTextBox = Base.extend( { text = this.element.innerHTML; if(this.options.AutoPostBack && text != this.editField.value) - this.onTextChanged(text); + { + if(this.isEditing) + this.onTextChanged(text); + } else { this.element.innerHTML = this.editField.value; @@ -173,6 +178,19 @@ Prado.WebUI.TInPlaceTextBox = Base.extend( } }, + onKeyPressed : function(e) + { + if (Event.keyCode(e) == Event.KEY_ESC) + { + this.editField.value = this.getText(); + this.isEditing = false; + if(this.options.AutoHide) + this.showLabel(); + } + else if (Event.keyCode(e) == Event.KEY_RETURN) + Event.stop(e); + }, + /** * When the text input value has changed. * @param {String} original text diff --git a/framework/Web/UI/ActiveControls/TActivePageAdapter.php b/framework/Web/UI/ActiveControls/TActivePageAdapter.php index af3cdd4d..da53856a 100644 --- a/framework/Web/UI/ActiveControls/TActivePageAdapter.php +++ b/framework/Web/UI/ActiveControls/TActivePageAdapter.php @@ -1,7 +1,6 @@ * @link http://www.pradosoft.com/ @@ -290,81 +289,6 @@ class TActivePageAdapter extends TControlAdapter } } -/** - * TCallbackEventParameter class. - * - * The TCallbackEventParameter provides the parameter passed during the callback - * requestion in the {@link getCallbackParameter CallbackParameter} property. The - * callback response content (e.g. new HTML content) must be rendered - * using an THtmlWriter obtained from the {@link getNewWriter NewWriter} - * property, which returns a NEW instance of TCallbackResponseWriter. - * - * Each instance TCallbackResponseWriter is associated with a unique - * boundary delimited. By default each panel only renders its own content. - * To replace the content of ONE panel with that of rendered from multiple panels - * use the same writer instance for the panels to be rendered. - * - * The response data (i.e., passing results back to the client-side - * callback handler function) can be set using {@link setResponseData ResponseData} property. - * - * @author Wei Zhuo - * @version $Id$ - * @package System.Web.UI.ActiveControls - * @since 3.1 - */ -class TCallbackEventParameter extends TEventParameter -{ - /** - * @var THttpResponse output content. - */ - private $_response; - /** - * @var mixed callback request parameter. - */ - private $_parameter; - - /** - * Creates a new TCallbackEventParameter. - */ - public function __construct($response, $parameter) - { - $this->_response = $response; - $this->_parameter = $parameter; - } - - /** - * @return TCallbackResponseWriter holds the response content. - */ - public function getNewWriter() - { - return $this->_response->createHtmlWriter(null); - } - - /** - * @return mixed callback request parameter. - */ - public function getCallbackParameter() - { - return $this->_parameter; - } - - /** - * @param mixed callback response data. - */ - public function setResponseData($value) - { - $this->_response->getAdapter()->setResponseData($value); - } - - /** - * @return mixed callback response data. - */ - public function getResponseData() - { - return $this->_response->getAdapter()->getResponseData(); - } -} - /** * TCallbackErrorHandler class. * diff --git a/framework/Web/UI/ActiveControls/TAutoComplete.php b/framework/Web/UI/ActiveControls/TAutoComplete.php index f94a826f..f7167feb 100644 --- a/framework/Web/UI/ActiveControls/TAutoComplete.php +++ b/framework/Web/UI/ActiveControls/TAutoComplete.php @@ -14,6 +14,7 @@ * Load active text box. */ Prado::using('System.Web.UI.ActiveControls.TActiveTextBox'); +Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter'); /** * TAutoComplete class. @@ -34,14 +35,20 @@ Prado::using('System.Web.UI.ActiveControls.TActiveTextBox'); * 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 (e.g. they can be set in the .page templates). + * 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, * * function autocomplete_suggestion($sender, $param) * { - * $token = $param->getCallbackParameter(); //the partial word to match + * $token = $param->getToken(); //the partial word to match * $sender->setDataSource($this->getSuggestionsFor($token)); //set suggestions * $sender->dataBind(); * } @@ -50,6 +57,12 @@ Prado::using('System.Web.UI.ActiveControls.TActiveTextBox'); * The suggestion will be rendered when the {@link dataBind()} method is called * during a callback request. * + * 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} @@ -128,6 +141,22 @@ class TAutoComplete extends TActiveTextBox implements INamingContainer $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 @@ -141,17 +170,25 @@ class TAutoComplete extends TActiveTextBox implements INamingContainer public function raiseCallbackEvent($param) { $token = $param->getCallbackParameter(); - if(is_array($token) && count($token) == 2 && $token[1] === '__TAutoComplete_onSuggest__') + if(is_array($token) && count($token) == 2) { - $parameter = new TCallbackEventParameter($this->getResponse(), $token[0]); - $this->onSuggest($parameter); + 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 a autocomplete suggestion is requested. + * 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. @@ -162,6 +199,18 @@ class TAutoComplete extends TActiveTextBox implements INamingContainer $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. */ @@ -285,6 +334,8 @@ class TAutoComplete extends TActiveTextBox implements INamingContainer $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(); @@ -308,6 +359,48 @@ class TAutoComplete extends TActiveTextBox implements INamingContainer } } +/** + * 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 + * @version $Id$ + * @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; + } + + /** + * @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. * diff --git a/framework/Web/UI/ActiveControls/TCallbackEventParameter.php b/framework/Web/UI/ActiveControls/TCallbackEventParameter.php new file mode 100644 index 00000000..ffc83d28 --- /dev/null +++ b/framework/Web/UI/ActiveControls/TCallbackEventParameter.php @@ -0,0 +1,88 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2007 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.ActiveControls + */ + +/** + * TCallbackEventParameter class. + * + * The TCallbackEventParameter provides the parameter passed during the callback + * requestion in the {@link getCallbackParameter CallbackParameter} property. The + * callback response content (e.g. new HTML content) must be rendered + * using an THtmlWriter obtained from the {@link getNewWriter NewWriter} + * property, which returns a NEW instance of TCallbackResponseWriter. + * + * Each instance TCallbackResponseWriter is associated with a unique + * boundary delimited. By default each panel only renders its own content. + * To replace the content of ONE panel with that of rendered from multiple panels + * use the same writer instance for the panels to be rendered. + * + * The response data (i.e., passing results back to the client-side + * callback handler function) can be set using {@link setResponseData ResponseData} property. + * + * @author Wei Zhuo + * @version $Id: TActivePageAdapter.php 1648 2007-01-24 05:52:22Z wei $ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TCallbackEventParameter extends TEventParameter +{ + /** + * @var THttpResponse output content. + */ + private $_response; + /** + * @var mixed callback request parameter. + */ + private $_parameter; + + /** + * Creates a new TCallbackEventParameter. + */ + public function __construct($response, $parameter) + { + $this->_response = $response; + $this->_parameter = $parameter; + } + + /** + * @return TCallbackResponseWriter holds the response content. + */ + public function getNewWriter() + { + return $this->_response->createHtmlWriter(null); + } + + /** + * @return mixed callback request parameter. + */ + public function getCallbackParameter() + { + return $this->_parameter; + } + + /** + * @param mixed callback response data. + */ + public function setResponseData($value) + { + $this->_response->getAdapter()->setResponseData($value); + } + + /** + * @return mixed callback response data. + */ + public function getResponseData() + { + return $this->_response->getAdapter()->getResponseData(); + } +} + +?> \ No newline at end of file diff --git a/framework/Web/UI/ActiveControls/TInPlaceTextBox.php b/framework/Web/UI/ActiveControls/TInPlaceTextBox.php index 88db2d8f..e1305ed0 100644 --- a/framework/Web/UI/ActiveControls/TInPlaceTextBox.php +++ b/framework/Web/UI/ActiveControls/TInPlaceTextBox.php @@ -232,5 +232,18 @@ class TInPlaceTextBox extends TActiveTextBox { return 'Prado.WebUI.TInPlaceTextBox'; } + + /** + * Ensure that the ID attribute is rendered and registers the javascript code + * for initializing the active control. + */ + protected function addAttributesToRender($writer) + { + TTextBox::addAttributesToRender($writer); + $writer->addAttribute('id',$this->getLabelClientID()); + $this->getActiveControl()->registerCallbackClientScript( + $this->getClientClassName(), $this->getPostBackOptions()); + } + } ?> \ No newline at end of file -- cgit v1.2.3