summaryrefslogtreecommitdiff
path: root/framework
diff options
context:
space:
mode:
Diffstat (limited to 'framework')
-rw-r--r--framework/Web/Javascripts/js/ajax.js29
-rw-r--r--framework/Web/Javascripts/js/prado.js2
-rw-r--r--framework/Web/Javascripts/prado/ajax3.js84
-rw-r--r--framework/Web/Javascripts/prado/element.js2
-rw-r--r--framework/Web/UI/ActiveControls/TActiveLabel.php70
-rw-r--r--framework/Web/UI/ActiveControls/TActivePageAdapter.php2
-rw-r--r--framework/Web/UI/ActiveControls/TCallback.php19
-rw-r--r--framework/Web/UI/ActiveControls/TCallbackClientScript.php14
-rw-r--r--framework/Web/UI/ActiveControls/TCallbackClientSideOptions.php16
-rw-r--r--framework/Web/UI/TPage.php33
10 files changed, 223 insertions, 48 deletions
diff --git a/framework/Web/Javascripts/js/ajax.js b/framework/Web/Javascripts/js/ajax.js
index 375d90e9..6ab3d18d 100644
--- a/framework/Web/Javascripts/js/ajax.js
+++ b/framework/Web/Javascripts/js/ajax.js
@@ -34,14 +34,14 @@ 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',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',Queque:[],InProgress:[],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")
-{Logger.error("Error in executing callback response:","Unable to find HTML element with ID '"+id+"' before executing "+method+"().");}}}},Exception:{"on505":function(request,transport,data)
+{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)
{var msg='HTTP '+transport.status+" with response : \n";msg+=transport.responseText+"\n";msg+="Data : \n"+inspect(data)+"\n";msg+="Actions : \n";request.getHeaderData(Prado.CallbackRequest.ACTION_HEADER).each(function(action)
@@ -52,15 +52,28 @@ Logger.warn(msg);}},onException:function(e)
{msg+=" #"+i+" "+trace[i].file;msg+="("+trace[i].line+"): ";msg+=trace[i]["class"]+"->"+trace[i]["function"]+"()"+"\n";}
msg+=e.version+" "+e.time+"\n";return msg;}},encode:function(data)
{return Prado.JSON.stringify(data);},decode:function(data)
-{return Prado.JSON.parse(data);}})
-Event.OnLoad(function()
+{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()
{if(typeof Logger!="undefined")
-Ajax.Responders.register(Prado.CallbackRequest.Exception);});Prado.CallbackRequest.prototype={url:window.location.href,options:{},id:null,request:null,initialize:function(id,options)
-{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:{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")
{var form=this.options.Form||Prado.Validation.getForm();if(Prado.Validation.validate(form,this.options.ValidationGroup,this)==false)
return;}
-this.request=new Ajax.Request(this.url,this.options);},_getPostData:function()
+Prado.CallbackRequest.Queque.push(this);Prado.CallbackRequest.dispatchQuequedRequest();},_getPostData:function()
{var data={};var callback=Prado.CallbackRequest;if(this.options.PostState!=false)
{callback.PostDataLoaders.each(function(name)
{$A(document.getElementsByName(name)).each(function(element)
diff --git a/framework/Web/Javascripts/js/prado.js b/framework/Web/Javascripts/js/prado.js
index f6c52983..f545ee74 100644
--- a/framework/Web/Javascripts/js/prado.js
+++ b/framework/Web/Javascripts/js/prado.js
@@ -266,7 +266,7 @@ el.setAttribute(attribute,value);},setOptions:function(element,options)
el.remove(0);for(var i=0;i<options.length;i++)
el.options[el.options.length]=new Option(options[i][0],options[i][1]);}},focus:function(element)
{var obj=$(element);if(typeof(obj)!="undefined"&&typeof(obj.focus)!="undefined")
-setTimeout(function(){obj.focus();},100);return false;},replaceContent:function(element,method,content,boundary,transport)
+setTimeout(function(){obj.focus();},100);return false;},replace:function(element,method,content,boundary,transport)
{if(boundary)
{var f=RegExp('(<!--'+boundary+'-->)([\\s\\S\\w\\W]*)(<!--//'+boundary+'-->)',"m");var result=transport.responseText.match(f);if(result&&result.length>=2)
content=result[2];}
diff --git a/framework/Web/Javascripts/prado/ajax3.js b/framework/Web/Javascripts/prado/ajax3.js
index 63add490..8ea76e10 100644
--- a/framework/Web/Javascripts/prado/ajax3.js
+++ b/framework/Web/Javascripts/prado/ajax3.js
@@ -103,6 +103,14 @@ Object.extend(Prado.CallbackRequest,
* Response errors/exceptions header name.
*/
ERROR_HEADER : 'X-PRADO-ERROR',
+ /**
+ * Callback request queque.
+ */
+ Queque : [],
+ /**
+ * Requests In progress.
+ */
+ InProgress : [],
/**
* Dispatch callback response actions.
@@ -140,9 +148,9 @@ Object.extend(Prado.CallbackRequest,
Exception :
{
/**
- * Server returns 505 exception. Just log it.
+ * Server returns 500 exception. Just log it.
*/
- "on505" : function(request, transport, data)
+ "on500" : function(request, transport, data)
{
var e = request.getHeaderData(Prado.CallbackRequest.ERROR_HEADER);
Logger.error("Callback Server Error "+e.code, this.formatException(e));
@@ -163,7 +171,6 @@ Object.extend(Prado.CallbackRequest,
{
msg += inspect(action)+"\n";
})
-
Logger.warn(msg);
}
},
@@ -209,10 +216,61 @@ Object.extend(Prado.CallbackRequest,
*/
decode : function(data)
{
- return Prado.JSON.parse(data);
+ if(typeof(data) == "string" && data.trim().length > 0)
+ return Prado.JSON.parse(data);
+ else
+ return null;
+ },
+
+ /**
+ * Dispatch quequed requests, and set a timeout.
+ */
+ 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);
+ }
+ },
+
+ /**
+ * Remove a request currently in progress and call dispatchQuequedRequest.
+ */
+ 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});
+
//Add HTTP exception respones when logger is enabled.
Event.OnLoad(function()
{
@@ -233,7 +291,10 @@ Prado.CallbackRequest.prototype =
/**
* Callback options, including onXXX events.
*/
- options : {},
+ options :
+ {
+ TimeOut : 30000 // 30 second timeout.
+ },
/**
* Callback target ID. E.g. $control->getUniqueID();
@@ -243,14 +304,15 @@ Prado.CallbackRequest.prototype =
/**
* Current callback request.
*/
- request : null,
+ callback : null,
/**
* Prepare and inititate a callback request.
*/
initialize : function(id, options)
{
- this.options = options || {};
+ Object.extend(this.options, options || {});
+
this.id = id;
var request =
@@ -258,14 +320,18 @@ Prado.CallbackRequest.prototype =
postBody : this._getPostData(),
parameters : ''
}
- Object.extend(this.options || {},request);
+
+ Object.extend(this.options, request);
+
if(this.options.CausesValidation != false && typeof(Prado.Validation) != "undefined")
{
var form = this.options.Form || Prado.Validation.getForm();
if(Prado.Validation.validate(form,this.options.ValidationGroup,this) == false)
return;
}
- this.request = new Ajax.Request(this.url, this.options);
+
+ Prado.CallbackRequest.Queque.push(this);
+ Prado.CallbackRequest.dispatchQuequedRequest();
},
/**
diff --git a/framework/Web/Javascripts/prado/element.js b/framework/Web/Javascripts/prado/element.js
index 88fb9ec5..cf02095b 100644
--- a/framework/Web/Javascripts/prado/element.js
+++ b/framework/Web/Javascripts/prado/element.js
@@ -76,7 +76,7 @@ Prado.Element =
return false;
},
- replaceContent : function(element, method, content, boundary, transport)
+ replace : function(element, method, content, boundary, transport)
{
if(boundary)
{
diff --git a/framework/Web/UI/ActiveControls/TActiveLabel.php b/framework/Web/UI/ActiveControls/TActiveLabel.php
new file mode 100644
index 00000000..d71d8b7a
--- /dev/null
+++ b/framework/Web/UI/ActiveControls/TActiveLabel.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * TActiveLabel class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $Date: $
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TActiveLabel class
+ *
+ * The active control counterpart of TLabel component. During a callback
+ * request, setting {@link setText Text} property will also set the text of the
+ * label on the client upon callback completion. Similarly, setting {@link
+ * setForControl ForControl} will set the client-side for attribute on the
+ * label.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Revision: $ $Date: $
+ * @package System.Web.UI.ActiveControls
+ * @since 3.0
+ */
+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.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * On callback response, the inner HTMl of the label is updated.
+ * @param string the text value of the label
+ */
+ public function setText($value)
+ {
+ parent::setText($value);
+ if($this->getPage()->getAllowCallbackUpdate())
+ {
+ $this->getPage()->getCallbackClient()->update($this, $value);
+ }
+ }
+
+ /**
+ * Sets the ID of the control that the label is associated with.
+ * The control must be locatable via {@link TControl::findControl} using the ID.
+ * On callback response, the For attribute of the label is updated.
+ * @param string the associated control ID
+ */
+ public function setForControl($value)
+ {
+ parent::setForControl($value);
+ if($this->getPage()->getAllowCallbackUpdate())
+ {
+ $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 4cb785dd..db783a12 100644
--- a/framework/Web/UI/ActiveControls/TActivePageAdapter.php
+++ b/framework/Web/UI/ActiveControls/TActivePageAdapter.php
@@ -285,7 +285,7 @@ class TCallbackErrorHandler extends TErrorHandler
{
$response = $this->getApplication()->getResponse();
$data = TJavascript::jsonEncode($this->getExceptionData($exception));
- $response->appendHeader('HTTP/1.0 505 Internal Error');
+ $response->appendHeader('HTTP/1.0 500 Internal Error');
$response->appendHeader(TActivePageAdapter::CALLBACK_ERROR_HEADER.': '.$data);
}
else
diff --git a/framework/Web/UI/ActiveControls/TCallback.php b/framework/Web/UI/ActiveControls/TCallback.php
index d3b1f54d..9c3234fd 100644
--- a/framework/Web/UI/ActiveControls/TCallback.php
+++ b/framework/Web/UI/ActiveControls/TCallback.php
@@ -4,7 +4,7 @@
* Created on 25/04/2006
*/
-class TCallback extends TWebControl implements ICallbackEventHandler
+class TCallback extends TControl implements ICallbackEventHandler
{
/**
* @var TCallbackClientSideOptions client-side options.
@@ -21,15 +21,7 @@ class TCallback extends TWebControl implements ICallbackEventHandler
parent::__construct();
$this->setAdapter(new TActiveControlAdapter($this));
}
-
- /**
- * @return string tag name of the panel
- */
- protected function getTagName()
- {
- return 'div';
- }
-
+
/**
* @return boolean whether callback event trigger by this button will cause
* input validation, default is true
@@ -153,13 +145,6 @@ class TCallback extends TWebControl implements ICallbackEventHandler
$client = $this->getPage()->getClientScript();
return $client->getCallbackReference($this, $this->getCallbackOptions());
}
-
- public function render($writer)
- {
- parent::render($writer);
- if($this->getPage()->getIsCallback())
- $this->getPage()->getCallbackClient()->replace($this, $writer);
- }
}
?>
diff --git a/framework/Web/UI/ActiveControls/TCallbackClientScript.php b/framework/Web/UI/ActiveControls/TCallbackClientScript.php
index aaf81380..5f8851db 100644
--- a/framework/Web/UI/ActiveControls/TCallbackClientScript.php
+++ b/framework/Web/UI/ActiveControls/TCallbackClientScript.php
@@ -318,20 +318,16 @@ class TCallbackClientScript extends TApplicationComponent
if($content instanceof TControl)
{
$boundary = $this->getRenderedContentBoundary($content);
- $this->callClientFunction('Prado.Element.replaceContent',
- array($element, $method, null, $boundary));
+ $content = null;
}
else if($content instanceof THtmlWriter)
{
$boundary = $this->getResponseContentBoundary($content);
- $this->callClientFunction('Prado.Element.replaceContent',
- array($element, $method, null, $boundary));
- }
- else
- {
- $this->callClientFunction('Prado.Element.replaceContent',
- array($element, $method, $content, $boundary));
+ $content = null;
}
+
+ $this->callClientFunction('Prado.Element.replace',
+ array($element, $method, $content, $boundary));
}
/**
diff --git a/framework/Web/UI/ActiveControls/TCallbackClientSideOptions.php b/framework/Web/UI/ActiveControls/TCallbackClientSideOptions.php
index 1e1bd52f..6a4731f7 100644
--- a/framework/Web/UI/ActiveControls/TCallbackClientSideOptions.php
+++ b/framework/Web/UI/ActiveControls/TCallbackClientSideOptions.php
@@ -216,6 +216,22 @@ class TCallbackClientSideOptions extends TClientSideOptions
{
$this->getOptions()->add('PostState', TPropertyValue::ensureBoolean($value));
}
+
+ /**
+ * @return integer callback request timeout.
+ */
+ public function getRequestTimeOut()
+ {
+ return $this->getOption('TimeOut');
+ }
+
+ /**
+ * @param integer callback request timeout
+ */
+ public function setRequestTimeOut($value)
+ {
+ $this->getOptions()->add('TimeOut', TPropertyValue::ensureInteger($value));
+ }
}
?>
diff --git a/framework/Web/UI/TPage.php b/framework/Web/UI/TPage.php
index 94f1f475..11ebc1dd 100644
--- a/framework/Web/UI/TPage.php
+++ b/framework/Web/UI/TPage.php
@@ -37,7 +37,7 @@ class TPage extends TTemplateControl
const FIELD_PAGESTATE='PRADO_PAGESTATE';
const FIELD_CALLBACK_TARGET='PRADO_CALLBACK_TARGET';
const FIELD_CALLBACK_PARAMETER='PRADO_CALLBACK_PARAMETER';
-// const FIELD_CALLBACK_ID='PRADO_CALLBACK_ID';
+
/**
* @var array system post fields
*/
@@ -48,7 +48,6 @@ class TPage extends TTemplateControl
'PRADO_PAGESTATE'=>true,
'PRADO_CALLBACK_TARGET'=>true,
'PRADO_CALLBACK_PARAMETER'=>true
- //'PRADO_CALLBACK_ID'=>true
);
/**
* @var TForm form instance
@@ -154,6 +153,11 @@ 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.
@@ -278,6 +282,8 @@ 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);
@@ -295,6 +301,7 @@ class TPage extends TTemplateControl
Prado::trace("Page raiseChangedEvents()",'System.Web.UI.TPage');
$this->raiseChangedEvents();
+
$this->getAdapter()->processCallbackEvent($writer);
/*
@@ -324,6 +331,28 @@ class TPage extends TTemplateControl
}
/**
+ * 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.
* @return TCallbackClientScript interface to client-side javascript code.