summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxue <>2006-04-15 14:35:46 +0000
committerxue <>2006-04-15 14:35:46 +0000
commit70944795827cffd1bd5a27a9c4a99eb1434f905f (patch)
tree8c77df484074d8a104a4646a4e2fa6c051324ed4
parent3ba2c4fbc3a5e07d3f51dc2a89e9eed24b9f2a16 (diff)
Merge from branch 3.0 till 913.
-rw-r--r--HISTORY7
-rw-r--r--UPGRADE10
-rw-r--r--buildscripts/texbuilder/build.php7
-rw-r--r--demos/composer/protected/pages/ClassDefinition.php15
-rw-r--r--demos/composer/protected/pages/Home.page38
-rw-r--r--demos/personal/protected/Pages/Home.page2
-rw-r--r--demos/quickstart/protected/pages/Configurations/Templates2.page2
-rw-r--r--demos/quickstart/protected/pages/Configurations/Templates3.page28
-rw-r--r--demos/quickstart/protected/pages/Controls/Samples/TDataGrid/Sample3.page4
-rw-r--r--demos/quickstart/protected/pages/Controls/Samples/TDataList/Sample2.page10
-rw-r--r--demos/quickstart/protected/pages/Controls/Samples/TRepeater/Sample3.page6
-rw-r--r--demos/quickstart/protected/pages/Controls/Samples/TTextBox/Home.page2
-rw-r--r--demos/quickstart/protected/pages/Fundamentals/Modules.page2
-rw-r--r--framework/Exceptions/messages.txt2
-rw-r--r--framework/Web/UI/TControl.php143
-rw-r--r--framework/Web/UI/TTemplateManager.php105
-rw-r--r--framework/Web/UI/WebControls/TRepeater.php52
17 files changed, 288 insertions, 147 deletions
diff --git a/HISTORY b/HISTORY
index bb534a9f..a316ad36 100644
--- a/HISTORY
+++ b/HISTORY
@@ -10,13 +10,20 @@ NEW: SQLMap (Wei)
Version 3.0RC2 April 16, 2006
=============================
+BUG: Ticket#54 - recursive reverse() definition (Wei)
+BUG: Ticket#93 - ValidationGroup not working in TImageMap for js validator (Wei)
+BUG: Ticket#97 - Invalid return type value for TSimpleDateFormatter::parse (Wei)
BUG: Ticket#118 - Variables that may not have been initialized (Qiang)
+BUG: Ticket#121 - OnClick don't fire with TImageButton and TRequiredFieldValidator (Wei)
BUG: Ticket#129 - TRadioButtonList in TWizard step does not postback correctly (Qiang)
CHG: Moved localize() into PradoBase (Qiang)
CHG: List controls now use array keys as list item values even if the array is integer-indexed (Qiang)
CHG: THttpUtility::htmlEncode and htmlDecode now do not deal with & (Qiang)
+CHG: Expressions appeared in a template are evaluated in PreRender stage (Qiang)
+CHG: The context of expressions appeared in a template is changed to the template control (Qiang)
ENH: Optimized the representation and evaluation of template expressions (Qiang)
ENH: Added Raw layout to TDataList (Qiang)
+ENH: Added TRepeater.DataKeys and TRepeater.DataKeyField (Qiang)
Version 3.0RC1 April 5, 2006
============================
diff --git a/UPGRADE b/UPGRADE
index b7bbd35b..b9213eb8 100644
--- a/UPGRADE
+++ b/UPGRADE
@@ -16,9 +16,13 @@ for both A and B.
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.
+- !!! Expressions appeared in a template are now evaluated in PreRender
+ stage. Previously, for template expressions, they are evaluated during
+ rendering stage, while for property expressions, they are done right
+ after the controls are constructed.
+- !!! The context of the expressions appeared in a template is changed
+ to the template control. Previously, it is the component/control
+ associated with the expression.
- !!! List controls databound with integer-indexed arrays will have
the integers as their list item values. Previously, it used the array
values as the list item values.
diff --git a/buildscripts/texbuilder/build.php b/buildscripts/texbuilder/build.php
index d1d6cac5..7395406c 100644
--- a/buildscripts/texbuilder/build.php
+++ b/buildscripts/texbuilder/build.php
@@ -202,6 +202,7 @@ function parse_html($page,$html)
$html = preg_replace('/<\/com:TTextHighlighter>/', '`2`', $html);
$html = preg_replace_callback('/(`1`)([^`]*)(`2`)/m', 'escape_verbatim', $html);
$html = preg_replace_callback('/(<div class="source">)([^<]*)(<\/div>)/', 'escape_verbatim', $html);
+ $html = preg_replace_callback('/(<pre>)([^<]*)(<\/pre>)/', 'escape_verbatim', $html);
//<code>
$html = preg_replace_callback('/<code>([^<]*)<\/code>/', 'escape_verb', $html);
@@ -210,7 +211,11 @@ function parse_html($page,$html)
//runbar
$html = preg_replace('/<com:RunBar\s+PagePath="([^"]*)"\s+\/>/',
- 'Try, \href{http://www.pradosoft.com/demos/quickstart/index.php?page=$1}{$1}', $html);
+ '\href{http://www.pradosoft.com/demos/quickstart/index.php?page=$1}{$1 Demo}', $html);
+
+ //DocLink
+ $html = preg_replace('/<com:DocLink\s+ClassPath="([^"]*)[.]([^.]*)"\s+\/>/',
+ '\href{http://www.pradosoft.com/docs/manual/$1/$2.html}{$1.$2 API Reference}', $html);
//text modifiers
$html = preg_replace('/<b>([^<]*)<\/b>/', '\textbf{$1}', $html);
diff --git a/demos/composer/protected/pages/ClassDefinition.php b/demos/composer/protected/pages/ClassDefinition.php
index bd704b0e..cb657e85 100644
--- a/demos/composer/protected/pages/ClassDefinition.php
+++ b/demos/composer/protected/pages/ClassDefinition.php
@@ -36,8 +36,8 @@ class ClassDefinition extends TComponent
if($this->Comments!=='')
{
$str.=" *\n";
- $str.=implode("\n * ",explode("\n",wordwrap($this->Comments)));
- $str.=" *\n\n";
+ $str.=" * ".implode("\n * ",explode("\n",wordwrap($this->Comments)));
+ $str.="\n *\n";
}
if($this->Author!=='')
{
@@ -171,9 +171,18 @@ class ClassDefinition extends TComponent
$name=$event->Name;
if($name==='')
continue;
+ if(strncasecmp($name,'on',2)!==0)
+ $name='On'.$name;
+ else
+ {
+ $name[0]='O';
+ $name[1]='n';
+ }
+ $methodName=$name;
+ $methodName[0]='o';
$comments=implode("\n\t * ",explode("\n",wordwrap($event->Comments)));
$writer->write("\n\t/**\n\t * Raises <b>$name</b> event.\n\t * $comments\n\t * @param TEventParameter event parameter\n\t */\n");
- $writer->write("\tpublic function $name(\$param)\n\t{\n\t\t\$this->raiseEvent('$name',\$this,\$param);\n\t}\n");
+ $writer->write("\tpublic function $methodName(\$param)\n\t{\n\t\t\$this->raiseEvent('$name',\$this,\$param);\n\t}\n");
}
}
diff --git a/demos/composer/protected/pages/Home.page b/demos/composer/protected/pages/Home.page
index efdd1cda..51aaed8e 100644
--- a/demos/composer/protected/pages/Home.page
+++ b/demos/composer/protected/pages/Home.page
@@ -40,10 +40,10 @@ No properties defined.<br/>
<prop:ItemTemplate>
<tr>
<td>
- <com:TTextBox ID="PropertyName" Text=<%# $this->Parent->DataItem->Name %> CssClass="slTextBox"/>
+ <com:TTextBox ID="PropertyName" Text=<%# $this->DataItem->Name %> CssClass="slTextBox"/>
</td>
<td>
- <com:TDropDownList ID="PropertyType" SelectedValue=<%# $this->Parent->DataItem->Type %> >
+ <com:TDropDownList ID="PropertyType" SelectedValue=<%# $this->DataItem->Type %> >
<com:TListItem Text="string" />
<com:TListItem Text="integer" />
<com:TListItem Text="boolean" />
@@ -53,41 +53,41 @@ No properties defined.<br/>
</com:TDropDownList>
</td>
<td>
- <com:TTextBox ID="DefaultValue" Text=<%# $this->Parent->DataItem->DefaultValue %> CssClass="slTextBox"/>
+ <com:TTextBox ID="DefaultValue" Text=<%# $this->DataItem->DefaultValue %> CssClass="slTextBox"/>
</td>
<td>
- <com:TDropDownList ID="Storage" SelectedValue=<%# $this->Parent->DataItem->Storage %> >
+ <com:TDropDownList ID="Storage" SelectedValue=<%# $this->DataItem->Storage %> >
<com:TListItem Text="ViewState" />
<com:TListItem Text="ControlState" />
<com:TListItem Text="Memory" />
</com:TDropDownList>
</td>
<td>
- <com:TCheckBox ID="IsProtected" Text="protected" Checked=<%# $this->Parent->DataItem->IsProtected %> />
- <com:TCheckBox ID="ReadOnly" Text="read-only" Checked=<%# $this->Parent->DataItem->ReadOnly %> />
+ <com:TCheckBox ID="IsProtected" Text="protected" Checked=<%# $this->DataItem->IsProtected %> />
+ <com:TCheckBox ID="ReadOnly" Text="read-only" Checked=<%# $this->DataItem->ReadOnly %> />
</td>
<td>
- <com:TTextBox ID="Comments" Text=<%# $this->Parent->DataItem->Comments %> CssClass="slTextBox"/>
+ <com:TTextBox ID="Comments" Text=<%# $this->DataItem->Comments %> CssClass="slTextBox"/>
</td>
<td>
<com:TButton
Text="Remove"
CommandName="remove"
- CommandParameter=<%# $this->Parent->ItemIndex %>
+ CommandParameter=<%# $this->ItemIndex %>
CssClass="button"
/>
<com:TButton
Text="Up"
CommandName="up"
- CommandParameter=<%# $this->Parent->ItemIndex %>
- Enabled=<%# $this->Parent->ItemIndex > 0%>
+ CommandParameter=<%# $this->ItemIndex %>
+ Enabled=<%# $this->ItemIndex > 0%>
CssClass="button"
/>
<com:TButton
Text="Down"
CommandName="down"
- CommandParameter=<%# $this->Parent->ItemIndex %>
- Enabled=<%# $this->Parent->ItemIndex < $this->Page->ClassDefinition->Properties->Count-1 %>
+ CommandParameter=<%# $this->ItemIndex %>
+ Enabled=<%# $this->ItemIndex < $this->Page->ClassDefinition->Properties->Count-1 %>
CssClass="button"
/>
</td>
@@ -123,30 +123,30 @@ No properties defined.<br/>
<prop:ItemTemplate>
<tr>
<td>
- <com:TTextBox ID="EventName" Text=<%# $this->Parent->DataItem->Name %> CssClass="slTextBox"/>
+ <com:TTextBox ID="EventName" Text=<%# $this->DataItem->Name %> CssClass="slTextBox"/>
</td>
<td>
- <com:TTextBox ID="Comments" Text=<%# $this->Parent->DataItem->Comments %> CssClass="slTextBox"/>
+ <com:TTextBox ID="Comments" Text=<%# $this->DataItem->Comments %> CssClass="slTextBox"/>
</td>
<td>
<com:TButton
Text="Remove"
CommandName="remove"
- CommandParameter=<%# $this->Parent->ItemIndex %>
+ CommandParameter=<%# $this->ItemIndex %>
CssClass="button"
/>
<com:TButton
Text="Up"
CommandName="up"
- CommandParameter=<%# $this->Parent->ItemIndex %>
- Enabled=<%# $this->Parent->ItemIndex > 0%>
+ CommandParameter=<%# $this->ItemIndex %>
+ Enabled=<%# $this->ItemIndex > 0%>
CssClass="button"
/>
<com:TButton
Text="Down"
CommandName="down"
- CommandParameter=<%# $this->Parent->ItemIndex %>
- Enabled=<%# $this->Parent->ItemIndex < $this->Page->ClassDefinition->Events->Count-1 %>
+ CommandParameter=<%# $this->ItemIndex %>
+ Enabled=<%# $this->ItemIndex < $this->Page->ClassDefinition->Events->Count-1 %>
CssClass="button"
/>
</td>
diff --git a/demos/personal/protected/Pages/Home.page b/demos/personal/protected/Pages/Home.page
index 204d4c6f..32a3b1b2 100644
--- a/demos/personal/protected/Pages/Home.page
+++ b/demos/personal/protected/Pages/Home.page
@@ -1,3 +1,5 @@
<com:TContent ID="main">
main content
+<com:TTextBox ID="TextBox" /><com:TButton Text="Submit" />
+<com:TLiteral Text=<%=$this->TextBox->Text %> />
</com:TContent> \ No newline at end of file
diff --git a/demos/quickstart/protected/pages/Configurations/Templates2.page b/demos/quickstart/protected/pages/Configurations/Templates2.page
index 0971c828..9fc06fb4 100644
--- a/demos/quickstart/protected/pages/Configurations/Templates2.page
+++ b/demos/quickstart/protected/pages/Configurations/Templates2.page
@@ -10,7 +10,7 @@ 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. The context (namely <tt>$this</tt>) of the expression is the control owning the template.
+An expression tag represents a PHP expression that is evaluated when the template control is in <tt>PreRender</tt> stage. 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,
diff --git a/demos/quickstart/protected/pages/Configurations/Templates3.page b/demos/quickstart/protected/pages/Configurations/Templates3.page
index d08f8736..b97b1583 100644
--- a/demos/quickstart/protected/pages/Configurations/Templates3.page
+++ b/demos/quickstart/protected/pages/Configurations/Templates3.page
@@ -5,11 +5,13 @@
<h2>Dynamic Property Tags</h2>
<p>
Dynamic property tags are very similar to dynamic content tags, except that they are applied to component properties. The purpose of dynamic property tags is to allow more versatile component property configuration. Note, you are not required to use dynamic property tags because what can be done using dynamic property tags can also be done in PHP code. However, using dynamic property tags bring you much more convenience at accomplishing the same tasks. The basic usage of dynamic property tags is as follows,
+</p>
<com:TTextHighlighter Language="prado" CssClass="source">
&lt;com:ComponentType PropertyName=DynamicPropertyTag ...&gt;
body content
&lt;/com:ComponentType&gt;
</com:TTextHighlighter>
+<p>
where you may enclose <tt>DynamicPropertyTag</tt> within single or double quotes for better readability.
</p>
<p>
@@ -19,51 +21,54 @@ Like dynamic content tags, we have <a href="#et">expression tags</a>, <a href="#
<a name="et"></a>
<h3>Expression Tags</h3>
<p>
-An expression tag represents a PHP expression that is evaluated when the template is being instantiated. The expression evaluation result is assigned to the corresponding component property. The format of expression tags is as follows,
+An expression tag represents a PHP expression that is evaluated when the control is in <tt>PreRender</tt> stage. The expression evaluation result is assigned to the corresponding component property. The format of expression tags is as follows,
+</p>
<com:TTextHighlighter Language="prado" CssClass="source">
&lt;%= PhpExpression %&gt;
</com:TTextHighlighter>
-In the expression, <tt>$this</tt> refers to the component specified by the component tag. The following example specifies a <tt>TLabel</tt> control whose <tt>Text</tt> property is initialized as the current page title when the <tt>TLabel</tt> control is being constructed,
+<p>
+In the expression, <tt>$this</tt> refers to the control owning the template. The following example specifies a <tt>TLabel</tt> control whose <tt>Text</tt> property is initialized as the current page title when the <tt>TLabel</tt> control is being constructed,
+</p>
<com:TTextHighlighter Language="prado" CssClass="source">
&lt;com:TLabel Text=&lt;%= $this-&gt;Page-&gt;Title %&gt; /&gt;
</com:TTextHighlighter>
-</p>
-<p>
-Note, unlike dynamic content tags, the expressions tags for component properties are evaluated when the components are being constructed, while for the dynamic content tags, the expressions are evaluated when the controls are being rendered.
-</p>
<a name="dt"></a>
<h3>Databind Tags</h3>
<p>
-Databind tags are similar to expression tags, except that they can only be used with control properties and the expressions are evaluated only when a <tt>dataBind()</tt> call is invoked on the controls represented by the component tags. In the expression, <tt>$this</tt> refers to the control itself. Databind tags do not apply to all components. They can only be used for controls.
+Databind tags are similar to expression tags, except that they can only be used with control properties and the expressions are evaluated only when a <tt>dataBind()</tt> call is invoked on the controls represented by the component tags. In the expression, <tt>$this</tt> refers to the control owning the template. Databind tags do not apply to all components. They can only be used for controls.
</p>
<p>
The format of databind tags is as follows,
+</p>
<com:TTextHighlighter Language="prado" CssClass="source">
&lt;%# PhpExpression %&gt;
</com:TTextHighlighter>
-</p>
<a name="pt"></a>
<h3>Parameter Tags</h3>
<p>
Parameter tags are used to assign application parameter values to the corresponding component properties. The format of parameter tags is as follows,
+</p>
<com:TTextHighlighter Language="prado" CssClass="source">
&lt;%$ ParameterName %&gt;
</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>
<a name="at"></a>
<h3>Asset Tags</h3>
<p>
-Asset tags are used to publish private files and assign the corresponding the URLs to the component properties. For example, if you have an image file that is not Web-accessible and you want to make it visible to end-users, you can use asset tags to publish this file and show the URL to end-users so that they can fetch the published image.
+Asset tags are used to publish private files and assign the corresponding the URLs to the component properties. For example, if you have an image file that is not Web-accessible and you want to make it visible to end-users, you can use asset tags to publish this file and show the URL to end-users so that they can fetch the published image. The asset tags are evaluated when the template is instantiated.
</p>
<p>
The format of asset tags is as follows,
+</p>
<com:TTextHighlighter Language="prado" CssClass="source">
&lt;%~ LocalFileName %&gt;
</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>
@@ -74,9 +79,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">
&lt;%[string]%&gt;
</com:TTextHighlighter>
-where <tt>string</tt> will be translated to different languages according to the end-user's language preference.
+<p>
+where <tt>string</tt> will be translated to different languages according to the end-user's language preference. The localization tags are evaluated when the template is instantiated.
+</p>
</com:TContent> \ No newline at end of file
diff --git a/demos/quickstart/protected/pages/Controls/Samples/TDataGrid/Sample3.page b/demos/quickstart/protected/pages/Controls/Samples/TDataGrid/Sample3.page
index be2f80bc..2864de46 100644
--- a/demos/quickstart/protected/pages/Controls/Samples/TDataGrid/Sample3.page
+++ b/demos/quickstart/protected/pages/Controls/Samples/TDataGrid/Sample3.page
@@ -48,11 +48,11 @@
/>
<com:TTemplateColumn HeaderText="Rating">
<prop:ItemTemplate>
- <img src="images/star<%#$this->NamingContainer->DataItem['rating']%>.gif" alt="" />
+ <img src="images/star<%#$this->Parent->DataItem['rating']%>.gif" alt="" />
</prop:ItemTemplate>
<prop:EditItemTemplate>
<com:TDropDownList
- SelectedValue=<%#$this->NamingContainer->DataItem['rating'] %>
+ SelectedValue=<%#$this->Parent->DataItem['rating'] %>
ID="Rating">
<com:TListItem Value="1" />
<com:TListItem Value="2" />
diff --git a/demos/quickstart/protected/pages/Controls/Samples/TDataList/Sample2.page b/demos/quickstart/protected/pages/Controls/Samples/TDataList/Sample2.page
index 4b484b21..a0908f60 100644
--- a/demos/quickstart/protected/pages/Controls/Samples/TDataList/Sample2.page
+++ b/demos/quickstart/protected/pages/Controls/Samples/TDataList/Sample2.page
@@ -26,7 +26,7 @@
<tr>
<td>
<com:TLinkButton
- Text=<%#$this->Parent->DataItem['id']%>
+ Text=<%#$this->DataItem['id']%>
CommandName="select"
/>
<%#$this->DataItem['name']%>
@@ -83,7 +83,7 @@
<td align="right">Name</td>
<td><com:TTextBox
ID="ProductName"
- Text=<%#$this->Parent->DataItem['name'] %>
+ Text=<%#$this->DataItem['name'] %>
/>
</td>
</tr>
@@ -91,7 +91,7 @@
<td align="right">Quantity</td>
<td><com:TTextBox
ID="ProductQuantity"
- Text=<%#$this->Parent->DataItem['quantity'] %>
+ Text=<%#$this->DataItem['quantity'] %>
/>
</td>
</tr>
@@ -99,7 +99,7 @@
<td align="right">Price</td>
<td><com:TTextBox
ID="ProductPrice"
- Text=<%#$this->Parent->DataItem['price'] %>
+ Text=<%#$this->DataItem['price'] %>
/>
</td>
</tr>
@@ -107,7 +107,7 @@
<td align="right">Imported</td>
<td><com:TCheckBox
ID="ProductImported"
- Checked=<%#$this->Parent->DataItem['imported'] %>
+ Checked=<%#$this->DataItem['imported'] %>
/>
</td>
</tr>
diff --git a/demos/quickstart/protected/pages/Controls/Samples/TRepeater/Sample3.page b/demos/quickstart/protected/pages/Controls/Samples/TRepeater/Sample3.page
index 38636962..4b6849e9 100644
--- a/demos/quickstart/protected/pages/Controls/Samples/TRepeater/Sample3.page
+++ b/demos/quickstart/protected/pages/Controls/Samples/TRepeater/Sample3.page
@@ -19,7 +19,7 @@ The following example allows users to modify the existing tabular data using a <
<td>
<com:TTextBox
ID="ProductName"
- Text=<%#$this->Parent->DataItem['name']%> />
+ Text=<%#$this->DataItem['name']%> />
</td>
<td>
<com:TDropDownList
@@ -29,12 +29,12 @@ The following example allows users to modify the existing tabular data using a <
<com:TTextBox
ID="ProductPrice"
Columns="7"
- Text=<%#$this->Parent->DataItem['price']%> />
+ Text=<%#$this->DataItem['price']%> />
</td>
<td>
<com:TCheckBox
ID="ProductImported"
- Checked=<%#$this->Parent->DataItem['imported']%> />
+ Checked=<%#$this->DataItem['imported']%> />
<com:TRequiredFieldValidator
ControlToValidate="ProductName"
ErrorMessage="Product name cannot be empty."
diff --git a/demos/quickstart/protected/pages/Controls/Samples/TTextBox/Home.page b/demos/quickstart/protected/pages/Controls/Samples/TTextBox/Home.page
index 49d254a8..b6357722 100644
--- a/demos/quickstart/protected/pages/Controls/Samples/TTextBox/Home.page
+++ b/demos/quickstart/protected/pages/Controls/Samples/TTextBox/Home.page
@@ -89,7 +89,7 @@ Safety feature (cross-site scripting prevention):
<b>SafeText:</b>
<com:TLabel ID="Output"
BackColor="silver"
- Text=<%#$this->Page->TextBox2->SafeText%> />
+ Text=<%#$this->TextBox2->SafeText%> />
</td></tr>
</table>
diff --git a/demos/quickstart/protected/pages/Fundamentals/Modules.page b/demos/quickstart/protected/pages/Fundamentals/Modules.page
index ebf4ac53..782ebb8c 100644
--- a/demos/quickstart/protected/pages/Fundamentals/Modules.page
+++ b/demos/quickstart/protected/pages/Fundamentals/Modules.page
@@ -41,7 +41,7 @@ Error handler module is used to capture and process all error conditions in an a
PRADO is released with a few more modules besides the core ones. They include caching modules (<tt>TSqliteCache</tt> and <tt>TMemCache</tt>), user management module (<tt>TUserManager</tt>), authentication and authorization module (<tt>TAuthManager</tt>), etc.
</p>
<p>
-When <tt>TPageService</tt> is requested, it also loads modules specific for page service, including asset manager (<tt>TAssetManager</tt>), template manager (<tt>TTemplateManager</tt>), theme/skin manager (<tt>TThemeManager</tt>), and page state persister (<tt>TPageStatePersister</tt>).
+When <tt>TPageService</tt> is requested, it also loads modules specific for page service, including asset manager (<tt>TAssetManager</tt>), template manager (<tt>TTemplateManager</tt>), theme/skin manager (<tt>TThemeManager</tt>).
</p>
<p>
Custom modules and core modules are all configurable via <a href="?page=Configurations.Overview">configurations</a>.
diff --git a/framework/Exceptions/messages.txt b/framework/Exceptions/messages.txt
index e53255cd..cde4eae1 100644
--- a/framework/Exceptions/messages.txt
+++ b/framework/Exceptions/messages.txt
@@ -110,7 +110,7 @@ template_property_unknown = {0} has no property called '{1}'.
template_event_unknown = {0} has no event called '{1}'.
template_property_readonly = {0} has a read-only property '{1}'.
template_event_forbidden = {0} is a non-control component. No handler can be attached to its event '{1}' in a template.
-template_databind_forbidden = {0} is a non-control component. No databinding expression can be set to its property '{1}'.
+template_databind_forbidden = {0} is a non-control component. Expressions cannot be bound to its property '{1}'.
template_component_required = '{0}' is not a component. Only components can appear in a template.
template_format_invalid = Error in {0} (line {1}) : {2}
template_format_invalid2 = Error at line {0} of the following template: {1} {2}
diff --git a/framework/Web/UI/TControl.php b/framework/Web/UI/TControl.php
index 78c5bdfc..9ede6be5 100644
--- a/framework/Web/UI/TControl.php
+++ b/framework/Web/UI/TControl.php
@@ -122,6 +122,7 @@ class TControl extends TApplicationComponent implements IRenderable, IBindable
const RF_CONTROLSTATE=7; // controlstate
const RF_NAMED_OBJECTS=8; // controls declared with ID on template
const RF_ADAPTER=9; // adapter
+ const RF_AUTO_BINDINGS=10; // auto data bindings
/**
* @var string control ID
@@ -722,7 +723,7 @@ class TControl extends TApplicationComponent implements IRenderable, IBindable
/**
* Sets up the binding between a property (or property path) and an expression.
- * The context of the expression is the control itself.
+ * The context of the expression is the template control (or the control itself if it is a page).
* @param string the property name, or property path
* @param string the expression
*/
@@ -741,6 +742,19 @@ class TControl extends TApplicationComponent implements IRenderable, IBindable
}
/**
+ * Sets up the binding between a property (or property path) and an expression.
+ * Unlike regular databinding, the expression bound by this method
+ * is automatically evaluated during {@link prerenderRecursive()}.
+ * The context of the expression is the template control (or the control itself if it is a page).
+ * @param string the property name, or property path
+ * @param string the expression
+ */
+ public function autoBindProperty($name,$expression)
+ {
+ $this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression;
+ }
+
+ /**
* Performs the databinding for this control.
*/
public function dataBind()
@@ -760,8 +774,24 @@ class TControl extends TApplicationComponent implements IRenderable, IBindable
{
if(isset($this->_rf[self::RF_DATA_BINDINGS]))
{
+ if(($context=$this->getTemplateControl())===null)
+ $context=$this;
foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression)
- $this->setSubProperty($property,$this->evaluateExpression($expression));
+ $this->setSubProperty($property,$context->evaluateExpression($expression));
+ }
+ }
+
+ /**
+ * Auto databinding properties of the control.
+ */
+ protected function autoDataBindProperties()
+ {
+ if(isset($this->_rf[self::RF_AUTO_BINDINGS]))
+ {
+ if(($context=$this->getTemplateControl())===null)
+ $context=$this;
+ foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression)
+ $this->setSubProperty($property,$context->evaluateExpression($expression));
}
}
@@ -1159,6 +1189,8 @@ class TControl extends TApplicationComponent implements IRenderable, IBindable
{
if($this->_stage<self::CS_LOADED)
{
+ if(($context=$this->getTemplateControl())===null)
+ $context=$this;
if(isset($this->_rf[self::RF_ADAPTER]))
$this->_rf[self::RF_ADAPTER]->onLoad(null);
else
@@ -1167,8 +1199,10 @@ class TControl extends TApplicationComponent implements IRenderable, IBindable
if($this->getHasControls())
{
foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
if($control instanceof TControl)
$control->loadRecursive();
+ }
}
if($this->_stage<self::CS_LOADED)
$this->_stage=self::CS_LOADED;
@@ -1180,6 +1214,8 @@ class TControl extends TApplicationComponent implements IRenderable, IBindable
*/
protected function preRenderRecursive()
{
+ $this->autoDataBindProperties();
+
if($this->getVisible(false))
{
$this->ensureChildControls();
@@ -1190,8 +1226,12 @@ class TControl extends TApplicationComponent implements IRenderable, IBindable
if($this->getHasControls())
{
foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
if($control instanceof TControl)
$control->preRenderRecursive();
+ else if($control instanceof TCompositeLiteral)
+ $control->evaluateDynamicContent();
+ }
}
}
$this->_stage=self::CS_PRERENDERED;
@@ -2030,4 +2070,103 @@ class TCommandEventParameter extends TEventParameter
}
}
+
+/**
+ * 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;
+ }
+
+ /**
+ * Evaluates the expressions and/or statements in the component.
+ */
+ public function evaluateDynamicContent()
+ {
+ $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);
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * Renders the content stored in this component.
+ * This method is required by {@link IRenderable}
+ * @param ITextWriter
+ */
+ public function render($writer)
+ {
+ $writer->write(implode('',$this->_items));
+ }
+}
+
?> \ No newline at end of file
diff --git a/framework/Web/UI/TTemplateManager.php b/framework/Web/UI/TTemplateManager.php
index 7961a121..488a3a3b 100644
--- a/framework/Web/UI/TTemplateManager.php
+++ b/framework/Web/UI/TTemplateManager.php
@@ -397,7 +397,6 @@ class TTemplate extends TApplicationComponent implements ITemplate
*/
protected function configureProperty($component,$name,$value)
{
- $setter='set'.$name;
if(is_array($value))
{
switch($value[0])
@@ -406,19 +405,23 @@ class TTemplate extends TApplicationComponent implements ITemplate
$component->bindProperty($name,$value[1]);
break;
case self::CONFIG_EXPRESSION:
- $component->$setter($component->evaluateExpression($value[1]));
+ $component->autoBindProperty($name,$value[1]);
break;
case self::CONFIG_TEMPLATE:
+ $setter='set'.$name;
$component->$setter($value[1]);
break;
case self::CONFIG_ASSET: // asset URL
+ $setter='set'.$name;
$url=$this->publishFilePath($this->_contextPath.'/'.$value[1]);
$component->$setter($url);
break;
case self::CONFIG_PARAMETER: // application parameter
+ $setter='set'.$name;
$component->$setter($this->getApplication()->getParameters()->itemAt($value[1]));
break;
case self::CONFIG_LOCALIZATION:
+ $setter='set'.$name;
$component->$setter(Prado::localize($value[1]));
break;
default: // an error if reaching here
@@ -426,7 +429,10 @@ class TTemplate extends TApplicationComponent implements ITemplate
}
}
else
+ {
+ $setter='set'.$name;
$component->$setter($value);
+ }
}
/**
@@ -817,7 +823,7 @@ class TTemplate extends TApplicationComponent implements ITemplate
{
foreach($attributes as $name=>$att)
{
- if(is_array($att) && $att[0]===self::CONFIG_DATABIND)
+ if(is_array($att) && ($att[0]===self::CONFIG_DATABIND || $att[0]===self::CONFIG_EXPRESSION))
throw new TConfigurationException('template_databind_forbidden',$type,$name);
if(($pos=strpos($name,'.'))!==false)
{
@@ -846,95 +852,4 @@ 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/Web/UI/WebControls/TRepeater.php b/framework/Web/UI/WebControls/TRepeater.php
index 3d57fbd5..1acdc766 100644
--- a/framework/Web/UI/WebControls/TRepeater.php
+++ b/framework/Web/UI/WebControls/TRepeater.php
@@ -259,6 +259,35 @@ class TRepeater extends TDataBoundControl implements INamingContainer
}
/**
+ * @return string the field of the data source that provides the keys of the list items.
+ */
+ public function getDataKeyField()
+ {
+ return $this->getViewState('DataKeyField','');
+ }
+
+ /**
+ * @param string the field of the data source that provides the keys of the list items.
+ */
+ public function setDataKeyField($value)
+ {
+ $this->setViewState('DataKeyField',$value,'');
+ }
+
+ /**
+ * @return TList the keys used in the data listing control.
+ */
+ public function getDataKeys()
+ {
+ if(($dataKeys=$this->getViewState('DataKeys',null))===null)
+ {
+ $dataKeys=new TList;
+ $this->setViewState('DataKeys',$dataKeys,null);
+ }
+ return $dataKeys;
+ }
+
+ /**
* Creates a repeater item instance based on the item type and index.
* @param integer zero-based item index
* @param string item type, may be 'Header', 'Footer', 'Empty', 'Item', 'Separator', 'AlternatingItem'.
@@ -405,11 +434,18 @@ class TRepeater extends TDataBoundControl implements INamingContainer
protected function performDataBinding($data)
{
$this->reset();
+
+ $keys=$this->getDataKeys();
+ $keys->clear();
+ $keyField=$this->getDataKeyField();
+
$items=$this->getItems();
$itemIndex=0;
$hasSeparator=$this->_separatorTemplate!==null;
foreach($data as $dataItem)
{
+ if($keyField!=='')
+ $keys->add($this->getDataFieldValue($dataItem,$keyField));
if($itemIndex===0 && $this->_headerTemplate!==null)
$this->_header=$this->createItemInternal(-1,self::IT_HEADER,true,null);
if($hasSeparator && $itemIndex>0)
@@ -493,6 +529,22 @@ class TRepeater extends TDataBoundControl implements INamingContainer
{
$this->raiseEvent('OnItemCommand',$this,$param);
}
+
+ /**
+ * Returns the value of the data at the specified field.
+ * If data is an array, TMap or TList, the value will be returned at the index
+ * of the specified field. If the data is a component with a property named
+ * as the field name, the property value will be returned.
+ * Otherwise, an exception will be raised.
+ * @param mixed data item
+ * @param mixed field name
+ * @return mixed data value at the specified field
+ * @throws TInvalidDataValueException if the data is invalid
+ */
+ protected function getDataFieldValue($data,$field)
+ {
+ return TDataFieldAccessor::getDataFieldValue($data,$field);
+ }
}
/**