summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxue <>2006-09-13 12:37:23 +0000
committerxue <>2006-09-13 12:37:23 +0000
commit348fb25264f6cc9251f5ae9cb8c7a8a1013e2d67 (patch)
treeca03f23737bfdb09ab509a8b788277fc218400c2
parent3e76d1b8b3c71108f5a9ca1af5c9d40613546a90 (diff)
Merge from 3.0 branch till 1409.
-rw-r--r--.gitattributes1
-rw-r--r--HISTORY2
-rw-r--r--demos/quickstart/protected/pages/Advanced/MasterContent.page15
-rw-r--r--demos/quickstart/protected/pages/Configurations/Templates1.page15
-rw-r--r--demos/quickstart/protected/pages/Controls/DataGrid.page1
-rw-r--r--framework/3rdParty/TinyMCE/tiny_mce.tarbin3162493 -> 3164160 bytes
-rw-r--r--framework/Exceptions/messages.txt1
-rw-r--r--framework/Web/THttpResponse.php10
-rw-r--r--framework/Web/UI/TTemplateManager.php109
-rw-r--r--framework/Web/UI/WebControls/TLiteralColumn.php154
10 files changed, 297 insertions, 11 deletions
diff --git a/.gitattributes b/.gitattributes
index 6875bd34..53b3e2b0 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1837,6 +1837,7 @@ framework/Web/UI/WebControls/TListControl.php -text
framework/Web/UI/WebControls/TListControlValidator.php -text
framework/Web/UI/WebControls/TListItem.php -text
framework/Web/UI/WebControls/TLiteral.php -text
+framework/Web/UI/WebControls/TLiteralColumn.php -text
framework/Web/UI/WebControls/TMarkdown.php -text
framework/Web/UI/WebControls/TMultiView.php -text
framework/Web/UI/WebControls/TOutputCache.php -text
diff --git a/HISTORY b/HISTORY
index 6eb24fee..0fd3c0a0 100644
--- a/HISTORY
+++ b/HISTORY
@@ -13,7 +13,9 @@ NEW: TFeedService, TRssFeedDocument (Knut, Qiang)
Version 3.0.5 October 8, 2006
===============================
CHG: Ticket#358 - TFileUpload::saveAs() now returns false instead of exception when error (Qiang)
+ENH: Ticket#361 - Introduced include template tag that supports including external templates (Qiang)
ENH: Ticket#366 - white spaces are now allowed around attribute names in template (Qiang)
+NEW: TLiteralColumn (Qiang)
Version 3.0.4 September 4, 2006
===============================
diff --git a/demos/quickstart/protected/pages/Advanced/MasterContent.page b/demos/quickstart/protected/pages/Advanced/MasterContent.page
index 2698f865..b7bcc9bb 100644
--- a/demos/quickstart/protected/pages/Advanced/MasterContent.page
+++ b/demos/quickstart/protected/pages/Advanced/MasterContent.page
@@ -39,4 +39,19 @@ Then, the contents are inserted into the master control according to the followi
</p>
<img src=<%~ mastercontent.gif %> alt="Master and Content" />
<img src=<%~ pcrelation.gif %> alt="Parent-child relationship between master and content" />
+
+<h2>Master vs. External Template</h2>
+<p>
+Master is very similar to external templates which are introduced since version 3.0.5. A special <a href="?page=Configurations.Templates1">include tag</a> is used to include an external template file into a base template.
+</p>
+<p>
+Both master and external template can be used to share common contents among pages. A master is a template control whose template contains the common content and whose class file contains the logic associated with the master. An external template, on the other hand, is a pure template file without any class files.
+</p>
+<p>
+Therefore, use master control if the common content has to be associated with some logic, such as a page header with search box or login box. A master control allows you to specify how the common content should interact with end users. If you use external templates, you will have to put the needed logic in the page or control class who owns the base template.
+</p>
+<p>
+Performancewise, external template is lighter than master as the latter is a self-contained control participating the page lifecycles, while the former is used only when the template is being parsed.
+</p>
+
</com:TContent> \ No newline at end of file
diff --git a/demos/quickstart/protected/pages/Configurations/Templates1.page b/demos/quickstart/protected/pages/Configurations/Templates1.page
index 3f2fcc5e..7acd92d0 100644
--- a/demos/quickstart/protected/pages/Configurations/Templates1.page
+++ b/demos/quickstart/protected/pages/Configurations/Templates1.page
@@ -85,4 +85,19 @@ Comments INVISIBLE to end-users
Note, template comments (by &lt;!-- ... --!&gt;) cannot appear in a property value.
</p>
+<h2>Include Tags</h2>
+<p>
+Since version 3.0.5, PRADO starts to support external template inclusion. This is accomplished via include tags, where external template files are specified in namespace format and their file name must be terminated as <tt>.tpl</tt>.
+</p>
+<com:TTextHighlighter Language="prado" CssClass="source">
+&lt;%include path.to.templateFile %&gt;
+</com:TTextHighlighter>
+
+<p>
+External templates will be inserted at the places where the include tags occur in the base template.
+</p>
+<p>
+Note, nested template inclusion is not supported, i.e., you cannot have include tags in an external template.
+</p>
+
</com:TContent> \ No newline at end of file
diff --git a/demos/quickstart/protected/pages/Controls/DataGrid.page b/demos/quickstart/protected/pages/Controls/DataGrid.page
index 2a51a3de..4697d0e5 100644
--- a/demos/quickstart/protected/pages/Controls/DataGrid.page
+++ b/demos/quickstart/protected/pages/Controls/DataGrid.page
@@ -21,6 +21,7 @@ PRADO provides five types of columns:
</p>
<ul>
<li><tt>TBoundColumn</tt> associates cells with a specific field of data and displays the cells according to their modes.</li>
+ <li><tt>TLiteralColumn</tt> associates cells with a specific field of data and displays the cells with static texts.</li>
<li><tt>TCheckBoxColumn</tt> associates cells with a specific field of data and displays in each cell a checkbox whose check state is determined by the data field value.</li>
<li><tt>TDropDownListColumn</tt> associates cells with a specific field of data and displays the cells according to their modes. If in edit mode, a cell will be displayed with a <tt>TDropDownList</tt>.</li>
<li><tt>THyperLinkColumn</tt> displays in the cells a hyperlink whose caption and URL can be either statically specified or bound to some fields of data.</li>
diff --git a/framework/3rdParty/TinyMCE/tiny_mce.tar b/framework/3rdParty/TinyMCE/tiny_mce.tar
index ee8a5603..125ee624 100644
--- a/framework/3rdParty/TinyMCE/tiny_mce.tar
+++ b/framework/3rdParty/TinyMCE/tiny_mce.tar
Binary files differ
diff --git a/framework/Exceptions/messages.txt b/framework/Exceptions/messages.txt
index dfa88750..40e5110e 100644
--- a/framework/Exceptions/messages.txt
+++ b/framework/Exceptions/messages.txt
@@ -124,6 +124,7 @@ template_eventhandler_invalid = {0}.{1} can only accept a static string.
template_controlid_invalid = {0}.ID can only accept a static text string.
template_controlskinid_invalid = {0}.SkinID can only accept a static text string.
template_content_unexpected = Unexpected content is encountered when instantiating template: {0}.
+template_include_invalid = Invalid template inclusion. Make sure {0} is a valid namespace pointing to an existing template file whose extension is .tpl.
xmldocument_file_read_failed = TXmlDocument is unable to read file '{0}'.
xmldocument_file_write_failed = TXmlDocument is unable to write file '{0}'.
diff --git a/framework/Web/THttpResponse.php b/framework/Web/THttpResponse.php
index 90d2c0ef..ad935103 100644
--- a/framework/Web/THttpResponse.php
+++ b/framework/Web/THttpResponse.php
@@ -32,13 +32,15 @@ Prado::using('System.Web.THttpResponseAdapter');
* By default, THttpResponse is registered with {@link TApplication} as the
* response module. It can be accessed via {@link TApplication::getResponse()}.
*
- * THttpRequest may be configured in application configuration file as follows
+ * THttpResponse may be configured in application configuration file as follows
+ *
* <module id="response" CacheExpire="20" CacheControl="nocache" BufferOutput="true" />
+ *
* where {@link getCacheExpire CacheExpire}, {@link getCacheControl CacheControl}
- * and {@link getBufferOutput BufferOutput} are configurable properties of THttpResponse.
+ * and {@link getBufferOutput BufferOutput} are optional properties of THttpResponse.
*
- * When sending headers the Charset set in {@link TGlobalization::getCharset()}
- * is use when Charset is null or empty in THttpResponse.
+ * THttpResponse sends charset header if either {@link setCharset() Charset}
+ * or {@link TGlobalization::setCharset() TGlobalization.Charset} is set.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @version $Id$
diff --git a/framework/Web/UI/TTemplateManager.php b/framework/Web/UI/TTemplateManager.php
index 58afed3c..8c4983bf 100644
--- a/framework/Web/UI/TTemplateManager.php
+++ b/framework/Web/UI/TTemplateManager.php
@@ -85,12 +85,28 @@ class TTemplateManager extends TModule
$array=$cache->get(self::TEMPLATE_CACHE_PREFIX.$fileName);
if(is_array($array))
{
- list($template,$timestamp)=$array;
- if(filemtime($fileName)<$timestamp)
+ list($template,$timestamps)=$array;
+ if($this->getApplication()->getMode()===TApplicationMode::Performance)
+ return $template;
+ $cacheValid=true;
+ foreach($timestamps as $tplFile=>$timestamp)
+ {
+ if(!is_file($tplFile) || filemtime($tplFile)>$timestamp)
+ {
+ $cacheValid=false;
+ break;
+ }
+ }
+ if($cacheValid)
return $template;
}
$template=new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
- $cache->set(self::TEMPLATE_CACHE_PREFIX.$fileName,array($template,time()));
+ $includedFiles=$template->getIncludedFiles();
+ $timestamps=array();
+ $timestamps[$fileName]=filemtime($fileName);
+ foreach($includedFiles as $includedFile)
+ $timestamps[$includedFile]=filemtime($includedFile);
+ $cache->set(self::TEMPLATE_CACHE_PREFIX.$fileName,array($template,$timestamps));
return $template;
}
}
@@ -206,6 +222,9 @@ class TTemplate extends TApplicationComponent implements ITemplate
*/
private $_hashCode='';
private $_tplControl=null;
+ private $_includedFiles=array();
+ private $_includeAtLine=array();
+ private $_includeLines=array();
/**
@@ -540,6 +559,7 @@ class TTemplate extends TApplicationComponent implements ITemplate
*/
protected function parse($input)
{
+ $input=$this->preprocess($input);
$tpl=&$this->_tpl;
$n=preg_match_all(self::REGEX_RULES,$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
$expectPropEnd=false;
@@ -732,10 +752,7 @@ class TTemplate extends TApplicationComponent implements ITemplate
$line=$this->_startingLine+1;
else
$line=$this->_startingLine+count(explode("\n",substr($input,0,$matchEnd+1)));
- if(empty($this->_tplFile))
- throw new TConfigurationException('template_format_invalid2',$line,$e->getMessage(),$input);
- else
- throw new TConfigurationException('template_format_invalid',$this->_tplFile,$line,$e->getMessage());
+ $this->handleException($e,$line,$input);
}
if($this->_directive===null)
@@ -949,6 +966,84 @@ class TTemplate extends TApplicationComponent implements ITemplate
else
throw new TConfigurationException('template_component_required',$type);
}
+
+ /**
+ * @return array list of included external template files
+ */
+ public function getIncludedFiles()
+ {
+ return $this->_includedFiles;
+ }
+
+ /**
+ * Handles template parsing exception.
+ * This method rethrows the exception caught during template parsing.
+ * It adjusts the error location by giving out correct error line number and source file.
+ * @param Exception template exception
+ * @param int line number
+ * @param string template string if no source file is used
+ */
+ protected function handleException($e,$line,$input=null)
+ {
+ $srcFile=$this->_tplFile;
+ if(($n=count($this->_includedFiles))>0) // need to adjust error row number and file name
+ {
+ for($i=$n-1;$i>=0;--$i)
+ {
+ if($this->_includeAtLine[$i]<=$line)
+ {
+ if($line<$this->_includeAtLine[$i]+$this->_includeLines[$i])
+ {
+ $line=$line-$this->_includeAtLine[$i]+1;
+ $srcFile=$this->_includedFiles[$i];
+ break;
+ }
+ else
+ $line=$line-$this->_includeLines[$i]+1;
+ }
+ }
+ }
+ if(empty($srcFile))
+ throw new TConfigurationException('template_format_invalid2',$line,$e->getMessage(),$input);
+ else
+ throw new TConfigurationException('template_format_invalid',$srcFile,$line,$e->getMessage());
+ }
+
+ /**
+ * Preprocesses the template string by including external templates
+ * @param string template string
+ * @return string expanded template string
+ */
+ protected function preprocess($input)
+ {
+ if($n=preg_match_all('/<%include(.*?)%>/',$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE))
+ {
+ for($i=0;$i<$n;++$i)
+ {
+ $filePath=Prado::getPathOfNamespace(trim($matches[$i][1][0]),TTemplateManager::TEMPLATE_FILE_EXT);
+ if($filePath!==null && is_file($filePath))
+ $this->_includedFiles[]=$filePath;
+ else
+ {
+ $errorLine=count(explode("\n",substr($input,0,$matches[$i][0][1]+1)));
+ $this->handleException(new TConfigurationException('template_include_invalid',trim($matches[$i][1][0])),$errorLine,$input);
+ }
+ }
+ $base=0;
+ for($i=0;$i<$n;++$i)
+ {
+ $ext=file_get_contents($this->_includedFiles[$i]);
+ $length=strlen($matches[$i][0][0]);
+ $offset=$base+$matches[$i][0][1];
+ $this->_includeAtLine[$i]=count(explode("\n",substr($input,0,$offset)));
+ $this->_includeLines[$i]=count(explode("\n",$ext));
+ $input=substr_replace($input,$ext,$offset,$length);
+ $base+=strlen($ext)-$length;
+ }
+ }
+
+ return $input;
+ }
}
?>
diff --git a/framework/Web/UI/WebControls/TLiteralColumn.php b/framework/Web/UI/WebControls/TLiteralColumn.php
new file mode 100644
index 00000000..e78c4e6d
--- /dev/null
+++ b/framework/Web/UI/WebControls/TLiteralColumn.php
@@ -0,0 +1,154 @@
+<?php
+/**
+ * TLiteralColumn class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id: TLiteralColumn.php 1397 2006-09-07 07:55:53Z wei $
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TDataGridColumn class file
+ */
+Prado::using('System.Web.UI.WebControls.TDataGridColumn');
+
+/**
+ * TLiteralColumn class
+ *
+ * TLiteralColumn represents a static text column that is bound to a field in a data source.
+ * The cells in the column will be displayed with static texts using the data indexed by
+ * {@link setDataField DataField}. You can customize the display by
+ * setting {@link setDataFormatString DataFormatString}.
+ *
+ * If {@link setDataField DataField} is not specified, the cells will be filled
+ * with {@link setText Text}.
+ *
+ * If {@link setEncode Encode} is true, the static texts will be HTML-encoded.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: TLiteralColumn.php 1397 2006-09-07 07:55:53Z wei $
+ * @package System.Web.UI.WebControls
+ * @since 3.0.5
+ */
+class TLiteralColumn extends TDataGridColumn
+{
+ /**
+ * @return string the field name from the data source to bind to the column
+ */
+ public function getDataField()
+ {
+ return $this->getViewState('DataField','');
+ }
+
+ /**
+ * @param string the field name from the data source to bind to the column
+ */
+ public function setDataField($value)
+ {
+ $this->setViewState('DataField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how the bound data will be displayed.
+ */
+ public function getDataFormatString()
+ {
+ return $this->getViewState('DataFormatString','');
+ }
+
+ /**
+ * @param string the formatting string used to control how the bound data will be displayed.
+ */
+ public function setDataFormatString($value)
+ {
+ $this->setViewState('DataFormatString',$value,'');
+ }
+
+ /**
+ * @return string static text to be displayed in the column. Defaults to empty.
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * @param string static text to be displayed in the column.
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * @return boolean whether the rendered text should be HTML-encoded. Defaults to false.
+ */
+ public function getEncode()
+ {
+ return $this->getViewState('Encode',false);
+ }
+
+ /**
+ * @param boolean whether the rendered text should be HTML-encoded.
+ */
+ public function setEncode($value)
+ {
+ $this->setViewState('Encode',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * This method overrides the parent implementation.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ parent::initializeCell($cell,$columnIndex,$itemType);
+ if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::EditItem || $itemType===TListItemType::SelectedItem)
+ {
+ if($this->getDataField()!=='')
+ $cell->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ else
+ {
+ if(($dataField=$this->getDataField())!=='')
+ $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ else
+ {
+ $text=$this->getText();
+ if($this->getEncode())
+ $text=THttpUtility::htmlEncode($text);
+ $cell->setText($text);
+ }
+ }
+ }
+ }
+
+ /**
+ * Databinds a cell in the column.
+ * This method is invoked when datagrid performs databinding.
+ * It populates the content of the cell with the relevant data from data source.
+ */
+ public function dataBindColumn($sender,$param)
+ {
+ $item=$sender->getNamingContainer();
+ $data=$item->getDataItem();
+ $formatString=$this->getDataFormatString();
+ if(($field=$this->getDataField())!=='')
+ $value=$this->formatDataValue($formatString,$this->getDataFieldValue($data,$field));
+ else
+ $value=$this->formatDataValue($formatString,$data);
+ if($sender instanceof TTableCell)
+ {
+ if($this->getEncode())
+ $value=THttpUtility::htmlEncode($value);
+ $sender->setText($value);
+ }
+ }
+}
+
+?> \ No newline at end of file