From 47d05516b1d1c465217c59732bf8442ab0cfd497 Mon Sep 17 00:00:00 2001 From: wei <> Date: Fri, 5 May 2006 06:58:04 +0000 Subject: Added prioritize callback and enabled viewstate update on callback return. --- framework/Exceptions/messages.txt | 4 +- framework/I18N/core/Gettext/MO.php | 2 +- framework/I18N/core/Gettext/PO.php | 2 +- framework/I18N/core/Gettext/TGettext.php | 2 +- framework/I18N/core/MessageSource_SQLite.php | 2 +- framework/I18N/core/TCache_Lite.php | 2 +- framework/IO/TTarFileExtractor.php | 2 +- framework/PradoBase.php | 2 +- framework/Web/Javascripts/js/ajax.js | 44 +++---- framework/Web/Javascripts/prado/ajax3.js | 130 ++++++++++++--------- .../UI/ActiveControls/TActiveControlAdapter.php | 2 +- framework/Web/UI/ActiveControls/TActiveLabel.php | 8 +- .../Web/UI/ActiveControls/TActivePageAdapter.php | 15 ++- framework/Web/UI/ActiveControls/TCallback.php | 2 +- .../UI/ActiveControls/TCallbackClientScript.php | 2 +- .../ActiveControls/TCallbackClientSideOptions.php | 114 ++++++++++-------- .../Web/UI/ActiveControls/TCallbackResponse.php | 15 +-- framework/Web/UI/TClientScriptManager.php | 89 ++++++++++++-- framework/Web/UI/TControl.php | 8 ++ framework/Web/UI/TPage.php | 34 +----- framework/Web/UI/TTemplateManager.php | 2 +- framework/Web/UI/WebControls/TBaseValidator.php | 73 ++++-------- framework/Web/UI/WebControls/TCheckBox.php | 2 +- .../Web/UI/WebControls/TValidationSummary.php | 63 +++------- framework/interfaces.php | 5 + .../pages/ActiveControls/ActiveControl.page | 16 ++- .../pages/ActiveControls/ActiveControl.php | 3 +- 27 files changed, 353 insertions(+), 292 deletions(-) diff --git a/framework/Exceptions/messages.txt b/framework/Exceptions/messages.txt index 3df84dde..5edd7c75 100644 --- a/framework/Exceptions/messages.txt +++ b/framework/Exceptions/messages.txt @@ -295,4 +295,6 @@ stack_data_not_iterable = TStack can only fetch data from an array or a trav stack_empty = TStack is empty. queue_data_not_iterable = TQueue can only fetch data from an array or a traversable object. -queue_empty = TQueue is empty. \ No newline at end of file +queue_empty = TQueue is empty. + +callback_not_support_no_priority_state_update = Callback request does not support unprioritized pagestate update. \ No newline at end of file diff --git a/framework/I18N/core/Gettext/MO.php b/framework/I18N/core/Gettext/MO.php index f3be1a30..5ee0057f 100644 --- a/framework/I18N/core/Gettext/MO.php +++ b/framework/I18N/core/Gettext/MO.php @@ -352,4 +352,4 @@ class TGettext_MO extends TGettext return true; } } -?> +?> \ No newline at end of file diff --git a/framework/I18N/core/Gettext/PO.php b/framework/I18N/core/Gettext/PO.php index 3c69c091..015747a0 100644 --- a/framework/I18N/core/Gettext/PO.php +++ b/framework/I18N/core/Gettext/PO.php @@ -157,4 +157,4 @@ class TGettext_PO extends TGettext return true; } } -?> +?> \ No newline at end of file diff --git a/framework/I18N/core/Gettext/TGettext.php b/framework/I18N/core/Gettext/TGettext.php index 8e87bee5..c13940b3 100644 --- a/framework/I18N/core/Gettext/TGettext.php +++ b/framework/I18N/core/Gettext/TGettext.php @@ -284,4 +284,4 @@ class TGettext return $PO; } } -?> +?> \ No newline at end of file diff --git a/framework/I18N/core/MessageSource_SQLite.php b/framework/I18N/core/MessageSource_SQLite.php index ac98df77..99065f7f 100644 --- a/framework/I18N/core/MessageSource_SQLite.php +++ b/framework/I18N/core/MessageSource_SQLite.php @@ -351,4 +351,4 @@ class MessageSource_SQLite extends MessageSource } } -?> +?> \ No newline at end of file diff --git a/framework/I18N/core/TCache_Lite.php b/framework/I18N/core/TCache_Lite.php index b42afc10..260e56c4 100644 --- a/framework/I18N/core/TCache_Lite.php +++ b/framework/I18N/core/TCache_Lite.php @@ -622,4 +622,4 @@ class TCache_Lite } -?> +?> \ No newline at end of file diff --git a/framework/IO/TTarFileExtractor.php b/framework/IO/TTarFileExtractor.php index 611662c5..9f61026d 100644 --- a/framework/IO/TTarFileExtractor.php +++ b/framework/IO/TTarFileExtractor.php @@ -569,4 +569,4 @@ class TTarFileExtractor return $p_path; } } -?> +?> \ No newline at end of file diff --git a/framework/PradoBase.php b/framework/PradoBase.php index 7e631cb8..9c6ef96b 100644 --- a/framework/PradoBase.php +++ b/framework/PradoBase.php @@ -645,4 +645,4 @@ else // PHP < 5.1.0 } } -?> +?> \ No newline at end of file diff --git a/framework/Web/Javascripts/js/ajax.js b/framework/Web/Javascripts/js/ajax.js index 6ab3d18d..5deebd1b 100644 --- a/framework/Web/Javascripts/js/ajax.js +++ b/framework/Web/Javascripts/js/ajax.js @@ -23,7 +23,7 @@ setTimeout(this.onComplete.bind(this),10);}}});Ajax.PeriodicalUpdater=Class.crea this.timer=setTimeout(this.onTimerEvent.bind(this),this.decay*this.frequency*1000);},onTimerEvent:function(){this.updater=new Ajax.Updater(this.container,this.url,this.options);}});Object.extend(Ajax.Request.prototype,{respondToReadyState:function(readyState) {var event=Ajax.Request.Events[readyState];var transport=this.transport,json=this.getHeaderData(Prado.CallbackRequest.DATA_HEADER);if(event=='Complete') {try -{Ajax.Responders.dispatch('on'+transport.status,this,transport,json);Prado.CallbackRequest.dispatchActions(transport,this.getHeaderData(Prado.CallbackRequest.ACTION_HEADER));(this.options['on'+this.transport.status]||this.options['on'+(this.responseIsSuccess()?'Success':'Failure')]||Prototype.emptyFunction)(transport,json);}catch(e){this.dispatchException(e);} +{Prado.CallbackRequest.updatePageState(this,transport);Ajax.Responders.dispatch('on'+transport.status,this,transport,json);Prado.CallbackRequest.dispatchActions(transport,this.getHeaderData(Prado.CallbackRequest.ACTION_HEADER));(this.options['on'+this.transport.status]||this.options['on'+(this.responseIsSuccess()?'Success':'Failure')]||Prototype.emptyFunction)(transport,json);}catch(e){this.dispatchException(e);} if((this.header('Content-type')||'').match(/^text\/javascript/i)) this.evalResponse();} try{(this.options['on'+event]||Prototype.emptyFunction)(transport,json);Ajax.Responders.dispatch('on'+event,this,transport,json);}catch(e){this.dispatchException(e);} @@ -34,7 +34,7 @@ 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',Queque:[],InProgress:[],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',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) @@ -54,27 +54,29 @@ msg+=e.version+" "+e.time+"\n";return msg;}},encode:function(data) {return Prado.JSON.stringify(data);},decode:function(data) {if(typeof(data)=="string"&&data.trim().length>0) return Prado.JSON.parse(data);else -return null;},dispatchQuequedRequest:function() -{requests=Prado.CallbackRequest;if(requests.InProgress.length==0&&requests.Queque.length>0) -{var item=requests.Queque.pop();item.callback=new Ajax.Request(item.url,item.options);item.callback.callbackID=item.id;item.timeout=setTimeout(function() -{requests.removeInProgress(item.callback);},item.options.TimeOut);requests.InProgress.push(item);}},removeInProgress:function(request) -{if(request&&request.callbackID) -{var stillInProgress=[];requests=Prado.CallbackRequest;requests.InProgress.each(function(item) -{if(item.callback.callbackID==request.callbackID) -{item.callback.transport.abort();request.transport.abort();clearTimeout(item.timeout);} -else -{stillInProgress.push(item);}}) -requests.InProgress=stillInProgress;} -requests.dispatchQuequedRequest();}}) -Ajax.Responders.register({onComplete:Prado.CallbackRequest.removeInProgress});Event.OnLoad(function() +return null;},dispatchPriorityRequest:function(callback) +{Logger.info("priority request "+callback.id) +this.abortRequestInProgress();callback.request=new Ajax.Request(callback.url,callback.options);callback.timeout=setTimeout(function() +{Logger.warn("priority timeout");Prado.CallbackRequest.abortRequestInProgress();},callback.options.RequestTimeOut);this.requestInProgress=callback;Logger.info("dispatched "+this.requestInProgress)},dispatchNormalRequest:function(callback) +{Logger.info("dispatching normal request");new Ajax.Request(callback.url,callback.options);},abortRequestInProgress:function() +{inProgress=Prado.CallbackRequest.requestInProgress;if(inProgress) +{Logger.warn("aborted "+inProgress.id) +inProgress.request.transport.abort();clearTimeout(inProgress.timeout);Prado.CallbackRequest.requestInProgress=null;}},updatePageState:function(request,transport) +{pagestate=$(this.FIELD_CALLBACK_PAGESTATE);if(request.options.EnablePageStateUpdate&&request.options.HasPriority&&pagestate) +{Logger.warn("updating page state");pagestate.value=request.header(this.PAGESTATE_HEADER);}}}) +Ajax.Responders.register({onComplete:function(request) +{if(request.options.HasPriority) +Prado.CallbackRequest.abortRequestInProgress();}});Event.OnLoad(function() {if(typeof Logger!="undefined") -Ajax.Responders.register(Prado.CallbackRequest.Exception);});Prado.CallbackRequest.prototype={url:window.location.href,options:{TimeOut:30000},id:null,callback:null,initialize:function(id,options) -{Object.extend(this.options,options||{});this.id=id;var request={postBody:this._getPostData(),parameters:''} -Object.extend(this.options,request);if(this.options.CausesValidation!=false&&typeof(Prado.Validation)!="undefined") +Ajax.Responders.register(Prado.CallbackRequest.Exception);});Prado.CallbackRequest.prototype={url:window.location.href,options:{},id:null,request:null,initialize:function(id,options) +{this.id=id;this.options={RequestTimeOut:30000,EnablePageStateUpdate:true,HasPriority:true,CausesValidation:true,ValidationGroup:null,PostInputs:true,postBody:this._getPostData(),parameters:''} +Object.extend(this.options,options||{});if(this.options.CausesValidation&&typeof(Prado.Validation)!="undefined") {var form=this.options.Form||Prado.Validation.getForm();if(Prado.Validation.validate(form,this.options.ValidationGroup,this)==false) return;} -Prado.CallbackRequest.Queque.push(this);Prado.CallbackRequest.dispatchQuequedRequest();},_getPostData:function() -{var data={};var callback=Prado.CallbackRequest;if(this.options.PostState!=false) +if(this.options.HasPriority) +Prado.CallbackRequest.dispatchPriorityRequest(this);else +Prado.CallbackRequest.dispatchNormalRequest(this);},_getPostData:function() +{var data={};var callback=Prado.CallbackRequest;if(this.options.PostInputs!=false) {callback.PostDataLoaders.each(function(name) {$A(document.getElementsByName(name)).each(function(element) {var value=$F(element);if(typeof(value)!="undefined") @@ -83,7 +85,7 @@ 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();}} Prado.Callback=function(UniqueID,parameter,onSuccess,options) -{var callback={'params':parameter||'','onSuccess':onSuccess||Prototype.emptyFunction,'CausesValidation':true};Object.extend(callback,options||{});new Prado.CallbackRequest(UniqueID,callback);return false;} +{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 0) + Logger.info("priority request "+callback.id) + this.abortRequestInProgress(); + + callback.request = new Ajax.Request(callback.url, callback.options); + callback.timeout = setTimeout(function() { - var item = requests.Queque.pop(); - item.callback = new Ajax.Request(item.url, item.options); - item.callback.callbackID = item.id; - item.timeout = setTimeout(function() - { - requests.removeInProgress(item.callback); - }, item.options.TimeOut); - requests.InProgress.push(item); + Logger.warn("priority timeout"); + Prado.CallbackRequest.abortRequestInProgress(); + },callback.options.RequestTimeOut); + + this.requestInProgress = callback; + Logger.info("dispatched "+this.requestInProgress) + }, + + /** + * Dispatch a normal request, no timeouts or aborting of requests. + */ + dispatchNormalRequest : function(callback) + { + Logger.info("dispatching normal request"); + new Ajax.Request(callback.url, callback.options); + }, + + /** + * Abort the current priority request in progress. + */ + abortRequestInProgress : function() + { + inProgress = Prado.CallbackRequest.requestInProgress; + if(inProgress) + { + Logger.warn("aborted "+inProgress.id) + inProgress.request.transport.abort(); + clearTimeout(inProgress.timeout); + Prado.CallbackRequest.requestInProgress = null; } }, /** - * Remove a request currently in progress and call dispatchQuequedRequest. + * Updates the page state. It will update only if EnablePageStateUpdate and + * HasPriority options are both true. */ - removeInProgress : function(request) + updatePageState : function(request, transport) { - if(request && request.callbackID) + pagestate = $(this.FIELD_CALLBACK_PAGESTATE); + if(request.options.EnablePageStateUpdate && request.options.HasPriority && pagestate) { - var stillInProgress = []; - requests = Prado.CallbackRequest; - requests.InProgress.each(function(item) - { - if(item.callback.callbackID == request.callbackID) - { - item.callback.transport.abort(); - request.transport.abort(); - clearTimeout(item.timeout); - } - else - { - stillInProgress.push(item); - } - }) - requests.InProgress = stillInProgress; + Logger.warn("updating page state"); + pagestate.value = request.header(this.PAGESTATE_HEADER); } - requests.dispatchQuequedRequest(); } }) -Ajax.Responders.register({onComplete : Prado.CallbackRequest.removeInProgress}); +/** + * Automatically aborts the current request when a priority request has returned. + */ +Ajax.Responders.register({onComplete : function(request) +{ + if(request.options.HasPriority) + Prado.CallbackRequest.abortRequestInProgress(); +}}); //Add HTTP exception respones when logger is enabled. Event.OnLoad(function() @@ -291,10 +310,7 @@ Prado.CallbackRequest.prototype = /** * Callback options, including onXXX events. */ - options : - { - TimeOut : 30000 // 30 second timeout. - }, + options : { }, /** * Callback target ID. E.g. $control->getUniqueID(); @@ -304,34 +320,39 @@ Prado.CallbackRequest.prototype = /** * Current callback request. */ - callback : null, + request : null, /** * Prepare and inititate a callback request. */ initialize : function(id, options) { - Object.extend(this.options, options || {}); - this.id = id; - - var request = + + this.options = { + RequestTimeOut : 30000, // 30 second timeout. + EnablePageStateUpdate : true, + HasPriority : true, + CausesValidation : true, + ValidationGroup : null, + PostInputs : true, postBody : this._getPostData(), parameters : '' } - - Object.extend(this.options, request); - - if(this.options.CausesValidation != false && typeof(Prado.Validation) != "undefined") + Object.extend(this.options, options || {}); + + if(this.options.CausesValidation && typeof(Prado.Validation) != "undefined") { var form = this.options.Form || Prado.Validation.getForm(); if(Prado.Validation.validate(form,this.options.ValidationGroup,this) == false) return; } - Prado.CallbackRequest.Queque.push(this); - Prado.CallbackRequest.dispatchQuequedRequest(); + if(this.options.HasPriority) + Prado.CallbackRequest.dispatchPriorityRequest(this); + else + Prado.CallbackRequest.dispatchNormalRequest(this); }, /** @@ -343,7 +364,7 @@ Prado.CallbackRequest.prototype = { var data = {}; var callback = Prado.CallbackRequest; - if(this.options.PostState != false) + if(this.options.PostInputs != false) { callback.PostDataLoaders.each(function(name) { @@ -378,8 +399,7 @@ Prado.Callback = function(UniqueID, parameter, onSuccess, options) var callback = { 'params' : parameter || '', - 'onSuccess' : onSuccess || Prototype.emptyFunction, - 'CausesValidation' : true + 'onSuccess' : onSuccess || Prototype.emptyFunction }; Object.extend(callback, options || {}); diff --git a/framework/Web/UI/ActiveControls/TActiveControlAdapter.php b/framework/Web/UI/ActiveControls/TActiveControlAdapter.php index b95bdd37..77973b2c 100644 --- a/framework/Web/UI/ActiveControls/TActiveControlAdapter.php +++ b/framework/Web/UI/ActiveControls/TActiveControlAdapter.php @@ -22,4 +22,4 @@ class TActiveControlAdapter extends TControlAdapter parent::render($writer); } } -?> +?> \ No newline at end of file diff --git a/framework/Web/UI/ActiveControls/TActiveLabel.php b/framework/Web/UI/ActiveControls/TActiveLabel.php index d71d8b7a..3216be43 100644 --- a/framework/Web/UI/ActiveControls/TActiveLabel.php +++ b/framework/Web/UI/ActiveControls/TActiveLabel.php @@ -29,7 +29,7 @@ class TActiveLabel extends TLabel /** * Creates a new callback control, sets the adapter to * TActiveControlAdapter. If you override this class, be sure to set the - * adapter appropriately by, for example, call this constructor. + * adapter appropriately by, for example, by calling this constructor. */ public function __construct() { @@ -44,7 +44,7 @@ class TActiveLabel extends TLabel public function setText($value) { parent::setText($value); - if($this->getPage()->getAllowCallbackUpdate()) + if($this->getIsInitialized()) { $this->getPage()->getCallbackClient()->update($this, $value); } @@ -59,7 +59,7 @@ class TActiveLabel extends TLabel public function setForControl($value) { parent::setForControl($value); - if($this->getPage()->getAllowCallbackUpdate()) + if($this->getIsInitialized()) { $id=$this->findControl($value)->getClientID(); $this->getPage()->getCallbackClient()->setAttribute($this, 'for', $id); @@ -67,4 +67,4 @@ class TActiveLabel extends TLabel } } -?> +?> \ No newline at end of file diff --git a/framework/Web/UI/ActiveControls/TActivePageAdapter.php b/framework/Web/UI/ActiveControls/TActivePageAdapter.php index db783a12..67720afd 100644 --- a/framework/Web/UI/ActiveControls/TActivePageAdapter.php +++ b/framework/Web/UI/ActiveControls/TActivePageAdapter.php @@ -25,6 +25,7 @@ class TActivePageAdapter extends TControlAdapter const CALLBACK_DATA_HEADER = 'X-PRADO-DATA'; const CALLBACK_ACTION_HEADER = 'X-PRADO-ACTIONS'; const CALLBACK_ERROR_HEADER = 'X-PRADO-ERROR'; + const CALLBACK_PAGESTATE_HEADER = 'X-PRADO-PAGESTATE'; /** * @var ICallbackEventHandler callback event handler. @@ -80,7 +81,7 @@ class TActivePageAdapter extends TControlAdapter /** * Renders the callback response by adding additional callback data and - * javascript actions in the header. + * javascript actions in the header and page state if required. */ protected function renderResponse($writer) { @@ -92,7 +93,15 @@ class TActivePageAdapter extends TControlAdapter { $data = TJavascript::jsonEncode($this->_result->getData()); $response->appendHeader(self::CALLBACK_DATA_HEADER.': '.$data); - } + } + if(($handler = $this->getCallbackEventTarget()) !== null) + { + if($handler->getClientSide()->getEnablePageStateUpdate()) + { + $pagestate = $this->getPage()->getClientState(); + $response->appendHeader(self::CALLBACK_PAGESTATE_HEADER.': '.$pagestate); + } + } } /** @@ -329,4 +338,4 @@ class TInvalidCallbackRequestException extends TException { } -?> +?> \ No newline at end of file diff --git a/framework/Web/UI/ActiveControls/TCallback.php b/framework/Web/UI/ActiveControls/TCallback.php index 9c3234fd..9d2301d8 100644 --- a/framework/Web/UI/ActiveControls/TCallback.php +++ b/framework/Web/UI/ActiveControls/TCallback.php @@ -147,4 +147,4 @@ class TCallback extends TControl implements ICallbackEventHandler } } -?> +?> \ No newline at end of file diff --git a/framework/Web/UI/ActiveControls/TCallbackClientScript.php b/framework/Web/UI/ActiveControls/TCallbackClientScript.php index 5f8851db..5d317c8a 100644 --- a/framework/Web/UI/ActiveControls/TCallbackClientScript.php +++ b/framework/Web/UI/ActiveControls/TCallbackClientScript.php @@ -531,4 +531,4 @@ class TCallbackClientScript extends TApplicationComponent } } -?> +?> \ No newline at end of file diff --git a/framework/Web/UI/ActiveControls/TCallbackClientSideOptions.php b/framework/Web/UI/ActiveControls/TCallbackClientSideOptions.php index 6a4731f7..c0a817f0 100644 --- a/framework/Web/UI/ActiveControls/TCallbackClientSideOptions.php +++ b/framework/Web/UI/ActiveControls/TCallbackClientSideOptions.php @@ -1,37 +1,4 @@ _options = Prado::createComponent('System.Collections.TMap'); - } - - protected function setFunction($name, $code) - { - $this->_options->add($name, $this->ensureFunction($code)); - } - - protected function getOption($name) - { - return $this->_options->itemAt($name); - } - - public function getOptions() - { - return $this->_options; - } - - protected function ensureFunction($javascript) - { - return $javascript; - } -} /** * TCallbackClientSideOptions class. @@ -54,6 +21,15 @@ class TClientSideOptions extends TComponent * - onException raised when callback request fails due to * request/response errors. * + * - PostInputs true to collect the form inputs and post them during + * callback, default is true. + * - RequestTimeOut The request timeout in milliseconds. + * - HasPriority true to ensure that the callback request will be sent + * immediately and will abort existing prioritized requests. It does not affect + * callbacks that are not prioritized. + * - EnablePageStateUpdate enable the callback response to enable the + * viewstate update. This will automatically set HasPrority to true when + * enabled. */ class TCallbackClientSideOptions extends TClientSideOptions { @@ -65,13 +41,7 @@ class TCallbackClientSideOptions extends TClientSideOptions */ protected function ensureFunction($javascript) { - if(TJavascript::isFunction($javascript)) - return $javascript; - else - { - $code = "function(request, result){ {$javascript} }"; - return TJavascript::quoteFunction($code); - } + return "function(request, result){ {$javascript} }"; } /** @@ -200,21 +170,21 @@ class TCallbackClientSideOptions extends TClientSideOptions } /** - * @return boolean true to post the state on callback, default is post the - * state on callback. + * @return boolean true to post the inputs of the form on callback, default + * is post the inputs on callback. */ public function getPostState() { - return $this->getOption('PostState'); + return $this->getOption('PostInputs'); } /** - * @param boolean true to post the state of the form with callback requests. - * Default is to post the state. + * @param boolean true to post the inputs of the form with callback + * requests. Default is to post the inputs. */ public function setPostState($value) { - $this->getOptions()->add('PostState', TPropertyValue::ensureBoolean($value)); + $this->setOption('PostInputs', TPropertyValue::ensureBoolean($value)); } /** @@ -222,7 +192,7 @@ class TCallbackClientSideOptions extends TClientSideOptions */ public function getRequestTimeOut() { - return $this->getOption('TimeOut'); + return $this->getOption('RequestTimeOut'); } /** @@ -230,8 +200,54 @@ class TCallbackClientSideOptions extends TClientSideOptions */ public function setRequestTimeOut($value) { - $this->getOptions()->add('TimeOut', TPropertyValue::ensureInteger($value)); + $this->setOption('RequestTimeOut', TPropertyValue::ensureInteger($value)); + } + + /** + * @return boolean true if the callback request has priority and will abort + * existing prioritized request in order to send immediately. It does not + * affect callbacks that are not prioritized. + */ + public function getHasPriority() + { + return $this->getOption('HasPriority'); + } + + /** + * @param boolean true to ensure that the callback request will be sent + * immediately and will abort existing prioritized requests. It does not + * affect callbacks that are not prioritized. + */ + public function setHasPriority($value) + { + $hasPriority = TPropertyValue::ensureBoolean($value); + $this->setOption('HasPriority', $hasPriority); + if(!$hasPriority) + $this->setEnablePageStateUpdate(false); + } + + /** + * Set to true to enable the callback response to enable the viewstate + * update. This will automatically set HasPrority to true. + * @param boolean true enables the callback response to update the + * viewstate. + */ + public function setEnablePageStateUpdate($value) + { + $enabled = TPropertyValue::ensureBoolean($value); + $this->setOption('EnablePageStateUpdate', $enabled); + if($enabled) + $this->setHasPriority(true); + } + + /** + * @return boolean client-side viewstate will be updated on callback + * response if true. + */ + public function getEnablePageStateUpdate() + { + return $this->getOption('EnablePageStateUpdate'); } } -?> +?> \ No newline at end of file diff --git a/framework/Web/UI/ActiveControls/TCallbackResponse.php b/framework/Web/UI/ActiveControls/TCallbackResponse.php index 4a893b9a..024ad6ef 100644 --- a/framework/Web/UI/ActiveControls/TCallbackResponse.php +++ b/framework/Web/UI/ActiveControls/TCallbackResponse.php @@ -1,14 +1,8 @@ + +?> \ No newline at end of file diff --git a/framework/Web/UI/TClientScriptManager.php b/framework/Web/UI/TClientScriptManager.php index 46203b0b..20612ce2 100644 --- a/framework/Web/UI/TClientScriptManager.php +++ b/framework/Web/UI/TClientScriptManager.php @@ -1,6 +1,6 @@ * @link http://www.pradosoft.com/ @@ -164,15 +164,12 @@ class TClientScriptManager extends TApplicationComponent } } - public function getCallbackReference($callbackHandler, $options=null) + public function getCallbackReference(ICallbackEventHandler $callbackHandler, $options=null) { $options = !is_array($options) ? array() : $options; $class = new TReflectionClass($callbackHandler); - if($class->hasMethod('getClientSide')) - { - $clientSide = $callbackHandler->getClientSide(); - $options = array_merge($options, $clientSide->getOptions()->toArray()); - } + $clientSide = $callbackHandler->getClientSide(); + $options = array_merge($options, $clientSide->getOptions()->toArray()); $optionString = TJavascript::encode($options); $this->registerPradoScriptInternal('ajax'); $id = $callbackHandler->getUniqueID(); @@ -532,4 +529,82 @@ class TClientScriptManager extends TApplicationComponent } } +/** + * TClientSideOptions abstract class. + * + * TClientSideOptions manages client-side options for components that have + * common client-side javascript behaviours and client-side events such as + * between ActiveControls and validators. + * + * @author + * @version $Revision: $ $Date: $ + * @package System.Web.UI + * @since 3.0 + */ +abstract class TClientSideOptions extends TComponent +{ + /** + * @var TMap list of client-side options. + */ + private $_options; + + /** + * Constructor, initialize the options list. + */ + public function __construct() + { + $this->_options = Prado::createComponent('System.Collections.TMap'); + } + + /** + * Adds on client-side event handler by wrapping the code within a + * javascript function block. If the code begins with "javascript:", the + * code is assumed to be a javascript function block rather than arbiturary + * javascript statements. + * @param string option name + * @param string javascript statements. + */ + protected function setFunction($name, $code) + { + if(!TJavascript::isFunction($code)) + $code = TJavascript::quoteFunction($this->ensureFunction($code)); + $this->setOption($name, $code); + } + + /** + * @return string gets a particular option, null if not set. + */ + protected function getOption($name) + { + return $this->_options->itemAt($name); + } + + /** + * @param string option name + * @param mixed option value. + */ + protected function setOption($name, $value) + { + $this->_options->add($name, $value); + } + + /** + * @return TMap gets the list of options as TMap + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Ensure that the javascript statements are wrapped in a javascript + * function block. Default has no wrapping. Override this method to + * customize the wrapping javascript function block. + */ + protected function ensureFunction($javascript) + { + return $javascript; + } +} + ?> \ No newline at end of file diff --git a/framework/Web/UI/TControl.php b/framework/Web/UI/TControl.php index 860b6baf..3bb893e2 100644 --- a/framework/Web/UI/TControl.php +++ b/framework/Web/UI/TControl.php @@ -997,6 +997,14 @@ class TControl extends TApplicationComponent implements IRenderable, IBindable { return isset($this->_rf[self::RF_NAMED_OBJECTS][$name]); } + + /** + * @return boolean true if the control has been initialized. + */ + public function getIsInitialized() + { + return $this->getControlStage() >= self::CS_CHILD_INITIALIZED; + } /** * Returns the named registered object. diff --git a/framework/Web/UI/TPage.php b/framework/Web/UI/TPage.php index 11ebc1dd..008b7c83 100644 --- a/framework/Web/UI/TPage.php +++ b/framework/Web/UI/TPage.php @@ -153,12 +153,7 @@ class TPage extends TTemplateControl * @var array post data loader IDs. */ private $_postDataLoaders=array(); - /** - * @var boolean true if callback request is allowed to update the client- - * side contents during callback response. - */ - private $_allowCallbackUpdate=false; - + /** * Constructor. * Sets the page object to itself. @@ -282,8 +277,6 @@ class TPage extends TTemplateControl Prado::trace("Page initRecursive()",'System.Web.UI.TPage'); $this->initRecursive(); - $this->setAllowCallbackUpdate(true); - Prado::trace("Page onInitComplete()",'System.Web.UI.TPage'); $this->onInitComplete(null); @@ -316,11 +309,12 @@ class TPage extends TTemplateControl Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage'); $this->onPreRenderComplete(null); -/* Prado::trace("Page savePageState()",'System.Web.UI.TPage'); + Prado::trace("Page savePageState()",'System.Web.UI.TPage'); $this->savePageState(); Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage'); $this->onSaveStateComplete(null); +/* Prado::trace("Page renderControl()",'System.Web.UI.TPage'); $this->renderControl($writer); */ @@ -330,28 +324,6 @@ class TPage extends TTemplateControl $this->unloadRecursive(); } - /** - * Returns true if callback request is allowed to update the client- side - * contents during callback response. Default is true if {@link - * getIsCallback IsCallback} is true and onInit stage has been completed. - * @return boolean true to allow client-side update. - */ - public function getAllowCallbackUpdate() - { - return $this->_allowCallbackUpdate; - } - - /** - * Set to true to allow callback request to update client-side content - * during callback response. Default is true if {@link getIsCallback - * IsCallback} is true and onInit stage has been completed. - * @param boolean true to allow callback to update client-side content. - */ - public function setAllowCallbackUpdate($value) - { - $this->_allowCallbackUpdate = TPropertyValue::ensureBoolean($value); - } - /** * Gets the callback client script handler that allows javascript functions * to be executed during the callback response. diff --git a/framework/Web/UI/TTemplateManager.php b/framework/Web/UI/TTemplateManager.php index 36562b1b..27bd0ac6 100644 --- a/framework/Web/UI/TTemplateManager.php +++ b/framework/Web/UI/TTemplateManager.php @@ -883,4 +883,4 @@ class TTemplate extends TApplicationComponent implements ITemplate } } -?> +?> \ No newline at end of file diff --git a/framework/Web/UI/WebControls/TBaseValidator.php b/framework/Web/UI/WebControls/TBaseValidator.php index ea1a5836..c39db85a 100644 --- a/framework/Web/UI/WebControls/TBaseValidator.php +++ b/framework/Web/UI/WebControls/TBaseValidator.php @@ -80,9 +80,9 @@ abstract class TBaseValidator extends TLabel implements IValidator */ private $_registered=false; /** - * @var TValidatorClientScript validator client-script options. + * @var TClientSideValidatorOptions validator client-script options. */ - private $_clientScript; + private $_clientSide; /** * Constructor. @@ -154,14 +154,14 @@ abstract class TBaseValidator extends TLabel implements IValidator $options['ControlCssClass'] = $this->getControlCssClass(); $options['ControlType'] = get_class($control); - if(!is_null($this->_clientScript)) - $options = array_merge($options,$this->_clientScript->getOptions()); + if(!is_null($this->_clientSide)) + $options = array_merge($options,$this->_clientSide->getOptions()->toArray()); return $options; } /** - * Gets the TValidatorClientScript that allows modification of the client- + * Gets the TClientSideValidatorOptions that allows modification of the client- * side validator events. * * The client-side validator supports the following events. @@ -174,21 +174,21 @@ abstract class TBaseValidator extends TLabel implements IValidator * * You can attach custom javascript code to each of these events * - * @return TValidatorClientScript javascript validator event options. + * @return TClientSideValidatorOptions javascript validator event options. */ public function getClientSide() { - if(is_null($this->_clientScript)) - $this->_clientScript = $this->createClientScript(); - return $this->_clientScript; + if(is_null($this->_clientSide)) + $this->_clientSide = $this->createClientSideOptions(); + return $this->_clientSide; } /** - * @return TValidatorClientScript javascript validator event options. + * @return TClientSideValidatorOptions javascript validator event options. */ - protected function createClientScript() + protected function createClientSideOptions() { - return new TValidatorClientScript; + return new TClientSideValidatorOptions; } /** @@ -491,11 +491,11 @@ abstract class TBaseValidator extends TLabel implements IValidator } /** - * TValidatorClientScript class. + * TClientSideValidatorOptions class. * * Client-side validator events can be modified through the {@link * TBaseValidator::getClientSide ClientSide} property of a validator. The - * subproperties of ClientSide are those of the TValidatorClientScript + * subproperties of ClientSide are those of the TClientSideValidatorOptions * properties. The client-side validator supports the following events. * * The OnValidate event is raise before the validator validation @@ -513,27 +513,14 @@ abstract class TBaseValidator extends TLabel implements IValidator * @package System.Web.UI.WebControls * @since 3.0 */ -class TValidatorClientScript extends TComponent +class TClientSideValidatorOptions extends TClientSideOptions { - /** - * @var TMap client-side validator event javascript code. - */ - private $_options; - - /** - * Constructor. - */ - public function __construct() - { - $this->_options = new TMap; - } - /** * @return string javascript code for client-side OnValidate event. */ public function getOnValidate() { - return $this->_options->itemAt['OnValidate']; + return $this->getOption('OnValidate'); } /** @@ -543,7 +530,7 @@ class TValidatorClientScript extends TComponent */ public function setOnValidate($javascript) { - $this->_options->add('OnValidate', $this->ensureFunction($javascript)); + $this->setFunction('OnValidate', $javascript); } /** @@ -553,7 +540,7 @@ class TValidatorClientScript extends TComponent */ public function setOnSuccess($javascript) { - $this->_options->add('OnSuccess', $this->ensureFunction($javascript)); + $this->setFunction('OnSuccess', $javascript); } /** @@ -561,7 +548,7 @@ class TValidatorClientScript extends TComponent */ public function getOnSuccess() { - return $this->_options->itemAt('OnSuccess'); + return $this->getOption('OnSuccess'); } /** @@ -571,7 +558,7 @@ class TValidatorClientScript extends TComponent */ public function setOnError($javascript) { - $this->_options->add('OnError', $this->ensureFunction($javascript)); + $this->setFunction('OnError', $javascript); } /** @@ -579,15 +566,7 @@ class TValidatorClientScript extends TComponent */ public function getOnError() { - return $this->_options->itemAt('OnError'); - } - - /** - * @return array list of client-side event code. - */ - public function getOptions() - { - return $this->_options->toArray(); + return $this->getOption('OnError'); } /** @@ -597,15 +576,9 @@ class TValidatorClientScript extends TComponent * @param string javascript code. * @return string javascript function code. */ - private function ensureFunction($javascript) + protected function ensureFunction($javascript) { - if(TJavascript::isFunction($javascript)) - return $javascript; - else - { - $code = "function(validator, sender){ {$javascript} }"; - return TJavascript::quoteFunction($code); - } + return "function(validator, sender){ {$javascript} }"; } } diff --git a/framework/Web/UI/WebControls/TCheckBox.php b/framework/Web/UI/WebControls/TCheckBox.php index 681c8748..da389948 100644 --- a/framework/Web/UI/WebControls/TCheckBox.php +++ b/framework/Web/UI/WebControls/TCheckBox.php @@ -378,4 +378,4 @@ class TCheckBox extends TWebControl implements IPostBackDataHandler, IValidatabl } -?> +?> \ No newline at end of file diff --git a/framework/Web/UI/WebControls/TValidationSummary.php b/framework/Web/UI/WebControls/TValidationSummary.php index 87821292..8148036b 100644 --- a/framework/Web/UI/WebControls/TValidationSummary.php +++ b/framework/Web/UI/WebControls/TValidationSummary.php @@ -37,9 +37,9 @@ class TValidationSummary extends TWebControl { /** - * @var TValidatorClientScript validator client-script options. + * @var TClientSideValidationSummaryOptions validation client side options. */ - private $_clientScript; + private $_clientSide; /** * Constructor. @@ -248,30 +248,30 @@ class TValidationSummary extends TWebControl $options['ValidationGroup'] = $this->getValidationGroup(); $options['Display'] = $this->getDisplay(); - if(!is_null($this->_clientScript)) - $options = array_merge($options,$this->_clientScript->getOptions()); + if(!is_null($this->_clientSide)) + $options = array_merge($options,$this->_clientSide->getOptions()->toArray()); return $options; } /** - * @return TValidationSummaryClientScript client-side validation summary + * @return TClientSideValidationSummaryOptions client-side validation summary * event options. */ public function getClientSide() { - if(is_null($this->_clientScript)) - $this->_clientScript = $this->createClientScript(); - return $this->_clientScript; + if(is_null($this->_clientSide)) + $this->_clientSide = $this->createClientScript(); + return $this->_clientSide; } /** - * @return TValidationSummaryClientScript javascript validation summary + * @return TClientSideValidationSummaryOptions javascript validation summary * event options. */ protected function createClientScript() { - return new TValidationSummaryClientScript; + return new TClientSideValidationSummaryOptions; } /** * Get the list of validation error messages. @@ -372,7 +372,7 @@ class TValidationSummary extends TWebControl } /** - * TValidationSummaryClientScript class. + * TClientSideValidationSummaryOptions class. * * Client-side validation summary events such as {@link setOnHideSummary * OnHideSummary} and {@link setOnShowSummary OnShowSummary} can be modified @@ -392,27 +392,14 @@ class TValidationSummary extends TWebControl * @package System.Web.UI.WebControls * @since 3.0 */ -class TValidationSummaryClientScript extends TComponent +class TClientSideValidationSummaryOptions extends TClientSideOptions { - /** - * @var TMap client-side validation summary event javascript code. - */ - private $_options; - - /** - * Constructor. - */ - public function __construct() - { - $this->_options = new TMap; - } - /** * @return string javascript code for client-side OnHideSummary event. */ public function getOnHideSummary() { - return $this->_options->itemAt['OnHideSummary']; + return $this->getOption('OnHideSummary'); } /** @@ -423,7 +410,7 @@ class TValidationSummaryClientScript extends TComponent */ public function setOnHideSummary($javascript) { - $this->_options->add('OnHideSummary', $this->ensureFunction($javascript)); + $this->setFunction('OnHideSummary', $javascript); } /** @@ -434,7 +421,7 @@ class TValidationSummaryClientScript extends TComponent */ public function setOnShowSummary($javascript) { - $this->_options->add('OnShowSummary', $this->ensureFunction($javascript)); + $this->setFunction('OnShowSummary', $javascript); } /** @@ -442,15 +429,7 @@ class TValidationSummaryClientScript extends TComponent */ public function getOnShowSummary() { - return $this->_options->itemAt('OnShowSummary'); - } - - /** - * @return array list of client-side event code. - */ - public function getOptions() - { - return $this->_options->toArray(); + return $this->getOption('OnShowSummary'); } /** @@ -460,15 +439,9 @@ class TValidationSummaryClientScript extends TComponent * @param string javascript code. * @return string javascript function code. */ - private function ensureFunction($javascript) + protected function ensureFunction($javascript) { - if(TJavascript::isFunction($javascript)) - return $javascript; - else - { - $code = "function(summary, validators){ {$javascript} }"; - return TJavascript::quoteFunction($code); - } + return "function(summary, validators){ {$javascript} }"; } } diff --git a/framework/interfaces.php b/framework/interfaces.php index eb9084b3..fc830140 100644 --- a/framework/interfaces.php +++ b/framework/interfaces.php @@ -315,6 +315,11 @@ interface ICallbackEventHandler * @param TCallbackEventParameter the parameter associated with the callback event */ public function raiseCallbackEvent($eventArgument); + + /** + * @return TCallbackClientSideOptions client-side options. + */ + public function getClientSide(); } ?> \ No newline at end of file diff --git a/tests/FunctionalTests/features/protected/pages/ActiveControls/ActiveControl.page b/tests/FunctionalTests/features/protected/pages/ActiveControls/ActiveControl.page index 2d43bb82..b33e9000 100644 --- a/tests/FunctionalTests/features/protected/pages/ActiveControls/ActiveControl.page +++ b/tests/FunctionalTests/features/protected/pages/ActiveControls/ActiveControl.page @@ -2,6 +2,11 @@

TCallback Demo

+ + @@ -12,9 +17,8 @@ - - - + + \ No newline at end of file diff --git a/tests/FunctionalTests/features/protected/pages/ActiveControls/ActiveControl.php b/tests/FunctionalTests/features/protected/pages/ActiveControls/ActiveControl.php index 8323667a..e9a6226a 100644 --- a/tests/FunctionalTests/features/protected/pages/ActiveControls/ActiveControl.php +++ b/tests/FunctionalTests/features/protected/pages/ActiveControls/ActiveControl.php @@ -7,7 +7,8 @@ class ActiveControl extends TPage { public function control1onCallback($sender, $param) { - $this->label1->setText("The time is ".time()); + sleep(5); + $this->label1->setText("The time is ".time()." from ".$sender->ID); } } ?> -- cgit v1.2.3