summaryrefslogtreecommitdiff
path: root/framework
diff options
context:
space:
mode:
Diffstat (limited to 'framework')
-rw-r--r--framework/TApplication.php6
-rw-r--r--framework/Web/THttpResponse.php78
-rw-r--r--framework/Web/UI/ActiveControls/TActiveControlAdapter.php10
-rwxr-xr-xframework/Web/UI/ActiveControls/TDraggable.php19
-rwxr-xr-xframework/Web/UI/ActiveControls/TDropContainer.php13
-rw-r--r--framework/Web/UI/TClientScriptManager.php67
-rw-r--r--framework/Web/UI/TForm.php28
-rw-r--r--framework/Web/UI/THtmlWriter.php3
-rw-r--r--framework/Web/UI/TPage.php27
-rw-r--r--framework/Web/UI/WebControls/TBaseValidator.php3
-rw-r--r--framework/Web/UI/WebControls/THtmlArea.php18
11 files changed, 227 insertions, 45 deletions
diff --git a/framework/TApplication.php b/framework/TApplication.php
index b481f12a..1fc9485a 100644
--- a/framework/TApplication.php
+++ b/framework/TApplication.php
@@ -1252,10 +1252,11 @@ class TApplication extends TComponent
/**
* Flushes output to client side.
+ * @param boolean whether to continue buffering after flush if buffering was active
*/
- public function flushOutput()
+ public function flushOutput($continueBuffering = true)
{
- $this->getResponse()->flush();
+ $this->getResponse()->flush($continueBuffering);
}
/**
@@ -1264,6 +1265,7 @@ class TApplication extends TComponent
*/
public function onEndRequest()
{
+ $this->flushOutput(false); // flush all remaining content in the buffer
$this->saveGlobals(); // save global state
$this->raiseEvent('OnEndRequest',$this,null);
}
diff --git a/framework/Web/THttpResponse.php b/framework/Web/THttpResponse.php
index 50ac4d7d..07d11a2c 100644
--- a/framework/Web/THttpResponse.php
+++ b/framework/Web/THttpResponse.php
@@ -116,6 +116,14 @@ class THttpResponse extends TModule implements ITextWriter
* @var THttpResponseAdapter adapter.
*/
private $_adapter;
+ /**
+ * @var boolean whether http response header has been sent
+ */
+ private $_httpHeaderSent;
+ /**
+ * @var boolean whether content-type header has been sent
+ */
+ private $_contentTypeHeaderSent;
/**
* Destructor.
@@ -203,6 +211,8 @@ class THttpResponse extends TModule implements ITextWriter
*/
public function setContentType($type)
{
+ if ($this->_contentTypeHeaderSent)
+ throw new Exception('Unable to alter content-type as it has been already sent');
$this->_contentType = $type;
}
@@ -268,6 +278,8 @@ class THttpResponse extends TModule implements ITextWriter
*/
public function setStatusCode($status, $reason=null)
{
+ if ($this->_httpHeaderSent)
+ throw new Exception('Unable to alter response as HTTP header already sent');
$status=TPropertyValue::ensureInteger($status);
if(isset(self::$HTTP_STATUS_CODES[$status])) {
$this->_reason=self::$HTTP_STATUS_CODES[$status];
@@ -308,6 +320,9 @@ class THttpResponse extends TModule implements ITextWriter
*/
public function write($str)
{
+ // when starting output make sure we send the headers first
+ if (!$this->_bufferOutput and !$this->_httpHeaderSent)
+ $this->ensureHeadersSent();
echo $str;
}
@@ -435,36 +450,79 @@ class THttpResponse extends TModule implements ITextWriter
/**
* Flush the response contents and headers.
*/
- public function flush()
+ public function flush($continueBuffering = true)
{
if($this->getHasAdapter())
- $this->_adapter->flushContent();
+ $this->_adapter->flushContent($continueBuffering);
else
- $this->flushContent();
+ $this->flushContent($continueBuffering);
+ }
+
+ /**
+ * Ensures that HTTP response and content-type headers are sent
+ */
+ public function ensureHeadersSent()
+ {
+ $this->ensureHttpHeaderSent();
+ $this->ensureContentTypeHeaderSent();
}
/**
* Outputs the buffered content, sends content-type and charset header.
* This method is used internally. Please use {@link flush} instead.
+ * @param boolean whether to continue buffering after flush if buffering was active
*/
- public function flushContent()
+ public function flushContent($continueBuffering = true)
{
Prado::trace("Flushing output",'System.Web.THttpResponse');
- $this->sendHttpHeader();
- $this->sendContentTypeHeader();
- if($this->_bufferOutput)
- ob_flush();
+ $this->ensureHeadersSent();
+ if($this->_bufferOutput)
+ {
+ // avoid forced send of http headers (ob_flush() does that) if there's no output yet
+ if (ob_get_length()>0)
+ {
+ if (!$continueBuffering)
+ {
+ $this->_bufferOutput = false;
+ ob_end_flush();
+ }
+ else
+ ob_flush();
+ flush();
+ }
+ }
+ else
+ flush();
+ }
+
+ /**
+ * Ensures that the HTTP header with the status code and status reason are sent
+ */
+ protected function ensureHttpHeaderSent()
+ {
+ if (!$this->_httpHeaderSent)
+ $this->sendHttpHeader();
}
/**
* Send the HTTP header with the status code (defaults to 200) and status reason (defaults to OK)
*/
- protected function sendHttpHeader ()
+ protected function sendHttpHeader()
{
if (($version=$this->getRequest()->getHttpProtocolVersion())==='')
header (' ', true, $this->_status);
else
header($version.' '.$this->_status.' '.$this->_reason, true, $this->_status);
+ $this->_httpHeaderSent = true;
+ }
+
+ /**
+ * Ensures that the HTTP header with the status code and status reason are sent
+ */
+ protected function ensureContentTypeHeaderSent()
+ {
+ if (!$this->_contentTypeHeaderSent)
+ $this->sendContentTypeHeader();
}
/**
@@ -484,6 +542,8 @@ class THttpResponse extends TModule implements ITextWriter
if($charset==='') $charset = self::DEFAULT_CHARSET;
$this->appendHeader('Content-Type: '.$contentType.';charset='.$charset);
+
+ $this->_contentTypeHeaderSent = true;
}
/**
diff --git a/framework/Web/UI/ActiveControls/TActiveControlAdapter.php b/framework/Web/UI/ActiveControls/TActiveControlAdapter.php
index e8f947af..99c5e71e 100644
--- a/framework/Web/UI/ActiveControls/TActiveControlAdapter.php
+++ b/framework/Web/UI/ActiveControls/TActiveControlAdapter.php
@@ -75,6 +75,15 @@ class TActiveControlAdapter extends TControlAdapter
$this->_activeControlType = $type;
}
+ /**
+ * Publish the ajax script
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $this->getPage()->getClientScript()->registerPradoScript('ajax');
+ }
+
/**
* Renders the callback client scripts.
*/
@@ -93,7 +102,6 @@ class TActiveControlAdapter extends TControlAdapter
$key = 'Prado.CallbackRequest.addPostLoaders';
if(!$cs->isEndScriptRegistered($key))
{
- $cs->registerPradoScript('ajax');
$data = $this->getPage()->getPostDataLoaders();
if(count($data) > 0)
{
diff --git a/framework/Web/UI/ActiveControls/TDraggable.php b/framework/Web/UI/ActiveControls/TDraggable.php
index 34d8c548..10e78b9b 100755
--- a/framework/Web/UI/ActiveControls/TDraggable.php
+++ b/framework/Web/UI/ActiveControls/TDraggable.php
@@ -136,6 +136,20 @@ class TDraggable extends TPanel
$this->setViewState('Constraint', TPropertyValue::ensureEnum($value, 'TDraggableConstraint'), TDraggableConstraint::None);
}
+ /**
+ * Registers clientscripts
+ *
+ * This method overrides the parent implementation and is invoked before render.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ if ($this->getGhosting()==TDraggableGhostingOptions::SuperGhosting)
+ $cs->registerPradoScript('dragdropextra');
+ else
+ $cs->registerPradoScript('dragdrop');
+ }
/**
* Ensure that the ID attribute is rendered and registers the javascript code
@@ -145,11 +159,6 @@ class TDraggable extends TPanel
{
parent::addAttributesToRender($writer);
$writer->addAttribute('id',$this->getClientID());
- $cs=$this->getPage()->getClientScript();
- if ($this->getGhosting()==TDraggableGhostingOptions::SuperGhosting)
- $cs->registerPradoScript('dragdropextra');
- else
- $cs->registerPradoScript('dragdrop');
$options=TJavascript::encode($this->getPostBackOptions());
$class=$this->getClientClassName();
$code="new {$class}('{$this->getClientId()}', {$options}) ";
diff --git a/framework/Web/UI/ActiveControls/TDropContainer.php b/framework/Web/UI/ActiveControls/TDropContainer.php
index 915aa8f9..e6933147 100755
--- a/framework/Web/UI/ActiveControls/TDropContainer.php
+++ b/framework/Web/UI/ActiveControls/TDropContainer.php
@@ -172,6 +172,17 @@ class TDropContainer extends TPanel implements IActiveControl, ICallbackEventHan
return 'Prado.WebUI.DropContainer';
}
+ /**
+ * Registers clientscripts
+ *
+ * This method overrides the parent implementation and is invoked before render.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $this->getPage()->getClientScript()->registerPradoScript('dragdrop');
+ }
/**
* Ensure that the ID attribute is rendered and registers the javascript code
@@ -182,8 +193,6 @@ class TDropContainer extends TPanel implements IActiveControl, ICallbackEventHan
parent::addAttributesToRender($writer);
$writer->addAttribute('id',$this->getClientID());
- $this->getPage()->getClientScript()->registerPradoScript('dragdrop');
-
$this->getActiveControl()->registerCallbackClientScript(
$this->getClientClassName(), $this->getPostBackOptions());
}
diff --git a/framework/Web/UI/TClientScriptManager.php b/framework/Web/UI/TClientScriptManager.php
index 8f246d3d..eec347eb 100644
--- a/framework/Web/UI/TClientScriptManager.php
+++ b/framework/Web/UI/TClientScriptManager.php
@@ -82,6 +82,12 @@ class TClientScriptManager extends TApplicationComponent
*/
private static $_pradoPackages;
+ private $_renderedHiddenFields;
+
+ private $_renderedScriptFiles;
+
+ private $_renderedPradoScripts;
+
/**
* Constructor.
* @param TPage page that owns this client script manager
@@ -118,6 +124,7 @@ class TClientScriptManager extends TApplicationComponent
*/
private function registerPradoScriptInternal($name)
{
+ // $this->checkIfNotInRender();
if(!isset($this->_registeredPradoScripts[$name]))
{
if(self::$_pradoScripts === null)
@@ -149,9 +156,11 @@ class TClientScriptManager extends TApplicationComponent
* Renders the HTML tags for PRADO js files
* @param THtmlWriter writer
*/
- protected function renderPradoScripts($writer)
+ protected function renderPradoScriptsInt($writer, $initial)
{
- if(($packages=array_keys($this->_registeredPradoScripts))!==array())
+ if($initial) $this->_renderedPradoScripts = array();
+ $addedScripts = array_diff($this->_registeredPradoScripts,$this->_renderedPradoScripts);
+ if(($packages=array_keys($addedScripts))!==array())
{
if (Prado::getApplication()->getMode()!==TApplicationMode::Debug)
{
@@ -178,6 +187,7 @@ class TClientScriptManager extends TApplicationComponent
}
$writer->write(TJavaScript::renderScriptFiles($packagesUrl));
}
+ $this->_renderedPradoScripts = $this->_registeredPradoScripts;
}
}
@@ -420,6 +430,7 @@ class TClientScriptManager extends TApplicationComponent
*/
public function registerHeadScriptFile($key,$url)
{
+ $this->checkIfNotInRender();
$this->_headScriptFiles[$key]=$url;
$params=func_get_args();
@@ -433,6 +444,7 @@ class TClientScriptManager extends TApplicationComponent
*/
public function registerHeadScript($key,$script)
{
+ $this->checkIfNotInRender();
$this->_headScripts[$key]=$script;
$params=func_get_args();
@@ -446,6 +458,7 @@ class TClientScriptManager extends TApplicationComponent
*/
public function registerScriptFile($key,$url)
{
+ $this->checkIfNotInRender();
$this->_scriptFiles[$key]=$url;
$params=func_get_args();
@@ -459,6 +472,7 @@ class TClientScriptManager extends TApplicationComponent
*/
public function registerBeginScript($key,$script)
{
+ $this->checkIfNotInRender();
$this->_beginScripts[$key]=$script;
$params=func_get_args();
@@ -486,6 +500,7 @@ class TClientScriptManager extends TApplicationComponent
*/
public function registerHiddenField($name,$value)
{
+ $this->checkIfNotInRender();
$this->_hiddenFields[$name]=$value;
$params=func_get_args();
@@ -621,14 +636,30 @@ class TClientScriptManager extends TApplicationComponent
$writer->write(TJavaScript::renderScriptBlocks($this->_headScripts));
}
+ public function renderScriptFilesBegin($writer)
+ {
+ $this->renderScriptFilesInt($writer,true);
+ }
+
+ public function renderScriptFilesEnd($writer)
+ {
+ $this->renderScriptFilesInt($writer,false);
+ }
+
/**
* @param THtmlWriter writer for the rendering purpose
*/
- public function renderScriptFiles($writer)
+ public function renderScriptFilesInt($writer, $initial)
{
- $this->renderPradoScripts($writer);
+ if ($initial) $this->_renderedScriptFiles = array();
+ $this->renderPradoScriptsInt($writer, $initial);
if(!empty($this->_scriptFiles))
- $writer->write(TJavaScript::renderScriptFiles($this->_scriptFiles));
+ {
+ $addedScripts = array_diff($this->_scriptFiles,$this->_renderedScriptFiles);
+ if (count($addedScripts)>0)
+ $writer->write(TJavaScript::renderScriptFiles($addedScripts));
+ $this->_renderedScriptFiles = $this->_scriptFiles;
+ }
}
/**
@@ -647,14 +678,26 @@ class TClientScriptManager extends TApplicationComponent
$writer->write(TJavaScript::renderScriptBlocks($this->_endScripts));
}
+ public function renderHiddenFieldsBegin($writer)
+ {
+ $this->renderHiddenFieldsInt($writer,true);
+ }
+
+ public function renderHiddenFieldsEnd($writer)
+ {
+ $this->renderHiddenFieldsInt($writer,false);
+ }
+
/**
* @param THtmlWriter writer for the rendering purpose
*/
- public function renderHiddenFields($writer)
- {
+ protected function renderHiddenFieldsInt($writer, $initial)
+ {
+ if ($initial) $this->_renderedHiddenFields = array();
$str='';
foreach($this->_hiddenFields as $name=>$value)
{
+ if (in_array($name,$this->_renderedHiddenFields)) continue;
$id=strtr($name,':','_');
if(is_array($value))
{
@@ -665,10 +708,20 @@ class TClientScriptManager extends TApplicationComponent
{
$str.='<input type="hidden" name="'.$name.'" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
}
+ $this->_renderedHiddenFields[] = $name;
}
if($str!=='')
$writer->write("<div style=\"visibility:hidden;\">\n".$str."</div>\n");
}
+
+ /**
+ * Checks whether page rendering has not begun yet
+ */
+ protected function checkIfNotInRender()
+ {
+ if ($form = $this->_page->InFormRender)
+ throw new Exception('Operation invalid when page is already rendering');
+ }
}
/**
diff --git a/framework/Web/UI/TForm.php b/framework/Web/UI/TForm.php
index 561b59cb..f1e8df5a 100644
--- a/framework/Web/UI/TForm.php
+++ b/framework/Web/UI/TForm.php
@@ -4,7 +4,7 @@
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2011 PradoSoft
+ * @copyright Copyright &copy; 2005-2011 PradoSoft
* @license http://www.pradosoft.com/license/
* @version $Id$
* @package System.Web.UI
@@ -72,11 +72,6 @@ class TForm extends TControl
public function render($writer)
{
$page=$this->getPage();
- $page->beginFormRender($writer);
- $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), new TTextWriter());
- $this->renderChildren( $htmlWriter );
- $content = $htmlWriter->flush();
- $page->endFormRender($writer);
$this->addAttributesToRender($writer);
$writer->renderBeginTag('form');
@@ -84,18 +79,27 @@ class TForm extends TControl
$cs=$page->getClientScript();
if($page->getClientSupportsJavaScript())
{
- $cs->renderHiddenFields($writer);
- $cs->renderScriptFiles($writer);
+ $cs->renderHiddenFieldsBegin($writer);
+ $cs->renderScriptFilesBegin($writer);
$cs->renderBeginScripts($writer);
- $writer->write($content);
-
+ $page->beginFormRender($writer);
+ $this->renderChildren($writer);
+ $cs->renderHiddenFieldsEnd($writer);
+ $page->endFormRender($writer);
+
+ $cs->renderScriptFilesEnd($writer);
$cs->renderEndScripts($writer);
}
else
{
- $cs->renderHiddenFields($writer);
- $writer->write($content);
+ $cs->renderHiddenFieldsBegin($writer);
+
+ $page->beginFormRender($writer);
+ $this->renderChildren($writer);
+ $page->endFormRender($writer);
+
+ $cs->renderHiddenFieldsEnd($writer);
}
$writer->renderEndTag();
diff --git a/framework/Web/UI/THtmlWriter.php b/framework/Web/UI/THtmlWriter.php
index e90ca8e8..beb439b8 100644
--- a/framework/Web/UI/THtmlWriter.php
+++ b/framework/Web/UI/THtmlWriter.php
@@ -4,7 +4,7 @@
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2011 PradoSoft
+ * @copyright Copyright &copy; 2005-2011 PradoSoft
* @license http://www.pradosoft.com/license/
* @version $Id$
* @package System.Web.UI
@@ -181,6 +181,7 @@ class THtmlWriter extends TApplicationComponent implements ITextWriter
/**
* Flushes the rendering result.
* This will invoke the underlying writer's flush method.
+ * @return string the content being flushed
*/
public function flush()
{
diff --git a/framework/Web/UI/TPage.php b/framework/Web/UI/TPage.php
index 43b2f421..f3060dcc 100644
--- a/framework/Web/UI/TPage.php
+++ b/framework/Web/UI/TPage.php
@@ -167,6 +167,10 @@ class TPage extends TTemplateControl implements IPageEvents
* @var boolean whether client supports javascript
*/
private $_enableJavaScript=true;
+ /**
+ * @var THtmlWriter current html render writer
+ */
+ private $_writer;
/**
* Constructor.
@@ -186,6 +190,8 @@ class TPage extends TTemplateControl implements IPageEvents
public function run($writer)
{
Prado::trace("Running page life cycles",'System.Web.UI.TPage');
+ $this->_writer = $writer;
+
$this->determinePostBackMode();
if($this->getIsPostBack())
@@ -197,6 +203,8 @@ class TPage extends TTemplateControl implements IPageEvents
}
else
$this->processNormalRequest($writer);
+
+ $this->_writer = null;
}
protected function processNormalRequest($writer)
@@ -933,6 +941,14 @@ class TPage extends TTemplateControl implements IPageEvents
}
/**
+ * @return boolean Whether form rendering is in progress
+ */
+ public function getInFormRender()
+ {
+ return $this->_inFormRender;
+ }
+
+ /**
* Ensures the control is rendered within a form.
* @param TControl the control to be rendered
* @throws TConfigurationException if the control is outside of the form
@@ -951,8 +967,8 @@ class TPage extends TTemplateControl implements IPageEvents
if($this->_formRendered)
throw new TConfigurationException('page_form_duplicated');
$this->_formRendered=true;
- $this->_inFormRender=true;
$this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState());
+ $this->_inFormRender=true;
}
/**
@@ -1199,6 +1215,15 @@ class TPage extends TTemplateControl implements IPageEvents
$this->_cachingStack=new TStack;
return $this->_cachingStack;
}
+
+ /**
+ * Flushes output
+ */
+ public function flushWriter()
+ {
+ if ($this->_writer)
+ $this->Response->write($this->_writer->flush());
+ }
}
diff --git a/framework/Web/UI/WebControls/TBaseValidator.php b/framework/Web/UI/WebControls/TBaseValidator.php
index c9917a2b..c90f4d9d 100644
--- a/framework/Web/UI/WebControls/TBaseValidator.php
+++ b/framework/Web/UI/WebControls/TBaseValidator.php
@@ -239,7 +239,6 @@ abstract class TBaseValidator extends TLabel implements IValidator
{
$manager['FormID'] = $formID;
$options = TJavaScript::encode($manager);
- $scripts->registerPradoScript('validator');
$scripts->registerEndScript($scriptKey, "new Prado.ValidationManager({$options});");
}
if($this->getEnableClientScript())
@@ -254,6 +253,8 @@ abstract class TBaseValidator extends TLabel implements IValidator
{
parent::onPreRender($param);
$this->updateControlCssClass();
+ if ($this->getEnableClientScript())
+ $this->getPage()->getClientScript()->registerPradoScript('validator');
}
/**
diff --git a/framework/Web/UI/WebControls/THtmlArea.php b/framework/Web/UI/WebControls/THtmlArea.php
index 0af7a979..b11778bd 100644
--- a/framework/Web/UI/WebControls/THtmlArea.php
+++ b/framework/Web/UI/WebControls/THtmlArea.php
@@ -341,6 +341,20 @@ class THtmlArea extends TTextBox
}
/**
+ * Registers clientscripts
+ *
+ * This method overrides the parent implementation and is invoked before render.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $this->loadJavascriptLibrary();
+ if($this->getEnableCompression())
+ $this->preLoadCompressedScript();
+ }
+
+ /**
* Adds attribute name-value pairs to renderer.
* This method overrides the parent implementation by registering
* additional javacript code.
@@ -354,10 +368,6 @@ class THtmlArea extends TTextBox
$this->registerEditorClientScript($writer);
}
- $this->loadJavascriptLibrary();
- if($this->getEnableCompression())
- $this->preLoadCompressedScript();
-
parent::addAttributesToRender($writer);
}