diff options
20 files changed, 292 insertions, 110 deletions
@@ -5,6 +5,8 @@ ENH: Format string in TDataGrid columns can now evaluate an expression (Qiang) Version 3.0RC2 April 16, 2006
=============================
BUG: Ticket#118 - Variables that may not have been initialized (Qiang)
+CHG: Moved localize() into PradoBase (Qiang)
+ENH: Optimized the representation and evaluation of template expressions (Qiang)
Version 3.0RC1 April 5, 2006
============================
@@ -1,6 +1,6 @@ - Upgrading Instructions for PRADO Framework v3.0RC1
- ==================================================
+ Upgrading Instructions for PRADO Framework v3.0.0 RC2
+ =====================================================
!!!IMPORTANT!!!
@@ -14,8 +14,14 @@ version B between A and C, you need to following the instructions for both A and B.
-Upgrading from v3.0b
---------------------
+Upgrading from v3.0.0 RC1
+-------------------------
+- !!! The context of template expression/statements/databinding tags
+ is changed to the control owning the template. Previously, it was
+ the control representing the tag.
+
+Upgrading from v3.0.0 beta
+--------------------------
- THttpSession.UseCustomStorage replaces the previous Storage.
- Pagers in TDataGrid are now enclosed within panels. The event indicating
their creation is changed to OnPagerCreated instead of OnItemCreated.
@@ -27,8 +33,8 @@ Upgrading from v3.0b TLogger, TLogRouter, TDataFieldAccessor, TSimpleDateFormatter are moved to System.Util
-Upgrading from v3.0a
---------------------
+Upgrading from v3.0.0 alpha
+---------------------------
All event names must start with 'On'.
diff --git a/demos/quickstart/protected/pages/Configurations/Templates2.page b/demos/quickstart/protected/pages/Configurations/Templates2.page index f4f68b69..0971c828 100644 --- a/demos/quickstart/protected/pages/Configurations/Templates2.page +++ b/demos/quickstart/protected/pages/Configurations/Templates2.page @@ -10,52 +10,59 @@ Dynamic content tags are introduced as shortcuts to some commonly used <a href=" <a name="et"></a>
<h3>Expression Tags</h3>
<p>
-An expression tag represents a PHP expression that is evaluated when the template control is being rendered. The expression evaluation result is inserted at the place where the tag resides in the template. Its format is as follows,
+An expression tag represents a PHP expression that is evaluated when the template control is being rendered. The expression evaluation result is inserted at the place where the tag resides in the template. The context (namely <tt>$this</tt>) of the expression is the control owning the template.
+</p>
+<p>
+The format of an expression tag is as follows,
+</p>
<com:TTextHighlighter Language="prado" CssClass="source">
<%= PhpExpression %>
</com:TTextHighlighter>
-Inernally, an expression tag is represented by a <tt>TExpression</tt> control. Therefore, in the expression <tt>$this</tt> refers to the <tt>TExpression</tt> control. For example, the following expression tag will display the current page title at the place,
+<p>
+For example, the following expression tag will display the current page title at the place,
+</p>
<com:TTextHighlighter Language="prado" CssClass="source">
-<%= $this->Page->Title %>
+<%= $this->Title %>
</com:TTextHighlighter>
-</p>
<a name="st"></a>
<h3>Statement Tags</h3>
<p>
-Statement tags are similar to expression tags, except that statement tags contain PHP statements rather than expressions. The output of the PHP statements (using for example <tt>echo</tt> or <tt>print</tt> in PHP) are displayed at the place where the statement tag resides in the template. Inernally, a statement tag is represented by a <tt>TStatements</tt> control. Therefore, in the statements <tt>$this</tt> refers to the <tt>TStatements</tt> control. The format of statement tags is as follows,
+Statement tags are similar to expression tags, except that statement tags contain PHP statements rather than expressions. The output of the PHP statements (using for example <tt>echo</tt> or <tt>print</tt> in PHP) are displayed at the place where the statement tag resides in the template. The context (namely <tt>$this</tt>) of the statements is the control owning the template. The format of statement tags is as follows,
+</p>
<com:TTextHighlighter Language="prado" CssClass="source">
<%%
PHP Statements
%>
</com:TTextHighlighter>
-</p>
<p>
The following example displays the current time in Dutch at the place,
+</p>
<com:TTextHighlighter Language="prado" CssClass="source">
<%%
setlocale(LC_ALL, 'nl_NL');
echo strftime("%A %e %B %Y",time());
%>
</com:TTextHighlighter>
-</p>
<a name="dt"></a>
<h3>Databind Tags</h3>
<p>
-Databind tags are similar to expression tags, except that the expressions are evaluated only when a <tt>dataBind()</tt> call is invoked on the controls representing the databind tags. Internally, a <tt>TLiteral</tt> control is used to represent a databind tag and <tt>$this</tt> in the expression would refer to the control. The format of databind tags is as follows,
+Databind tags are similar to expression tags, except that the expressions are evaluated only when a <tt>dataBind()</tt> call is invoked on the controls representing the databind tags. The context (namely <tt>$this</tt>) of a databind expression is the control owning the template. The format of databind tags is as follows,
+</p>
<com:TTextHighlighter Language="prado" CssClass="source">
<%# PhpExpression %>
</com:TTextHighlighter>
-</p>
<a name="pt"></a>
<h3>Parameter Tags</h3>
<p>
Parameter tags are used to insert application parameters at the place where they appear in the template. The format of parameter tags is as follows,
+</p>
<com:TTextHighlighter Language="prado" CssClass="source">
<%$ ParameterName %>
</com:TTextHighlighter>
+<p>
Note, application parameters are usually defined in application configurations or page directory configurations. The parameters are evaluated when the template is instantiated.
</p>
@@ -66,9 +73,11 @@ Asset tags are used to publish private files and display the corresponding the U </p>
<p>
The format of asset tags is as follows,
+</p>
<com:TTextHighlighter Language="prado" CssClass="source">
<%~ LocalFileName %>
</com:TTextHighlighter>
+<p>
where <tt>LocalFileName</tt> refers to a file path that is relative to the directory containing the current template file. The file path can be a single file or a directory. If the latter, the content in the whole directory will be made accessible by end-users.
</p>
<p>
@@ -79,9 +88,12 @@ BE VERY CAUTIOUS when you are using asset tags as it may expose to end-users fil <h3>Localization Tags</h3>
<p>
Localization tags represent localized texts. They are in the following format,
+</p>
<com:TTextHighlighter Language="prado" CssClass="source">
<%[string]%>
</com:TTextHighlighter>
+<p>
where <tt>string</tt> will be translated to different languages according to the end-user's language preference.
+</p>
</com:TContent>
\ No newline at end of file diff --git a/demos/quickstart/protected/pages/Controls/Expression.page b/demos/quickstart/protected/pages/Controls/Expression.page index c87f0ba4..80a45a3a 100644 --- a/demos/quickstart/protected/pages/Controls/Expression.page +++ b/demos/quickstart/protected/pages/Controls/Expression.page @@ -4,23 +4,14 @@ <com:DocLink ClassPath="System.Web.UI.WebControls.TExpression" />
<p>
-<tt>TExpression</tt> evaluates a PHP expression and displays the evaluation result. To specify the expression to be evaluated, set the <tt>Expression</tt> property. In a control template, <a href="?page=Configurations.Templates2#et">expression tags</a> are often used instead of the complete <a href="?page=Configurations.Templates1#ct">component tags</a> when the main purpose is to display the evaluation result of some PHP expression. For example, the following two tags are equivalent,
-</p>
-<com:TTextHighlighter Language="prado" CssClass="source">
-<com:TExpression Expression="date()" />
-<%= date() %>
-</com:TTextHighlighter>
-
-<p>
-<tt>TExpression</tt> evaluates the expression during the rendering control lifecycle.
+<tt>TExpression</tt> evaluates a PHP expression and displays the evaluation result. To specify the expression to be evaluated, set the <tt>Expression</tt> property. Note, <tt>TExpression</tt> evaluates the expression during the rendering control lifecycle.
</p>
<p>
-The context of the expression in a <tt>TExpression</tt> control is the control itself. That is, <tt>$this</tt> represents the control object if it is present in the expression. For example, both of the following template tags will display the title of the page containing the <tt>TExpression</tt> control.
+The context of the expression in a <tt>TExpression</tt> control is the control itself. That is, <tt>$this</tt> represents the control object if it is present in the expression. For example, the following template tag will display the title of the page containing the <tt>TExpression</tt> control.
</p>
<com:TTextHighlighter Language="prado" CssClass="source">
<com:TExpression Expression="$this->Page->Title" />
-<%= $this->Page->Title %>
</com:TTextHighlighter>
<p>
diff --git a/demos/quickstart/protected/pages/Controls/Samples/TDataGrid/Sample2.page b/demos/quickstart/protected/pages/Controls/Samples/TDataGrid/Sample2.page index 6de3063a..79c1890c 100644 --- a/demos/quickstart/protected/pages/Controls/Samples/TDataGrid/Sample2.page +++ b/demos/quickstart/protected/pages/Controls/Samples/TDataGrid/Sample2.page @@ -42,7 +42,7 @@ <com:TTemplateColumn>
<prop:HeaderTemplate>Rating</prop:HeaderTemplate>
<prop:ItemTemplate>
- <img src="images/star<%#$this->NamingContainer->DataItem['rating']%>.gif" alt="" />
+ <img src="images/star<%#$this->Parent->DataItem['rating']%>.gif" alt="" />
</prop:ItemTemplate>
</com:TTemplateColumn>
</com:TDataGrid>
diff --git a/demos/quickstart/protected/pages/Controls/Samples/TDataGrid/Sample2.php b/demos/quickstart/protected/pages/Controls/Samples/TDataGrid/Sample2.php index d40e3be3..a49077b5 100644 --- a/demos/quickstart/protected/pages/Controls/Samples/TDataGrid/Sample2.php +++ b/demos/quickstart/protected/pages/Controls/Samples/TDataGrid/Sample2.php @@ -78,6 +78,8 @@ class Sample2 extends TPage {
foreach($this->DataGrid->Columns as $index=>$column)
$column->Visible=$sender->Items[$index]->Selected;
+ $this->DataGrid->DataSource=$this->Data;
+ $this->DataGrid->dataBind();
}
}
diff --git a/demos/quickstart/protected/pages/Controls/Samples/TDataGrid/Sample6.page b/demos/quickstart/protected/pages/Controls/Samples/TDataGrid/Sample6.page index d2277bc5..3d1a33a8 100644 --- a/demos/quickstart/protected/pages/Controls/Samples/TDataGrid/Sample6.page +++ b/demos/quickstart/protected/pages/Controls/Samples/TDataGrid/Sample6.page @@ -6,6 +6,7 @@ <div style="width:500px">
<com:TDataGrid
ID="DataGrid"
+ Width="100%"
AllowPaging="true"
AllowCustomPaging="true"
VirtualItemCount="19"
diff --git a/demos/quickstart/protected/pages/Controls/Samples/TDataList/Sample1.page b/demos/quickstart/protected/pages/Controls/Samples/TDataList/Sample1.page index dee3a41c..25b7db81 100644 --- a/demos/quickstart/protected/pages/Controls/Samples/TDataList/Sample1.page +++ b/demos/quickstart/protected/pages/Controls/Samples/TDataList/Sample1.page @@ -26,7 +26,7 @@ Since the page is mainly for display and does not require user interactions, the <prop:FooterTemplate>
<div style="font-weight:bold; text-align:center;">
-Total <%# $this->Parent->Parent->ItemCount %> products.
+Total <%# $this->Parent->ItemCount %> products.
</div>
</prop:FooterTemplate>
@@ -36,10 +36,10 @@ Total <%# $this->Parent->Parent->ItemCount %> products. <th>ID</th><th>Name</th><th>Quantity</th><th>Price</th>
</tr>
<tr>
- <td align="right"><%#$this->Parent->DataItem['id'] %></td>
- <td align="right"><%#$this->Parent->DataItem['name'] %></td>
- <td align="right"><%#$this->Parent->DataItem['quantity'] %></td>
- <td align="right">$<%#$this->Parent->DataItem['price'] %></td>
+ <td align="right"><%#$this->DataItem['id'] %></td>
+ <td align="right"><%#$this->DataItem['name'] %></td>
+ <td align="right"><%#$this->DataItem['quantity'] %></td>
+ <td align="right">$<%#$this->DataItem['price'] %></td>
</tr>
</table>
</prop:ItemTemplate>
diff --git a/demos/quickstart/protected/pages/Controls/Samples/TDataList/Sample2.page b/demos/quickstart/protected/pages/Controls/Samples/TDataList/Sample2.page index 07980c49..4b484b21 100644 --- a/demos/quickstart/protected/pages/Controls/Samples/TDataList/Sample2.page +++ b/demos/quickstart/protected/pages/Controls/Samples/TDataList/Sample2.page @@ -29,7 +29,7 @@ Text=<%#$this->Parent->DataItem['id']%>
CommandName="select"
/>
- <%#$this->Parent->DataItem['name']%>
+ <%#$this->DataItem['name']%>
</td>
<td align="right">
<com:TLinkButton
@@ -52,10 +52,10 @@ <th>ID</th><th>Name</th><th>Quantity</th><th>Price</th>
</tr>
<tr>
- <td align="right"><%#$this->Parent->DataItem['id'] %></td>
- <td align="right"><%#$this->Parent->DataItem['name'] %></td>
- <td align="right"><%#$this->Parent->DataItem['quantity'] %></td>
- <td align="right">$<%#$this->Parent->DataItem['price'] %></td>
+ <td align="right"><%#$this->DataItem['id'] %></td>
+ <td align="right"><%#$this->DataItem['name'] %></td>
+ <td align="right"><%#$this->DataItem['quantity'] %></td>
+ <td align="right">$<%#$this->DataItem['price'] %></td>
</tr>
<tr>
<td colspan="4" align="right">
@@ -77,7 +77,7 @@ <table border="0" width="100%">
<tr>
<td align="right">ID</td>
- <td><b><%#$this->Parent->DataItem['id']%></b></td>
+ <td><b><%#$this->DataItem['id']%></b></td>
</tr>
<tr>
<td align="right">Name</td>
diff --git a/demos/quickstart/protected/pages/Controls/Samples/TExpression/Home.page b/demos/quickstart/protected/pages/Controls/Samples/TExpression/Home.page index 2273f3c1..8c736ca9 100644 --- a/demos/quickstart/protected/pages/Controls/Samples/TExpression/Home.page +++ b/demos/quickstart/protected/pages/Controls/Samples/TExpression/Home.page @@ -10,12 +10,6 @@ Using expression component tag: <com:TExpression Expression="$this->Page->Head->Title" />
</td></tr>
-<tr><td class="samplenote">
-Using shortcut expression tag:
-</td><td class="sampleaction">
-<%= $this->Page->PagePath %>
-</td></tr>
-
</table>
</com:TContent>
\ No newline at end of file diff --git a/demos/quickstart/protected/pages/Controls/Samples/TRepeater/Sample1.page b/demos/quickstart/protected/pages/Controls/Samples/TRepeater/Sample1.page index e28ef6fb..f519342d 100644 --- a/demos/quickstart/protected/pages/Controls/Samples/TRepeater/Sample1.page +++ b/demos/quickstart/protected/pages/Controls/Samples/TRepeater/Sample1.page @@ -17,21 +17,21 @@ <prop:ItemTemplate>
<tr style="background-color:#BFCFFF">
-<td><%#$this->Parent->DataItem['id']%></td>
-<td><%#$this->Parent->DataItem['name']%></td>
-<td><%#$this->Parent->DataItem['quantity']%></td>
-<td><%#$this->Parent->DataItem['price']%></td>
-<td><%#$this->Parent->DataItem['imported']?'Yes':'No'%></td>
+<td><%#$this->DataItem['id']%></td>
+<td><%#$this->DataItem['name']%></td>
+<td><%#$this->DataItem['quantity']%></td>
+<td><%#$this->DataItem['price']%></td>
+<td><%#$this->DataItem['imported']?'Yes':'No'%></td>
</tr>
</prop:ItemTemplate>
<prop:AlternatingItemTemplate>
<tr style="background-color:#E6ECFF">
-<td><%#$this->Parent->DataItem['id']%></td>
-<td><%#$this->Parent->DataItem['name']%></td>
-<td><%#$this->Parent->DataItem['quantity']%></td>
-<td><%#$this->Parent->DataItem['price']%></td>
-<td><%#$this->Parent->DataItem['imported']?'Yes':'No'%></td>
+<td><%#$this->DataItem['id']%></td>
+<td><%#$this->DataItem['name']%></td>
+<td><%#$this->DataItem['quantity']%></td>
+<td><%#$this->DataItem['price']%></td>
+<td><%#$this->DataItem['imported']?'Yes':'No'%></td>
</tr>
</prop:AlternatingItemTemplate>
diff --git a/demos/quickstart/protected/pages/Controls/Samples/TRepeater/Sample2.page b/demos/quickstart/protected/pages/Controls/Samples/TRepeater/Sample2.page index b939c586..ce0942c3 100644 --- a/demos/quickstart/protected/pages/Controls/Samples/TRepeater/Sample2.page +++ b/demos/quickstart/protected/pages/Controls/Samples/TRepeater/Sample2.page @@ -14,7 +14,7 @@ <prop:ItemTemplate>
<tr>
<com:TTableCell ID="Cell">
- <%#$this->NamingContainer->DataItem %>
+ <%#$this->DataItem %>
</com:TTableCell>
<td>
<com:TRepeater
@@ -29,13 +29,13 @@ <prop:ItemTemplate>
<com:TTableRow ID="Row">
<com:TTableCell Width="70px">
- <%#$this->NamingContainer->DataItem['name'] %>
+ <%#$this->DataItem['name'] %>
</com:TTableCell>
<com:TTableCell Width="20">
- <%#$this->NamingContainer->DataItem['age'] %>
+ <%#$this->DataItem['age'] %>
</com:TTableCell>
<com:TTableCell Width="150px">
- <%#$this->NamingContainer->DataItem['position'] %>
+ <%#$this->DataItem['position'] %>
</com:TTableCell>
</com:TTableRow>
</prop:ItemTemplate>
diff --git a/demos/quickstart/protected/pages/Controls/Samples/TRepeater/Sample3.page b/demos/quickstart/protected/pages/Controls/Samples/TRepeater/Sample3.page index fde06a36..38636962 100644 --- a/demos/quickstart/protected/pages/Controls/Samples/TRepeater/Sample3.page +++ b/demos/quickstart/protected/pages/Controls/Samples/TRepeater/Sample3.page @@ -69,12 +69,12 @@ The following example allows users to modify the existing tabular data using a < </prop:HeaderTemplate>
<prop:ItemTemplate>
-<tr style="<%# 'background-color:' . ($this->Parent->ItemIndex%2 ? '#BFCFFF' : '#E6ECFF') %>">
-<td><%#$this->Parent->DataItem['id']%></td>
-<td><%#$this->Parent->DataItem['name']%></td>
-<td><%#$this->Parent->DataItem['category']%></td>
-<td><%#$this->Parent->DataItem['price']%></td>
-<td><%#$this->Parent->DataItem['imported']?'Yes':'No'%></td>
+<tr style="<%# 'background-color:' . ($this->ItemIndex%2 ? '#BFCFFF' : '#E6ECFF') %>">
+<td><%#$this->DataItem['id']%></td>
+<td><%#$this->DataItem['name']%></td>
+<td><%#$this->DataItem['category']%></td>
+<td><%#$this->DataItem['price']%></td>
+<td><%#$this->DataItem['imported']?'Yes':'No'%></td>
</tr>
</prop:ItemTemplate>
diff --git a/demos/quickstart/protected/pages/Controls/Samples/TStatements/Home.page b/demos/quickstart/protected/pages/Controls/Samples/TStatements/Home.page index 66734ce0..d07bf159 100644 --- a/demos/quickstart/protected/pages/Controls/Samples/TStatements/Home.page +++ b/demos/quickstart/protected/pages/Controls/Samples/TStatements/Home.page @@ -15,15 +15,6 @@ Using TStatements component tag: </com:TStatements>
</td></tr>
-<tr><td class="samplenote">
-Using shortcut statements tag:
-</td><td class="sampleaction">
-<%%
- $uid=$this->UniqueID;
- echo "UniqueID is '$uid'.";
-%>
-</td></tr>
-
</table>
</com:TContent>
\ No newline at end of file diff --git a/demos/quickstart/protected/pages/Controls/Statements.page b/demos/quickstart/protected/pages/Controls/Statements.page index c6807738..dd26ec1b 100644 --- a/demos/quickstart/protected/pages/Controls/Statements.page +++ b/demos/quickstart/protected/pages/Controls/Statements.page @@ -4,34 +4,31 @@ <com:DocLink ClassPath="System.Web.UI.WebControls.TStatements" />
<p>
-<tt>TStatements</tt> evaluates a sequence of PHP statements and displays the content rendered by the statements. To specify the PHP statements to be evaluated, set the <tt>Statements</tt> property. In a control template, <a href="?page=Configurations.Templates2#st">statement tags</a> are often used instead of the complete <a href="?page=Configurations.Templates1#ct">component tags</a> when the main purpose is to display the result rendered by some PHP statements. For example, the following two tags are equivalent,
+<tt>TStatements</tt> evaluates a sequence of PHP statements and displays the content rendered by the statements. To specify the PHP statements to be evaluated, set the <tt>Statements</tt> property. For example, the following component tag displays the current time on the Web page,
</p>
<com:TTextHighlighter Language="prado" CssClass="source">
<com:TStatements>
- <prop:Expression>
+ <prop:Statements>
setlocale(LC_ALL, 'nl_NL');
echo strftime("%A %e %B %Y",time());
- </prop:Expression>
+ </prop:Statements>
</com:TStatements>
-
-<%%
- setlocale(LC_ALL, 'nl_NL');
- echo strftime("%A %e %B %Y",time());
-%>
</com:TTextHighlighter>
<p>
-<tt>TStatements</tt> evaluates the PHP statements during the rendering control lifecycle. Unlike <tt>TExpression</tt>, <tt>TStatements</tt> only displays the content 'echoed' within the statements.
+Note, <tt>TStatements</tt> evaluates the PHP statements during the rendering control lifecycle. Unlike <tt>TExpression</tt>, <tt>TStatements</tt> only displays the content 'echoed' within the statements.
</p>
<p>
The context of the statements in a <tt>TStatements</tt> control is the control itself. That is, <tt>$this</tt> represents the control object if it is present in the statements. For example, the following statement tag will display the title of the page containing the <tt>TStatements</tt> control.
</p>
<com:TTextHighlighter Language="prado" CssClass="source">
-<%%
+<com:TStatements>
+ <prop:Statements>
$page=$this->Page;
echo $page->Title;
-%>
+ </prop:Statements>
+</com:TStatements>
</com:TTextHighlighter>
<p>
diff --git a/framework/Web/UI/TControl.php b/framework/Web/UI/TControl.php index 52ec9bb1..15965a74 100644 --- a/framework/Web/UI/TControl.php +++ b/framework/Web/UI/TControl.php @@ -68,7 +68,7 @@ Prado::using('System.Web.UI.TControlAdapter'); * @package System.Web.UI
* @since 3.0
*/
-class TControl extends TApplicationComponent
+class TControl extends TApplicationComponent implements IRenderable, IBindable
{
/**
* format of control ID
@@ -772,7 +772,7 @@ class TControl extends TApplicationComponent if(isset($this->_rf[self::RF_CONTROLS]))
{
foreach($this->_rf[self::RF_CONTROLS] as $control)
- if($control instanceof TControl)
+ if($control instanceof IBindable)
$control->dataBind();
}
}
@@ -1416,10 +1416,12 @@ class TControl extends TApplicationComponent {
foreach($this->_rf[self::RF_CONTROLS] as $control)
{
- if($control instanceof TControl)
- $control->renderControl($writer);
- else if(is_string($control))
+ if(is_string($control))
$writer->write($control);
+ else if($control instanceof TControl)
+ $control->renderControl($writer);
+ else if($control instanceof IRenderable)
+ $control->render($writer);
}
}
}
@@ -1660,13 +1662,13 @@ class TControlCollection extends TList */
public function insertAt($index,$item)
{
- if(is_string($item))
- parent::insertAt($index,$item);
- else if($item instanceof TControl)
+ if($item instanceof TControl)
{
parent::insertAt($index,$item);
$this->_o->addedControl($item);
}
+ else if(is_string($item) || ($item instanceof IRenderable))
+ parent::insertAt($index,$item);
else
throw new TInvalidDataTypeException('controlcollection_control_required');
}
diff --git a/framework/Web/UI/TTemplateManager.php b/framework/Web/UI/TTemplateManager.php index 26cc9c3a..fa4cbcbf 100644 --- a/framework/Web/UI/TTemplateManager.php +++ b/framework/Web/UI/TTemplateManager.php @@ -126,8 +126,7 @@ class TTemplateManager extends TModule * can be a property name, an event name or a regular tag attribute name.
* - directive: directive specifies the property values for the template owner.
* It is in the format of <% property name-value pairs %>
- * - expressions: expressions are shorthand of {@link TExpression} and {@link TStatements}
- * controls. They are in the formate of <= PHP expression > and < PHP statements >
+ * - expressions: They are in the formate of <= PHP expression > and <% PHP statements >
* - comments: There are two kinds of comments, regular HTML comments and special template comments.
* The former is in the format of <!-- comments -->, which will be treated as text strings.
* The latter is in the format of <%* comments %>, which will be stripped out.
@@ -310,7 +309,16 @@ class TTemplate extends TApplicationComponent implements ITemplate }
}
else // string
- $parent->addParsedObject($object[1]);
+ {
+ if($object[1] instanceof TCompositeLiteral)
+ {
+ $o=clone $object[1];
+ $o->setContainer($tplControl);
+ $parent->addParsedObject($o);
+ }
+ else
+ $parent->addParsedObject($object[1]);
+ }
}
}
@@ -388,8 +396,7 @@ class TTemplate extends TApplicationComponent implements ITemplate $component->$setter($this->getApplication()->getParameters()->itemAt($value[1]));
break;
case self::CONFIG_LOCALIZATION:
- Prado::using('System.I18N.Translation');
- $component->$setter(localize(trim($value[1])));
+ $component->$setter(Prado::localize($value[1]));
break;
default: // an error if reaching here
break;
@@ -532,12 +539,22 @@ class TTemplate extends TApplicationComponent implements ITemplate if($matchStart>$textStart)
$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
$textStart=$matchEnd+1;
+ $literal=trim(THttpUtility::htmlDecode($match[5][0]));
if($str[2]==='=') // expression
- $tpl[$c++]=array($container,'TExpression',array('Expression'=>THttpUtility::htmlDecode($match[5][0])));
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,$literal));
else if($str[2]==='%') // statements
- $tpl[$c++]=array($container,'TStatements',array('Statements'=>THttpUtility::htmlDecode($match[5][0])));
- else
- $tpl[$c++]=array($container,'TLiteral',array('Text'=>$this->parseAttribute($str)));
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_STATEMENTS,$literal));
+ else if($str[2]==='#')
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_DATABINDING,$literal));
+ else if($str[2]==='$')
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->getApplication()->getParameters()->itemAt('$literal')"));
+ else if($str[2]==='~')
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->publishFilePath('$this->_contextPath/$literal')"));
+ else if($str[2]==='[')
+ {
+ $literal=trim(substr($literal,0,strlen($literal)-1));
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"Prado::localize('$literal')"));
+ }
}
else if(strpos($str,'<prop:')===0) // opening property
{
@@ -618,7 +635,45 @@ class TTemplate extends TApplicationComponent implements ITemplate else
throw new TConfigurationException('template_format_invalid',$this->_tplFile,$line,$e->getMessage());
}
- return $tpl;
+
+ // optimization by merging consecutive strings, expressions, statements and bindings
+ $objects=array();
+ $parent=null;
+ $merged=array();
+ foreach($tpl as $id=>$object)
+ {
+ if(isset($object[2]) || $object[0]!==$parent)
+ {
+ if($parent!==null)
+ {
+ if(count($merged[1])===1 && is_string($merged[1][0]))
+ $objects[$id-1]=array($merged[0],$merged[1][0]);
+ else
+ $objects[$id-1]=array($merged[0],new TCompositeLiteral($merged[1]));
+ }
+ if(isset($object[2]))
+ {
+ $parent=null;
+ $objects[$id]=$object;
+ }
+ else
+ {
+ $parent=$object[0];
+ $merged=array($parent,array($object[1]));
+ }
+ }
+ else
+ $merged[1][]=$object[1];
+ }
+ if($parent!==null)
+ {
+ if(count($merged[1])===1 && is_string($merged[1][0]))
+ $objects[$id]=array($merged[0],$merged[1][0]);
+ else
+ $objects[$id]=array($merged[0],new TCompositeLiteral($merged[1]));
+ }
+ $tpl=$objects;
+ return $objects;
}
/**
@@ -768,4 +823,95 @@ class TTemplate extends TApplicationComponent implements ITemplate }
}
+/**
+ * TCompositeLiteral class
+ *
+ * TCompositeLiteral is used internally by {@link TTemplate} for representing
+ * consecutive static strings, expressions and statements.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Revision: $ $Date: $
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TCompositeLiteral extends TComponent implements IRenderable, IBindable
+{
+ const TYPE_EXPRESSION=0;
+ const TYPE_STATEMENTS=1;
+ const TYPE_DATABINDING=2;
+ private $_container=null;
+ private $_items=array();
+ private $_expressions=array();
+ private $_statements=array();
+ private $_bindings=array();
+
+ /**
+ * Constructor.
+ * @param array list of items to be represented by TCompositeLiteral
+ */
+ public function __construct($items)
+ {
+ $this->_items=array();
+ $this->_expressions=array();
+ $this->_statements=array();
+ foreach($items as $id=>$item)
+ {
+ if(is_array($item))
+ {
+ if($item[0]===self::TYPE_EXPRESSION)
+ $this->_expressions[$id]=$item[1];
+ else if($item[0]===self::TYPE_STATEMENTS)
+ $this->_statements[$id]=$item[1];
+ else if($item[0]===self::TYPE_DATABINDING)
+ $this->_bindings[$id]=$item[1];
+ $this->_items[$id]='';
+ }
+ else
+ $this->_items[$id]=$item;
+ }
+ }
+
+ /**
+ * @return TComponent container of this component. It serves as the evaluation context of expressions and statements.
+ */
+ public function getContainer()
+ {
+ return $this->_container;
+ }
+
+ /**
+ * @param TComponent container of this component. It serves as the evaluation context of expressions and statements.
+ */
+ public function setContainer(TComponent $value)
+ {
+ $this->_container=$value;
+ }
+
+ /**
+ * Renders the content stored in this component.
+ * This method is required by {@link IRenderable}
+ * @param ITextWriter
+ */
+ public function render($writer)
+ {
+ $context=$this->_container===null?$this:$this->_container;
+ foreach($this->_expressions as $id=>$expression)
+ $this->_items[$id]=$context->evaluateExpression($expression);
+ foreach($this->_statements as $id=>$statement)
+ $this->_items[$id]=$context->evaluateStatements($statement);
+ $writer->write(implode('',$this->_items));
+ }
+
+ /**
+ * Performs databindings.
+ * This method is required by {@link IBindable}
+ */
+ public function dataBind()
+ {
+ $context=$this->_container===null?$this:$this->_container;
+ foreach($this->_bindings as $id=>$binding)
+ $this->_items[$id]=$context->evaluateExpression($binding);
+ }
+}
+
?>
\ No newline at end of file diff --git a/framework/interfaces.php b/framework/interfaces.php index ca5c77bb..2a407696 100644 --- a/framework/interfaces.php +++ b/framework/interfaces.php @@ -242,4 +242,42 @@ interface ICacheDependency public function getHasChanged();
}
+/**
+ * IRenderable interface.
+ *
+ * This interface must be implemented by classes that can be rendered
+ * to end-users.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Revision: $ $Date: $
+ * @package System
+ * @since 3.0
+ */
+interface IRenderable
+{
+ /**
+ * Renders the component to end-users.
+ * @param ITextWriter writer for the rendering purpose
+ */
+ public function render($writer);
+}
+
+/**
+ * IBindable interface.
+ *
+ * This interface must be implemented by classes that are capable of performing databinding.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Revision: $ $Date: $
+ * @package System
+ * @since 3.0
+ */
+interface IBindable
+{
+ /**
+ * Performs databinding.
+ */
+ public function dataBind();
+}
+
?>
\ No newline at end of file diff --git a/tests/FunctionalTests/quickstart/Controls/DataGrid3TestCase.php b/tests/FunctionalTests/quickstart/Controls/DataGrid3TestCase.php index 095d455a..b92cc9f5 100644 --- a/tests/FunctionalTests/quickstart/Controls/DataGrid3TestCase.php +++ b/tests/FunctionalTests/quickstart/Controls/DataGrid3TestCase.php @@ -15,7 +15,7 @@ class DataGrid3TestCase extends SeleniumTestCase //$this->verifyElementPresent("//img[@src='images/star5.gif']",'');
// edit the 2nd row
- $this->clickAndWait("id=ctl0_body_DataGrid_ctl2_ctl9", "");
+ $this->clickAndWait("id=ctl0_body_DataGrid_ctl2_ctl8", "");
$this->type("ctl0\$body\$DataGrid\$ctl2\$ctl7", "Design Pattern: Elements of Reusable Object-Oriented Software");
$this->type("ctl0\$body\$DataGrid\$ctl2\$ctl8", "Addison Wesley Professional");
$this->type("ctl0\$body\$DataGrid\$ctl2\$ctl9", "\$57.04");
@@ -32,18 +32,18 @@ class DataGrid3TestCase extends SeleniumTestCase //$this->verifyElementPresent("//img[@src='images/star1.gif']",'');
// verify cancel editting the 3rd row
- $this->clickAndWait("id=ctl0_body_DataGrid_ctl3_ctl9", "");
+ $this->clickAndWait("id=ctl0_body_DataGrid_ctl3_ctl8", "");
$this->clickAndWait("link=Cancel", "");
$this->verifyTextPresent("Design Patterns Explained : A New Perspective on Object-Oriented Design", "");
// verify deleting
- $this->clickAndWait("id=ctl0_body_DataGrid_ctl3_ctl10", "");
+ $this->clickAndWait("id=ctl0_body_DataGrid_ctl3_ctl9", "");
$this->verifyConfirmation("Are you sure?");
$this->verifyTextNotPresent("Design Patterns Explained : A New Perspective on Object-Oriented Design", "");
$this->verifyTextPresent("Extreme Programming Explained : Embrace Change",'');
$this->chooseCancelOnNextConfirmation();
- $this->click("id=ctl0_body_DataGrid_ctl5_ctl10", "");
+ $this->click("id=ctl0_body_DataGrid_ctl6_ctl9", "");
$this->verifyConfirmation("Are you sure?");
$this->verifyTextPresent("Extreme Programming Explained : Embrace Change",'');
}
diff --git a/tests/FunctionalTests/quickstart/Controls/DataList2TestCase.php b/tests/FunctionalTests/quickstart/Controls/DataList2TestCase.php index e29aabc8..9b6e98d2 100644 --- a/tests/FunctionalTests/quickstart/Controls/DataList2TestCase.php +++ b/tests/FunctionalTests/quickstart/Controls/DataList2TestCase.php @@ -19,7 +19,7 @@ class DataList2TestCase extends SeleniumTestCase $this->verifyTextPresent("\$150", "");
// verify editting an item
- $this->clickAndWait("id=ctl0_body_DataList_ctl5_ctl4", "");
+ $this->clickAndWait("id=ctl0_body_DataList_ctl5_ctl0", "");
$this->type("ctl0\$body\$DataList\$ctl5\$ProductQuantity", "11");
$this->type("ctl0\$body\$DataList\$ctl5\$ProductPrice", "140.99");
$this->click("//input[@name='ctl0\$body\$DataList\$ctl5\$ProductImported' and @value='ctl0\$body\$DataList\$ctl5\$ProductImported']", "");
@@ -31,7 +31,7 @@ class DataList2TestCase extends SeleniumTestCase $this->verifyTextPresent("11", "");
// verify editting another item
- $this->clickAndWait("id=ctl0_body_DataList_ctl3_ctl2", "");
+ $this->clickAndWait("id=ctl0_body_DataList_ctl3_ctl1", "");
$this->type("ctl0\$body\$DataList\$ctl3\$ProductName", "Hard Drive");
$this->type("ctl0\$body\$DataList\$ctl3\$ProductQuantity", "23");
$this->click("//input[@name='ctl0\$body\$DataList\$ctl3\$ProductImported' and @value='ctl0\$body\$DataList\$ctl3\$ProductImported']", "");
@@ -43,10 +43,10 @@ class DataList2TestCase extends SeleniumTestCase $this->verifyTextPresent("Harddrive ", "");
// verify item deletion
- $this->clickAndWait("id=ctl0_body_DataList_ctl3_ctl5", "");
+ $this->clickAndWait("id=ctl0_body_DataList_ctl3_ctl1", "");
$this->verifyConfirmation("Are you sure?");
$this->chooseCancelOnNextConfirmation();
- $this->click("id=ctl0_body_DataList_ctl5_ctl3", "");
+ $this->click("id=ctl0_body_DataList_ctl5_ctl2", "");
$this->verifyConfirmation("Are you sure?");
$this->verifyTextPresent("Motherboard ", "");
$this->verifyTextPresent("CPU ", "");
|