From ae43fa72cdae13bace16a5b8250170e472bb2b87 Mon Sep 17 00:00:00 2001 From: wei <> Date: Sun, 14 May 2006 00:30:53 +0000 Subject: refactor active controls. --- framework/Web/Javascripts/js/ajax.js | 20 +- framework/Web/Javascripts/prado/ajax3.js | 30 ++- framework/Web/UI/ActiveControls/TActiveButton.php | 106 +---------- .../UI/ActiveControls/TActiveControlAdapter.php | 171 ++++++++++++++++- framework/Web/UI/ActiveControls/TActiveLabel.php | 31 +--- .../Web/UI/ActiveControls/TActivePageAdapter.php | 2 +- framework/Web/UI/ActiveControls/TActivePanel.php | 5 + framework/Web/UI/ActiveControls/TActiveTextBox.php | 111 +---------- framework/Web/UI/ActiveControls/TAutoComplete.php | 176 ++++++++---------- .../Web/UI/ActiveControls/TBaseActiveControl.php | 205 +++++++++++++++++++++ framework/Web/UI/ActiveControls/TCallback.php | 131 +------------ .../ActiveControls/TCallbackClientSideOptions.php | 24 +++ framework/Web/UI/TClientScriptManager.php | 2 +- framework/Web/UI/TControl.php | 2 +- 14 files changed, 543 insertions(+), 473 deletions(-) create mode 100644 framework/Web/UI/ActiveControls/TBaseActiveControl.php (limited to 'framework/Web') diff --git a/framework/Web/Javascripts/js/ajax.js b/framework/Web/Javascripts/js/ajax.js index ba4bdbaf..6e6d0afb 100644 --- a/framework/Web/Javascripts/js/ajax.js +++ b/framework/Web/Javascripts/js/ajax.js @@ -34,13 +34,18 @@ this.transport.onreadystatechange=Prototype.emptyFunction;},getHeaderData:functi catch(e) {if(typeof(json)=="string") {Logger.info("using json") -return Prado.CallbackRequest.decode(json);}}}});Prado.CallbackRequest=Class.create();Object.extend(Prado.CallbackRequest,{FIELD_CALLBACK_TARGET:'PRADO_CALLBACK_TARGET',FIELD_CALLBACK_PARAMETER:'PRADO_CALLBACK_PARAMETER',FIELD_CALLBACK_PAGESTATE:'PRADO_PAGESTATE',PostDataLoaders:[],DATA_HEADER:'X-PRADO-DATA',ACTION_HEADER:'X-PRADO-ACTIONS',ERROR_HEADER:'X-PRADO-ERROR',PAGESTATE_HEADER:'X-PRADO-PAGESTATE',requestInProgress:null,dispatchActions:function(transport,actions) +return Prado.CallbackRequest.decode(json);}}}});Prado.CallbackRequest=Class.create();Object.extend(Prado.CallbackRequest,{FIELD_CALLBACK_TARGET:'PRADO_CALLBACK_TARGET',FIELD_CALLBACK_PARAMETER:'PRADO_CALLBACK_PARAMETER',FIELD_CALLBACK_PAGESTATE:'PRADO_PAGESTATE',FIELD_POSTBACK_TARGET:'PRADO_POSTBACK_TARGET',FIELD_POSTBACK_PARAMETER:'PRADO_POSTBACK_PARAMETER',PostDataLoaders:[],DATA_HEADER:'X-PRADO-DATA',ACTION_HEADER:'X-PRADO-ACTIONS',ERROR_HEADER:'X-PRADO-ERROR',PAGESTATE_HEADER:'X-PRADO-PAGESTATE',requestInProgress:null,dispatchActions:function(transport,actions) {if(actions&&actions.length>0) actions.each(this.__run.bind(this,transport));},__run:function(transport,command) {for(var method in command) {if(command[method][0]) {var id=command[method][0];if($(id)||id.indexOf("[]")>-1) -method.toFunction().apply(this,command[method].concat(transport));else if(typeof(Logger)!="undefined") +{try +{method.toFunction().apply(this,command[method].concat(transport));} +catch(e) +{if(typeof(Logger)!="undefined") +Prado.CallbackRequest.Exception.onException(null,e);}} +else if(typeof(Logger)!="undefined") {Logger.error("Error in executing callback response:","Unable to find HTML element with ID '"+id+"' before executing "+method+"().");}}}},Exception:{"on500":function(request,transport,data) {var e=request.getHeaderData(Prado.CallbackRequest.ERROR_HEADER);Logger.error("Callback Server Error "+e.code,this.formatException(e));},'on200':function(request,transport,data) {if(transport.status<500) @@ -48,10 +53,9 @@ method.toFunction().apply(this,command[method].concat(transport));else if(typeof {data.each(function(action) {msg+=inspect(action)+"\n";});} Logger.warn(msg);}},onException:function(request,e) -{msg="";for(var v in e) -{if(typeof(v[e])!="object"&&typeof(v[e])!="function") -msg+=v+":"+e[v]+"\n";} -Logger.error('Uncaught Callback Client Exception:',e);},formatException:function(e) +{msg="";$H(e).each(function(item) +{msg+=item.key+": "+item.value+"\n";}) +Logger.error('Uncaught Callback Client Exception:',msg);},formatException:function(e) {var msg=e.type+" with message \""+e.message+"\"";msg+=" in "+e.file+"("+e.line+")\n";msg+="Stack trace:\n";var trace=e.trace;for(var i=0;i"+trace[i]["function"]+"()"+"\n";} msg+=e.version+" "+e.time+"\n";return msg;}},encode:function(data) @@ -91,7 +95,9 @@ Prado.CallbackRequest.dispatchNormalRequest(this);},_getPostData:function() data[name]=value;})})} if(typeof(this.options.params)!="undefined") data[callback.FIELD_CALLBACK_PARAMETER]=callback.encode(this.options.params);var pageState=$F(callback.FIELD_CALLBACK_PAGESTATE);if(typeof(pageState)!="undefined") -data[callback.FIELD_CALLBACK_PAGESTATE]=pageState;data[callback.FIELD_CALLBACK_TARGET]=this.id;return $H(data).toQueryString();}} +data[callback.FIELD_CALLBACK_PAGESTATE]=pageState;data[callback.FIELD_CALLBACK_TARGET]=this.id;if(this.options.EventTarget) +data[callback.FIELD_POSTBACK_TARGET]=this.options.EventTarget;if(this.options.EventParameter) +data[callback.FIELD_POSTBACK_PARAMETER]=this.options.EventParameter;return $H(data).toQueryString();}} Prado.Callback=function(UniqueID,parameter,onSuccess,options) {var callback={'params':parameter||'','onSuccess':onSuccess||Prototype.emptyFunction};Object.extend(callback,options||{});new Prado.CallbackRequest(UniqueID,callback);return false;} Array.prototype.______array='______array';Prado.JSON={org:'http://www.JSON.org',copyright:'(c)2005 JSON.org',license:'http://www.crockford.com/JSON/license.html',stringify:function(arg){var c,i,l,s='',v;switch(typeof arg){case'object':if(arg){if(arg.______array=='______array'){for(i=0;i -1) - method.toFunction().apply(this,command[method].concat(transport)); + { + try + { + method.toFunction().apply(this,command[method].concat(transport)); + } + catch(e) + { + if(typeof(Logger) != "undefined") + Prado.CallbackRequest.Exception.onException(null,e); + } + } else if(typeof(Logger) != "undefined") { Logger.error("Error in executing callback response:", @@ -185,12 +200,11 @@ Object.extend(Prado.CallbackRequest, onException : function(request,e) { msg = ""; - for(var v in e) + $H(e).each(function(item) { - if(typeof(v[e]) != "object" && typeof(v[e]) != "function") - msg += v+":"+e[v]+"\n"; - } - Logger.error('Uncaught Callback Client Exception:', e); + msg += item.key+": "+item.value+"\n"; + }) + Logger.error('Uncaught Callback Client Exception:', msg); }, /** @@ -407,6 +421,10 @@ Prado.CallbackRequest.prototype = if(typeof(pageState) != "undefined") data[callback.FIELD_CALLBACK_PAGESTATE] = pageState; data[callback.FIELD_CALLBACK_TARGET] = this.id; + if(this.options.EventTarget) + data[callback.FIELD_POSTBACK_TARGET] = this.options.EventTarget; + if(this.options.EventParameter) + data[callback.FIELD_POSTBACK_PARAMETER] = this.options.EventParameter; return $H(data).toQueryString(); } } diff --git a/framework/Web/UI/ActiveControls/TActiveButton.php b/framework/Web/UI/ActiveControls/TActiveButton.php index da5ec5ad..3343d7fe 100644 --- a/framework/Web/UI/ActiveControls/TActiveButton.php +++ b/framework/Web/UI/ActiveControls/TActiveButton.php @@ -5,11 +5,6 @@ class TActiveButton extends TButton implements ICallbackEventHandler { - /** - * @var TCallbackClientSideOptions client-side options. - */ - private $_clientSide; - /** * Creates a new callback control, sets the adapter to * TActiveControlAdapter. If you override this class, be sure to set the @@ -22,29 +17,13 @@ class TActiveButton extends TButton implements ICallbackEventHandler } /** - * @param boolean true to allow fine grain callback updates. + * @return TBaseActiveCallbackControl base callback options. */ - public function setAllowCallbackUpdate($value) + public function getActiveControl() { - $this->setViewState('CallbackUpdate', TPropertyValue::ensureBoolean($value), true); + return $this->getAdapter()->getActiveControl(); } - - /** - * @return true to allow fine grain callback updates. - */ - public function getAllowCallbackUpdate() - { - return $this->getViewState('CallbackUpdate', true); - } - - /** - * @return true if can update changes on the client-side during callback. - */ - protected function canUpdateClientSide() - { - return $this->getIsInitialized() && $this->getAllowCallbackUpdate(); - } - + /** * Raises the callback event. This method is required by {@link * ICallbackEventHandler} interface. If {@link getCausesValidation @@ -78,89 +57,22 @@ class TActiveButton extends TButton implements ICallbackEventHandler public function setText($value) { parent::setText($value); - if($this->canUpdateClientSide()) + if($this->getActiveControl()->canUpdateClientSide()) $this->getPage()->getCallbackClient()->setAttribute($this, 'value', $value); } - - /** - * Callback client-side options can be set by setting the properties of - * the ClientSide property. E.g. - * See {@link TCallbackClientSideOptions} for details on the properties of - * ClientSide. - * @return TCallbackClientSideOptions client-side callback options. - */ - public function getClientSide() - { - if(is_null($this->_clientSide)) - $this->_clientSide = $this->createClientSideOptions(); - return $this->_clientSide; - } - - /** - * @return TCallbackClientSideOptions callback client-side options. - */ - protected function createClientSideOptions() - { - if(($id=$this->getCallbackOptions())!=='' && ($control=$this->findControl($id))!==null) - { - if($control instanceof TCallbackOptions) - return clone($control->getClientSide()); - } - return new TCallbackClientSideOptions; - } - - /** - * Sets the ID of a TCallbackOptions component to duplicate the client-side - * options for this control. The {@link getClientSide ClientSide} - * subproperties has precendent over the CallbackOptions property. - * @param string ID of a TCallbackOptions control from which ClientSide - * options are cloned. - */ - public function setCallbackOptions($value) - { - $this->setViewState('CallbackOptions', $value,''); - } - - /** - * @return string ID of a TCallbackOptions control from which ClientSide - * options are cloned. - */ - public function getCallbackOptions() - { - return $this->getViewState('CallbackOptions',''); - } /** * Renders the callback control javascript statement. */ protected function renderClientControlScript($writer) { - $writer->addAttribute('id',$this->getClientID()); - $cs = $this->getPage()->getClientScript(); - $cs->registerCallbackControl(get_class($this),$this->getCallbackOptions()); } - /** - * @return array list of callback options. - */ - protected function getCallbackClientSideOptions() - { - return array_merge($this->getPostBackOptions(), - $this->getClientSide()->getOptions()->toArray()); - } - - /** - * Returns the javascript statement to invoke a callback request for this - * control. Additional options for callback can be set via subproperties of - * {@link getClientSide ClientSide} property. E.g. ClientSide.OnSuccess="..." - * @param TControl callback handler control, use current object if null. - * @return string javascript statement to invoke a callback. - */ - public function getCallbackReference($control=null) + protected function addAttributesToRender($writer) { - $client = $this->getPage()->getClientScript(); - $object = is_null($control) ? $this : $control; - return $client->getCallbackReference($object, $this->getCallbackClientSideOptions()); + parent::addAttributesToRender($writer); + $writer->addAttribute('id',$this->getClientID()); + $this->getActiveControl()->registerCallbackClientScript($this->getPostBackOptions()); } } diff --git a/framework/Web/UI/ActiveControls/TActiveControlAdapter.php b/framework/Web/UI/ActiveControls/TActiveControlAdapter.php index 1cdd5d73..af4131ea 100644 --- a/framework/Web/UI/ActiveControls/TActiveControlAdapter.php +++ b/framework/Web/UI/ActiveControls/TActiveControlAdapter.php @@ -2,28 +2,187 @@ /* * Created on 29/04/2006 */ +Prado::using('System.Web.UI.ActiveControls.TBaseActiveControl'); class TActiveControlAdapter extends TControlAdapter { private static $_renderedPosts = false; + private $_activeControlType; + + private $_baseActiveControl; + + private $_stateTracker; + + public function __construct($control, $baseCallbackClass=null) + { + parent::__construct($control); + $this->setBaseControlType($baseCallbackClass); + } + + private function setBaseControlType($type) + { + if(is_null($type)) + { + if($this->getControl() instanceof ICallbackEventHandler) + $this->_activeControlType = 'TBaseActiveCallbackControl'; + else + $this->_activeControlType = 'TBaseActiveControl'; + } + else + { + $this->_activeControlType = $type; + } + } + /** * Render the callback request post data loaders once only. */ public function render($writer) { - if(!self::$_renderedPosts) + $this->renderCallbackClientScripts(); + parent::render($writer); + if($this->getPage()->getIsCallback()) + $this->getPage()->getCallbackClient()->replace($this->getControl(), $writer); + } + + protected function renderCallbackClientScripts() + { + $cs = $this->getPage()->getClientScript(); + $key = get_class($this); + if(!$cs->isEndScriptRegistered($key)) { - $cs = $this->getPage()->getClientScript(); $cs->registerPradoScript('ajax'); $options = TJavascript::encode($this->getPage()->getPostDataLoaders(),false); $script = "Prado.CallbackRequest.PostDataLoaders = {$options};"; - $cs->registerEndScript(get_class($this), $script); - self::$_renderedPosts = true; + $cs->registerEndScript($key, $script); } - parent::render($writer); + } + + public function getActiveControl() + { + if(is_null($this->_baseActiveControl)) + { + $type = $this->_activeControlType; + $this->_baseActiveControl = new $type($this->getControl()); + } + return $this->_baseActiveControl; + } + + protected function getIsTrackingPageState() + { if($this->getPage()->getIsCallback()) - $this->getPage()->getCallbackClient()->replace($this->getControl(), $writer); + { + $target = $this->getPage()->getCallbackEventTarget(); + if($target instanceof ICallbackEventHandler) + { + $client = $target->getActiveControl()->getClientSide(); + return $client->getEnablePageStateUpdate(); + } + } + return false; + } + + public function loadState() + { + if($this->getIsTrackingPageState()) + { + $this->_stateTracker = new TCallbackPageStateTracker($this->getControl()); + $this->_stateTracker->trackChanges(); + } + parent::loadState(); + } + + public function saveState() + { + if(!is_null($this->_stateTracker) + && $this->getControl()->getActiveControl()->canUpdateClientSide()) + { + $this->_stateTracker->respondToChanges(); + } + parent::saveState(); } } + +class TCallbackPageStateTracker +{ + private $_states = array('Visible', 'Enabled', 'Attributes', 'Style', 'TabIndex', 'ToolTip', 'AccessKey'); + private $_existingState; + private $_control; + private $_nullObject; + + public function __construct($control) + { + $this->_control = $control; + $this->_existingState = new TMap; + $this->_nullObject = new stdClass; + } + + public function trackChanges() + { + foreach($this->_states as $name) + $this->_existingState[$name] = $this->_control->getViewState($name); + } + + protected function getChanges() + { + $diff = array(); + foreach($this->_states as $name) + { + $state = $this->_control->getViewState($name); + // echo " $name "; + $changes = $this->difference($state, $this->_existingState[$name]); + // echo " \n "; + if($changes !== $this->_nullObject) + $diff[$name] = $changes; + } + return $diff; + } + + protected function difference($value1, $value2) + { +// var_dump($value1, $value2); + if(gettype($value1) === gettype($value2) + && $value1 === $value2) return $this->_nullObject; + return $value1; + } + + public function respondToChanges() + { + foreach($this->getChanges() as $property => $value) + { + $this->{'update'.$property}($value); + } + } + + protected function client() + { + return $this->_control->getPage()->getCallbackClient(); + } + + protected function updateToolTip($value) + { + $this->client()->setAttribute($this->_control, 'title', $value); + } + + protected function updateVisible($visible) + { + var_dump($visible); + if($visible === false) + $this->client()->hide($this->_control); + else + $this->client()->show($this->_control); + } + + protected function updateEnabled($enable) + { + $this->client()->setAttribute($this->_control, 'disabled', $enable===false); + } + + protected function updateStyle($style) + { + var_dump($style); + } +} + ?> \ No newline at end of file diff --git a/framework/Web/UI/ActiveControls/TActiveLabel.php b/framework/Web/UI/ActiveControls/TActiveLabel.php index 13a88b4f..fd2d49b8 100644 --- a/framework/Web/UI/ActiveControls/TActiveLabel.php +++ b/framework/Web/UI/ActiveControls/TActiveLabel.php @@ -37,32 +37,11 @@ class TActiveLabel extends TLabel $this->setAdapter(new TActiveControlAdapter($this)); } - /** - * @param boolean true to allow fine grain callback updates. - */ - public function setAllowCallbackUpdate($value) - { - $this->setViewState('CallbackUpdate', TPropertyValue::ensureBoolean($value), true); - } - - /** - * @return true to allow fine grain callback updates. - */ - public function getAllowCallbackUpdate() + public function getActiveControl() { - return $this->getViewState('CallbackUpdate', true); + return $this->getAdapter()->getActiveControl(); } - - /** - * @return true if can update changes on the client-side during callback. - */ - protected function canUpdateClientSide() - { - return $this->getIsInitialized() - && $this->getPage()->getIsCallback() - && $this->getAllowCallbackUpdate(); - } - + /** * On callback response, the inner HTMl of the label is updated. * @param string the text value of the label @@ -70,7 +49,7 @@ class TActiveLabel extends TLabel public function setText($value) { parent::setText($value); - if($this->canUpdateClientSide()) + if($this->getActiveControl()->canUpdateClientSide()) $this->getPage()->getCallbackClient()->update($this, $value); } @@ -83,7 +62,7 @@ class TActiveLabel extends TLabel public function setForControl($value) { parent::setForControl($value); - if($this->canUpdateClientSide()) + if($this->getActiveControl()->canUpdateClientSide()) { $id=$this->findControl($value)->getClientID(); $this->getPage()->getCallbackClient()->setAttribute($this, 'for', $id); diff --git a/framework/Web/UI/ActiveControls/TActivePageAdapter.php b/framework/Web/UI/ActiveControls/TActivePageAdapter.php index e92c9cdc..9148a27f 100644 --- a/framework/Web/UI/ActiveControls/TActivePageAdapter.php +++ b/framework/Web/UI/ActiveControls/TActivePageAdapter.php @@ -95,7 +95,7 @@ class TActivePageAdapter extends TControlAdapter } if(($handler = $this->getCallbackEventTarget()) !== null) { - if($handler->getClientSide()->getEnablePageStateUpdate()) + if($handler->getActiveControl()->getClientSide()->getEnablePageStateUpdate()) { $pagestate = $this->getPage()->getClientState(); $response->appendHeader(self::CALLBACK_PAGESTATE_HEADER.': '.$pagestate); diff --git a/framework/Web/UI/ActiveControls/TActivePanel.php b/framework/Web/UI/ActiveControls/TActivePanel.php index b3568279..bd7b2200 100644 --- a/framework/Web/UI/ActiveControls/TActivePanel.php +++ b/framework/Web/UI/ActiveControls/TActivePanel.php @@ -15,6 +15,11 @@ class TActivePanel extends TPanel parent::__construct(); $this->setAdapter(new TActiveControlAdapter($this)); } + + public function getActiveControl() + { + return $this->getAdapter()->getActiveControl(); + } } ?> \ No newline at end of file diff --git a/framework/Web/UI/ActiveControls/TActiveTextBox.php b/framework/Web/UI/ActiveControls/TActiveTextBox.php index ad28b291..fba36a14 100644 --- a/framework/Web/UI/ActiveControls/TActiveTextBox.php +++ b/framework/Web/UI/ActiveControls/TActiveTextBox.php @@ -3,13 +3,8 @@ * Created on 6/05/2006 */ -class TActiveTextBox extends TTextBox implements ICallbackEventHandler +class TActiveTextBox extends TTextBox { - /** - * @var TCallbackClientSideOptions client-side options. - */ - private $_clientSide; - /** * Creates a new callback control, sets the adapter to * TActiveControlAdapter. If you override this class, be sure to set the @@ -21,79 +16,11 @@ class TActiveTextBox extends TTextBox implements ICallbackEventHandler $this->setAdapter(new TActiveControlAdapter($this)); } - /** - * @param boolean true to allow fine grain callback updates. - */ - public function setAllowCallbackUpdate($value) - { - $this->setViewState('CallbackUpdate', TPropertyValue::ensureBoolean($value), true); - } - - /** - * @return true to allow fine grain callback updates. - */ - public function getAllowCallbackUpdate() - { - return $this->getViewState('CallbackUpdate', true); - } - - /** - * @return true if can update changes on the client-side during callback. - */ - protected function canUpdateClientSide() - { - return $this->getIsInitialized() - && $this->getPage()->getIsCallback() - && $this->getAllowCallbackUpdate(); - } - - /** - * Callback client-side options can be set by setting the properties of - * the ClientSide property. E.g. - * See {@link TCallbackClientSideOptions} for details on the properties of - * ClientSide. - * @return TCallbackClientSideOptions client-side callback options. - */ - public function getClientSide() + public function getActiveControl() { - if(is_null($this->_clientSide)) - $this->_clientSide = $this->createClientSideOptions(); - return $this->_clientSide; + return $this->getAdapter()->getActiveControl(); } - /** - * @return TCallbackClientSideOptions callback client-side options. - */ - protected function createClientSideOptions() - { - return new TCallbackClientSideOptions; - } - - /** - * Raises the callback event. This method is required by {@link - * ICallbackEventHandler} interface. It class raisePostDataChangedEvent - * first then raises {@link onCallback OnCallback} event. This method is - * mainly used by framework and control developers. - * @param TCallbackEventParameter the event parameter - */ - public function raiseCallbackEvent($param) - { - $this->raisePostDataChangedEvent(); - $this->onCallback($param); - } - - /** - * This method is invoked when a callback is requested. The method raises - * 'OnCallback' event to fire up the event handlers. 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 onCallback($param) - { - $this->raiseEvent('OnCallback', $this, $param); - } - /** * Client-side Text property can only be updated after the OnLoad stage. * @param string text content for the textbox @@ -101,39 +28,9 @@ class TActiveTextBox extends TTextBox implements ICallbackEventHandler public function setText($value) { parent::setText($value); - if($this->canUpdateClientSide() && $this->getHasLoadedPostData()) + if($this->getActiveControl()->canUpdateClientSide() && $this->getHasLoadedPostData()) $this->getPage()->getCallbackClient()->setValue($this, $value); } - - protected function renderClientControlScript($writer) - { - $writer->addAttribute('id',$this->getClientID()); - $cs = $this->getPage()->getClientScript(); - $cs->registerCallbackControl(get_class($this),$this->getCallbackOptions()); - } - - /** - * @return array list of callback options. - */ - protected function getCallbackOptions() - { - return array_merge($this->getPostBackOptions(), - $this->getClientSide()->getOptions()->toArray()); - } - - /** - * Returns the javascript statement to invoke a callback request for this - * control. Additional options for callback can be set via subproperties of - * {@link getClientSide ClientSide} property. E.g. ClientSide.OnSuccess="..." - * @param TControl callback handler control, use current object if null. - * @return string javascript statement to invoke a callback. - */ - public function getCallbackReference($control=null) - { - $client = $this->getPage()->getClientScript(); - $object = is_null($control) ? $this : $control; - return $client->getCallbackReference($object, $this->getPostBackOptions()); - } } ?> \ No newline at end of file diff --git a/framework/Web/UI/ActiveControls/TAutoComplete.php b/framework/Web/UI/ActiveControls/TAutoComplete.php index 025a7977..5a76847d 100644 --- a/framework/Web/UI/ActiveControls/TAutoComplete.php +++ b/framework/Web/UI/ActiveControls/TAutoComplete.php @@ -11,6 +11,62 @@ class TAutoComplete extends TActiveTextBox implements ICallbackEventHandler, INa private $_repeater=null; private $_resultPanel=null; + public function getSeparator() + { + return $this->getViewState('tokens', ''); + } + + public function setSeparator($value) + { + $this->setViewState('tokens', TPropertyValue::ensureString($value), ''); + } + + public function getFrequency() + { + return $this->getViewState('frequency', ''); + } + + public function setFrequency($value) + { + $this->setViewState('frequency', TPropertyValue::ensureFloat($value),''); + } + + public function getMinChars() + { + return $this->getViewState('minChars',''); + } + + public function setMinChars($value) + { + $this->setViewState('minChars', TPropertyValue::ensureInteger($value), ''); + } + + /** + * Raises the callback event. This method is required by {@link + * ICallbackEventHandler} interface. If {@link getCausesValidation + * CausesValidation} is true, it will invoke the page's {@link TPage:: + * validate validate} method first. It will raise {@link onCallback + * OnCallback} event and then the {@link onClick OnClick} event. This method + * is mainly used by framework and control developers. + * @param TCallbackEventParameter the event parameter + */ + public function raiseCallbackEvent($param) + { + $this->onCallback($param); + } + + /** + * This method is invoked when a callback is requested. The method raises + * 'OnCallback' event to fire up the event handlers. 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 onCallback($param) + { + $this->raiseEvent('OnCallback', $this, $param); + } + public function setDataSource($data) { $this->getSuggestions()->setDataSource($data); @@ -54,47 +110,6 @@ class TAutoComplete extends TActiveTextBox implements ICallbackEventHandler, INa return $repeater; } - /** - * @return TCallbackClientSideOptions callback client-side options. - */ - protected function createClientSideOptions() - { - if(($id=$this->getCallbackOptions())!=='' && ($control=$this->findControl($id))!==null) - { - if($control instanceof TCallbackOptions) - { - $options = clone($control->getClientSide()); - $options->setEnablePageStateUpdate(false); - return $options; - } - } - $options = new TAutoCompleteClientSideOptions; - $options->setEnablePageStateUpdate(false); - return $options; - } - - /** - * Sets the ID of a TCallbackOptions component to duplicate the client-side - * options for this control. The {@link getClientSide ClientSide} - * subproperties has precendent over the CallbackOptions property. - * @param string ID of a TCallbackOptions control from which ClientSide - * options are cloned. - */ - public function setCallbackOptions($value) - { - $this->setViewState('CallbackOptions', $value,''); - } - - /** - * @return string ID of a TCallbackOptions control from which ClientSide - * options are cloned. - */ - public function getCallbackOptions() - { - return $this->getViewState('CallbackOptions',''); - } - - public function renderEndTag($writer) { $this->getPage()->getClientScript()->registerPradoScript('effects'); @@ -109,24 +124,36 @@ class TAutoComplete extends TActiveTextBox implements ICallbackEventHandler, INa public function render($writer) { - if($this->canUpdateClientSide()) + if($this->getPage()->getIsCallback()) { - $this->getSuggestions()->render($writer); - $boundary = $writer->getWriter()->getBoundary(); - $writer->getWriter()->getResponse()->setData($boundary); + if($this->getActiveControl()->canUpdateClientSide()) + $this->renderSuggestions($writer); } else parent::render($writer); } + + protected function renderSuggestions($writer) + { + if($this->getSuggestions()->getItems()->getCount() > 0) + { + $this->getSuggestions()->render($writer); + $boundary = $writer->getWriter()->getBoundary(); + $writer->getWriter()->getResponse()->setData($boundary); + } + } /** * @return array list of callback options. */ - protected function getCallbackClientSideOptions() + protected function getAutoCompleteOptions() { - $options = $this->getClientSide()->getOptions()->toArray(); - if(isset($options['tokens'])) - $options['tokens'] = TJavascript::encode($options['tokens'],false); + $this->getActiveControl()->getClientSide()->setEnablePageStateUpdate(false); + if(strlen($string = $this->getSeparator())) + { + $token = preg_split('//', $string, -1, PREG_SPLIT_NO_EMPTY); + $options['tokens'] = TJavascript::encode($token,false); + } if($this->getAutoPostBack()) $options = array_merge($options,$this->getPostBackOptions()); $options['ResultPanel'] = $this->getResultPanel()->getClientID(); @@ -135,57 +162,16 @@ class TAutoComplete extends TActiveTextBox implements ICallbackEventHandler, INa return $options; } - /** - * Adds attribute name-value pairs to renderer. - * This method overrides the parent implementation with additional textbox specific attributes. - * @param THtmlWriter the writer used for the rendering purpose - */ - protected function addAttributesToRender($writer) + public function addAttributesToRender($writer) { parent::addAttributesToRender($writer); - $this->renderClientControlScript($writer); + $writer->addAttribute('id',$this->getClientID()); + $this->getActiveControl()->registerCallbackClientScript($this->getAutoCompleteOptions()); } -} - -/** - * Client-side options for TAutoComplete. - * - * @author Wei Zhuo - * @version $Revision: $ $Date: $ - * @package System.Web.UI.ActiveControls - * @since 3.0 - */ -class TAutoCompleteClientSideOptions extends TCallbackClientSideOptions -{ - public function getSeparator() - { - return $this->getOption('tokens'); - } - - public function setSeparator($value) - { - $this->setOption('tokens', preg_split('//', $value, -1, PREG_SPLIT_NO_EMPTY)); - } - - public function getFrequency() - { - return $this->getOption('frequency'); - } - - public function setFrequency($value) - { - $this->setOption('frequency', TPropertyValue::ensureFloat($value)); - } - - public function getMinChars() - { - return $this->getOption('minChars'); - } - - public function setMinChars($value) + protected function renderClientControlScript($writer) { - $this->setOption('minChars', TPropertyValue::ensureInteger($value)); + } } diff --git a/framework/Web/UI/ActiveControls/TBaseActiveControl.php b/framework/Web/UI/ActiveControls/TBaseActiveControl.php new file mode 100644 index 00000000..c5a62ade --- /dev/null +++ b/framework/Web/UI/ActiveControls/TBaseActiveControl.php @@ -0,0 +1,205 @@ +_control = $control; + $this->_options = new TMap; + } + + protected function setOption($name,$value,$default=null) + { + $value = is_null($value) ? $default : $value; + if(!is_null($value)) + $this->_options->add($name,$value); + } + + protected function getOption($name,$default=null) + { + $item = $this->_options->itemAt($name); + return is_null($item) ? $default : $item; + } + + protected function getPage() + { + return $this->_control->getPage(); + } + + protected function getControl() + { + return $this->_control; + } + + /** + * @param boolean true to allow fine grain callback updates. + */ + public function setEnableUpdate($value) + { + $this->setOption('EnableUpdate', TPropertyValue::ensureBoolean($value), true); + } + + /** + * @return true to allow fine grain callback updates. + */ + public function getEnableUpdate() + { + return $this->getOption('EnableUpdate', true); + } + + public function canUpdateClientSide() + { + return $this->getControl()->getIsInitialized() + && $this->getPage()->getIsCallback() + && $this->getEnableUpdate(); + } +} + + +class TBaseActiveCallbackControl extends TBaseActiveControl +{ + /** + * Callback client-side options can be set by setting the properties of + * the ClientSide property. E.g. + * See {@link TCallbackClientSideOptions} for details on the properties of + * ClientSide. + * @return TCallbackClientSideOptions client-side callback options. + */ + public function getClientSide() + { + if(is_null($client = $this->getOption('ClientSide'))) + { + $client = $this->createClientSide(); + $this->setOption('ClientSide', $client); + } + return $client; + } + + /** + * @return TCallbackClientSideOptions callback client-side options. + */ + protected function createClientSide() + { + if(($id=$this->getCallbackOptions())!=='' + && ($control=$this->getControl()->findControl($id))!==null) + { + if($control instanceof TCallbackOptions) + return $control->getClientSide(); + } + return new TCallbackClientSideOptions; + } + + /** + * Sets the ID of a TCallbackOptions component to duplicate the client-side + * options for this control. The {@link getClientSide ClientSide} + * subproperties has precendent over the CallbackOptions property. + * @param string ID of a TCallbackOptions control from which ClientSide + * options are cloned. + */ + public function setCallbackOptions($value) + { + $this->setOption('CallbackOptions', $value, ''); + } + + /** + * @return string ID of a TCallbackOptions control from which ClientSide + * options are cloned. + */ + public function getCallbackOptions() + { + return $this->getOption('CallbackOptions', ''); + } + + /** + * @return boolean whether callback event trigger by this button will cause + * input validation, default is true + */ + public function getCausesValidation() + { + return $this->getOption('CausesValidation',true); + } + + /** + * @param boolean whether callback event trigger by this button will cause + * input validation + */ + public function setCausesValidation($value) + { + $this->setOption('CausesValidation',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return string the group of validators which the button causes validation + * upon callback + */ + public function getValidationGroup() + { + return $this->getOption('ValidationGroup',''); + } + + /** + * @param string the group of validators which the button causes validation + * upon callback + */ + public function setValidationGroup($value) + { + $this->getOption('ValidationGroup',$value,''); + } + + /** + * @return boolean whether to perform validation if the callback is + * requested. + */ + public function canCauseValidation() + { + if($this->getCausesValidation()) + { + $group=$this->getValidationGroup(); + return $this->getPage()->getValidators($group)->getCount()>0; + } + else + return false; + } + + /** + * @return array list of callback javascript options. + */ + protected function getClientSideOptions() + { + $options = $this->getClientSide()->getOptions()->toArray(); + $validate = $this->getCausesValidation(); + $options['CausesValidation']= $validate ? '' : false; + $options['ValidationGroup']=$this->getValidationGroup(); + return $options; + } + + public function registerCallbackClientScript($options=null) + { + $cs = $this->getPage()->getClientScript(); + if(is_array($options)) + $options = array_merge($this->getClientSideOptions(),$options); + else + $options = $this->getClientSideOptions(); + $cs->registerCallbackControl(get_class($this->getControl()), $options); + } + + /** + * Returns the javascript statement to invoke a callback request for this + * control. Additional options for callback can be set via subproperties of + * {@link getClientSide ClientSide} property. E.g. ClientSide. + * OnSuccess="..." + * @return string javascript statement to invoke a callback. + */ + public function getJavascript() + { + $client = $this->getPage()->getClientScript(); + return $client->getCallbackReference($this->getControl(),$this->getClientSideOptions()); + } +} + +?> \ No newline at end of file diff --git a/framework/Web/UI/ActiveControls/TCallback.php b/framework/Web/UI/ActiveControls/TCallback.php index 7bb4ee21..681093ee 100644 --- a/framework/Web/UI/ActiveControls/TCallback.php +++ b/framework/Web/UI/ActiveControls/TCallback.php @@ -26,11 +26,6 @@ */ class TCallback extends TControl implements ICallbackEventHandler { - /** - * @var TCallbackClientSideOptions client-side options. - */ - private $_clientSide; - /** * Creates a new callback control, sets the adapter to * TActiveControlAdapter. If you override this class, be sure to set the @@ -43,104 +38,13 @@ class TCallback extends TControl implements ICallbackEventHandler } /** - * @return boolean whether callback event trigger by this button will cause - * input validation, default is true - */ - public function getCausesValidation() - { - return $this->getViewState('CausesValidation',true); - } - - /** - * @param boolean whether callback event trigger by this button will cause - * input validation - */ - public function setCausesValidation($value) - { - $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true); - } - - /** - * @return string the group of validators which the button causes validation - * upon callback - */ - public function getValidationGroup() - { - return $this->getViewState('ValidationGroup',''); - } - - /** - * @param string the group of validators which the button causes validation - * upon callback + * @return TBaseActiveCallbackControl base callback options. */ - public function setValidationGroup($value) + public function getActiveControl() { - $this->setViewState('ValidationGroup',$value,''); + return $this->getAdapter()->getActiveControl(); } - /** - * Callback client-side options can be set by setting the properties of - * the ClientSide property. E.g. - * See {@link TCallbackClientSideOptions} for details on the properties of - * ClientSide. - * @return TCallbackClientSideOptions client-side callback options. - */ - public function getClientSide() - { - if(is_null($this->_clientSide)) - $this->_clientSide = $this->createClientSideOptions(); - return $this->_clientSide; - } - - /** - * @return TCallbackClientSideOptions callback client-side options. - */ - protected function createClientSideOptions() - { - if(($id=$this->getCallbackOptions())!=='' && ($control=$this->findControl($id))!==null) - { - if($control instanceof TCallbackOptions) - return clone($control->getClientSide()); - } - return new TCallbackClientSideOptions; - } - - /** - * Sets the ID of a TCallbackOptions component to duplicate the client-side - * options for this control. The {@link getClientSide ClientSide} - * subproperties has precendent over the CallbackOptions property. - * @param string ID of a TCallbackOptions control from which ClientSide - * options are cloned. - */ - public function setCallbackOptions($value) - { - $this->setViewState('CallbackOptions', $value,''); - } - - /** - * @return string ID of a TCallbackOptions control from which ClientSide - * options are cloned. - */ - public function getCallbackOptions() - { - return $this->getViewState('CallbackOptions',''); - } - - /** - * @return boolean whether to perform validation if the callback is - * requested. - */ - protected function canCauseValidation() - { - if($this->getCausesValidation()) - { - $group=$this->getValidationGroup(); - return $this->getPage()->getValidators($group)->getCount()>0; - } - else - return false; - } - /** * Raises the callback event. This method is required by {@link * ICallbackEventHandler} interface. If {@link getCausesValidation @@ -152,8 +56,8 @@ class TCallback extends TControl implements ICallbackEventHandler */ public function raiseCallbackEvent($param) { - if($this->getCausesValidation()) - $this->getPage()->validate($this->getValidationGroup()); + if($this->getActiveControl()->canCauseValidation()) + $this->getPage()->validate($this->getActiveControl()->getValidationGroup()); $this->onCallback($param); } @@ -168,31 +72,6 @@ class TCallback extends TControl implements ICallbackEventHandler { $this->raiseEvent('OnCallback', $this, $param); } - - /** - * @return array list of callback javascript options. - */ - protected function getCallbackClientSideOptions() - { - $validate = $this->getCausesValidation(); - $options['CausesValidation']= $validate ? '' : false; - $options['ValidationGroup']=$this->getValidationGroup(); - return $options; - } - - /** - * Returns the javascript statement to invoke a callback request for this - * control. Additional options for callback can be set via subproperties of - * {@link getClientSide ClientSide} property. E.g. ClientSide.OnSuccess="..." - * @param TControl callback handler control, use current object if null. - * @return string javascript statement to invoke a callback. - */ - public function getCallbackReference($control=null) - { - $client = $this->getPage()->getClientScript(); - $object = is_null($control) ? $this : $control; - return $client->getCallbackReference($object, $this->getCallbackClientSideOptions()); - } } ?> \ No newline at end of file diff --git a/framework/Web/UI/ActiveControls/TCallbackClientSideOptions.php b/framework/Web/UI/ActiveControls/TCallbackClientSideOptions.php index 3eadcd29..3f54e013 100644 --- a/framework/Web/UI/ActiveControls/TCallbackClientSideOptions.php +++ b/framework/Web/UI/ActiveControls/TCallbackClientSideOptions.php @@ -265,6 +265,30 @@ class TCallbackClientSideOptions extends TClientSideOptions $option = $this->getOption('EnablePageStateUpdate'); return is_null($option) ? true : $option; } + + public function getPostBackTarget() + { + return $this->getOption('EventTarget'); + } + + public function setPostBackTarget($value) + { + if($value instanceof TControl) + $value = $value->getUniqueID(); + $this->setOption('EventTarget', $value); + } + + public function getPostBackParameter() + { + return $this->getOption('EventParameter'); + } + + public function setPostBackParameter($value) + { + $this->setOption('EventParameter', $value); + } + + } ?> \ No newline at end of file diff --git a/framework/Web/UI/TClientScriptManager.php b/framework/Web/UI/TClientScriptManager.php index cad317ef..160ed055 100644 --- a/framework/Web/UI/TClientScriptManager.php +++ b/framework/Web/UI/TClientScriptManager.php @@ -168,7 +168,7 @@ class TClientScriptManager extends TApplicationComponent { $options = !is_array($options) ? array() : $options; $class = new TReflectionClass($callbackHandler); - $clientSide = $callbackHandler->getClientSide(); + $clientSide = $callbackHandler->getActiveControl()->getClientSide(); $options = array_merge($options, $clientSide->getOptions()->toArray()); $optionString = TJavascript::encode($options); $this->registerPradoScriptInternal('ajax'); diff --git a/framework/Web/UI/TControl.php b/framework/Web/UI/TControl.php index 7121e5ed..7ca37a00 100644 --- a/framework/Web/UI/TControl.php +++ b/framework/Web/UI/TControl.php @@ -1250,7 +1250,7 @@ class TControl extends TApplicationComponent implements IRenderable, IBindable } } - if($this->getEnabled() && $this instanceof IPostBackDataHandler) + if($this instanceof IPostBackDataHandler) $this->getPage()->registerPostDataLoader($this); } $this->_stage=self::CS_PRERENDERED; -- cgit v1.2.3