summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxue <>2006-04-27 13:13:17 +0000
committerxue <>2006-04-27 13:13:17 +0000
commit1f63d5c05ba117e0158c02d5bc79fa1f38f8ce85 (patch)
treea583561d32abb2e7ee400d8532d34d1acae96157
parent8ab196ce6c2d5de323bdd8ebcc11a73814c0cdca (diff)
merge from 3.0 branch till 978.
-rw-r--r--.gitattributes14
-rw-r--r--HISTORY4
-rw-r--r--UPGRADE4
-rw-r--r--build.xml36
-rw-r--r--buildscripts/phing/tasks/BuildPradoPEARPackageTask.php201
-rw-r--r--demos/quickstart/protected/pages/Controls/Samples/TMultiView/Home.page4
-rw-r--r--framework/Web/Javascripts/TJavaScript.php42
-rw-r--r--framework/Web/Javascripts/js/prado.js12
-rw-r--r--framework/Web/Javascripts/js/validator.js110
-rw-r--r--framework/Web/Javascripts/prado/form.js2
-rw-r--r--framework/Web/Javascripts/prado/prado.js16
-rw-r--r--framework/Web/Javascripts/prado/validation.js767
-rw-r--r--framework/Web/Javascripts/prado/validation3.js154
-rw-r--r--framework/Web/Javascripts/prado/validators.js222
-rw-r--r--framework/Web/UI/WebControls/TBaseValidator.php111
-rw-r--r--framework/Web/UI/WebControls/TClientScript.php75
-rw-r--r--framework/Web/UI/WebControls/TLiteral.php2
-rw-r--r--tests/FunctionalTests/features/protected/controls/Layout.tpl5
-rw-r--r--tests/FunctionalTests/features/protected/pages/ValidatorEffects.page91
-rw-r--r--tests/FunctionalTests/quickstart/Controls/ExpressionTestCase.php15
-rw-r--r--tests/FunctionalTests/quickstart/Controls/HtmlAreaTestCase.php15
-rw-r--r--tests/FunctionalTests/quickstart/Controls/MultiViewTestCase.php38
-rw-r--r--tests/FunctionalTests/quickstart/Controls/StatementsTestCase.php15
-rw-r--r--tests/FunctionalTests/quickstart/Controls/Wizard1TestCase.php26
-rw-r--r--tests/FunctionalTests/quickstart/Controls/Wizard2TestCase.php26
-rw-r--r--tests/FunctionalTests/quickstart/Controls/Wizard3TestCase.php46
-rw-r--r--tests/FunctionalTests/quickstart/Controls/Wizard4TestCase.php44
-rw-r--r--tests/FunctionalTests/quickstart/Controls/Wizard5TestCase.php37
28 files changed, 993 insertions, 1141 deletions
diff --git a/.gitattributes b/.gitattributes
index 4af4a3fe..fc04fe48 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -11,6 +11,7 @@ buildscripts/phing/style/log.xsl -text
buildscripts/phing/style/phpunit2-frames.xsl -text
buildscripts/phing/style/phpunit2-noframes.xsl -text
buildscripts/phing/style/str.replace.function.xsl -text
+buildscripts/phing/tasks/BuildPradoPEARPackageTask.php -text
buildscripts/phing/tasks/PhpLintTask.php -text
buildscripts/phing/tasks/XmlLintTask.php -text
buildscripts/phing/tasks/ZendCodeAnalyzerTask.php -text
@@ -883,9 +884,7 @@ framework/Web/Javascripts/prado/controls.js -text
framework/Web/Javascripts/prado/element.js -text
framework/Web/Javascripts/prado/form.js -text
framework/Web/Javascripts/prado/prado.js -text
-framework/Web/Javascripts/prado/validation.js -text
framework/Web/Javascripts/prado/validation3.js -text
-framework/Web/Javascripts/prado/validators.js -text
framework/Web/Javascripts/prototype/AUTHORS -text
framework/Web/Javascripts/prototype/LICENSE -text
framework/Web/Javascripts/prototype/README -text
@@ -945,6 +944,7 @@ framework/Web/UI/WebControls/TButtonColumn.php -text
framework/Web/UI/WebControls/TCheckBox.php -text
framework/Web/UI/WebControls/TCheckBoxColumn.php -text
framework/Web/UI/WebControls/TCheckBoxList.php -text
+framework/Web/UI/WebControls/TClientScript.php -text
framework/Web/UI/WebControls/TColorPicker.php -text
framework/Web/UI/WebControls/TCompareValidator.php -text
framework/Web/UI/WebControls/TContent.php -text
@@ -1034,6 +1034,7 @@ tests/FunctionalTests/features/protected/pages/I18N/Home.page -text
tests/FunctionalTests/features/protected/pages/I18N/Home.zh_CN.page -text
tests/FunctionalTests/features/protected/pages/I18N/config.xml -text
tests/FunctionalTests/features/protected/pages/RatingList.page -text
+tests/FunctionalTests/features/protected/pages/ValidatorEffects.page -text
tests/FunctionalTests/index.php -text
tests/FunctionalTests/quickstart.php -text
tests/FunctionalTests/quickstart/Advanced/I18N.php -text
@@ -1050,20 +1051,29 @@ tests/FunctionalTests/quickstart/Controls/DataGrid6TestCase.php -text
tests/FunctionalTests/quickstart/Controls/DataList1TestCase.php -text
tests/FunctionalTests/quickstart/Controls/DataList2TestCase.php -text
tests/FunctionalTests/quickstart/Controls/DropDownListTestCase.php -text
+tests/FunctionalTests/quickstart/Controls/ExpressionTestCase.php -text
+tests/FunctionalTests/quickstart/Controls/HtmlAreaTestCase.php -text
tests/FunctionalTests/quickstart/Controls/HyperLinkTestCase.php -text
tests/FunctionalTests/quickstart/Controls/ImageButtonTestCase.php -text
tests/FunctionalTests/quickstart/Controls/ImageTestCase.php -text
tests/FunctionalTests/quickstart/Controls/LabelTestCase.php -text
tests/FunctionalTests/quickstart/Controls/LinkButtonTestCase.php -text
tests/FunctionalTests/quickstart/Controls/ListBoxTestCase.php -text
+tests/FunctionalTests/quickstart/Controls/MultiViewTestCase.php -text
tests/FunctionalTests/quickstart/Controls/PanelTestCase.php -text
tests/FunctionalTests/quickstart/Controls/RadioButtonListTestCase.php -text
tests/FunctionalTests/quickstart/Controls/RadioButtonTestCase.php -text
tests/FunctionalTests/quickstart/Controls/Repeater1TestCase.php -text
tests/FunctionalTests/quickstart/Controls/Repeater2TestCase.php -text
tests/FunctionalTests/quickstart/Controls/Repeater3TestCase.php -text
+tests/FunctionalTests/quickstart/Controls/StatementsTestCase.php -text
tests/FunctionalTests/quickstart/Controls/TableTestCase.php -text
tests/FunctionalTests/quickstart/Controls/TextBoxTestCase.php -text
+tests/FunctionalTests/quickstart/Controls/Wizard1TestCase.php -text
+tests/FunctionalTests/quickstart/Controls/Wizard2TestCase.php -text
+tests/FunctionalTests/quickstart/Controls/Wizard3TestCase.php -text
+tests/FunctionalTests/quickstart/Controls/Wizard4TestCase.php -text
+tests/FunctionalTests/quickstart/Controls/Wizard5TestCase.php -text
tests/FunctionalTests/quickstart/Fundamentals/HangmanTestCase.php -text
tests/FunctionalTests/selenium/SeleneseRunner.html -text
tests/FunctionalTests/selenium/SeleniumLog.html -text
diff --git a/HISTORY b/HISTORY
index f92ad992..aee06513 100644
--- a/HISTORY
+++ b/HISTORY
@@ -24,12 +24,16 @@ ENH: TButtonColumn can now be a column of image buttons (Qiang)
ENH: TLiteral will display body content if Text is empty (Qiang)
ENH: Format string in classes extending TDataGridColumn can now evaluate an expression (Qiang)
ENH: Format string in classes extending TListControl can now evaluate an expression (Qiang)
+ENH: Custom visual effects can be added to client-side validators. (Wei)
+ENH: TJavascript::encode() allows raw javascript code when string begins with "javascript:" (Wei)
CHG: Rewrote client-side javascript validators, check your client-side validation behaviour (Wei)
CHG: Updated the javascript Prototype library, a few utilties functions REMOVED, may break your existing javascript code. (Wei)
CHG: Build javascript without compression, only comments are removed. (Wei)
CHG: TDatePicker's date can be set using Date property, it value must be in same format as DateFormat, TimeStamp must be set as integer (wei)
CHG: TSimpleDateFormatter::parse() now return an integer or null on parse error (Wei)
NEW: TListControlValidator (Wei)
+NEW: TClientScript (Wei)
+
Version 3.0RC2 April 16, 2006
diff --git a/UPGRADE b/UPGRADE
index 20c91cc9..ccf8c289 100644
--- a/UPGRADE
+++ b/UPGRADE
@@ -16,7 +16,9 @@ for both A and B.
Upgrading from v3.0.0 RC2
-------------------------
-There should be no compatibility issues.
+There should be no PHP compatibility issues. Javascript libraries
+were updated and client-side validators rewritten.
+
Upgrading from v3.0.0 RC1
diff --git a/build.xml b/build.xml
index 251a4b0d..ef0dce67 100644
--- a/build.xml
+++ b/build.xml
@@ -15,7 +15,7 @@
<property name="state" value=""/>
<property name="pear.state" value="stable"/>
<property name="pkgname" value="${phing.project.name}-${version}${state}"/>
- <property name="pkgname.pear" value="${pkgname}${pear.state}-pear"/>
+ <property name="pkgname.pear" value="${pkgname}-pear"/>
<property name="src.dir" value="framework"/>
<property name="doc.dir" value="docs"/>
<property name="build.base.dir" value="build"/>
@@ -38,10 +38,12 @@
<property name="codecoverage" value="false"/>
<property name="zca" value="/usr/local/Zend/ZendStudioClient-5.1.0/bin/ZendCodeAnalyzer"/>
<property name="quickstart" value="${build.base.dir}/docs/prado3_quick_start.pdf"/>
+ <property name="notes">This is the latest release of PRADO.</property>
<taskdef name="phplint" classname="PhpLintTask" classpath="buildscripts/phing/tasks"/>
<taskdef name="xmllint" classname="XmlLintTask" classpath="buildscripts/phing/tasks"/>
<taskdef name="analyze" classname="ZendCodeAnalyzerTask" classpath="buildscripts/phing/tasks"/>
+ <taskdef name="pear-package" classname="BuildPradoPEARPackageTask" classpath="buildscripts/phing/tasks"/>
<!--
PHP Source Files in framework
@@ -52,7 +54,7 @@
</fileset>
<!--
- Various resource files in framework
+ All Source Files in framework
-->
<fileset dir="." id="framework">
<exclude name="${src.dir}/**/.svn"/>
@@ -213,7 +215,6 @@
</then>
</if>
</target>
-
<target name="build-standard-package">
<echo>Building standard package...</echo>
@@ -228,8 +229,35 @@
</fileset>
</copy>
</target>
+
+ <target name="build-pear-package">
+ <echo>Preparing files for PEAR package...</echo>
+ <delete dir="${build.pear.dir}"/>
+ <mkdir dir="${build.pear.dir}"/>
+ <copy todir="${build.pear.dir}">
+ <fileset refid="src"/>
+ <fileset dir="${build.base.dir}">
+ <include name="${prado.lite}"/>
+ </fileset>
+ </copy>
+
+ <echo>Creating package.xml...</echo>
+ <pear-package dir="${build.pear.dir}" destFile="${build.base.dir}/pear/package.xml" version="${version}" state="${pear.state}" notes="${notes}">
+ <fileset refid="src"/>
+ <fileset dir="${build.base.dir}">
+ <include name="${prado.lite}"/>
+ </fileset>
+ </pear-package>
+ </target>
- <target name="build" depends="versioncheck,prepare,doc,pradolite,build-standard-package" description="Creating the main PRADO build"/>
+ <target name="build" depends="versioncheck,prepare,doc,quickstart,pradolite,build-standard-package,build-pear-package" description="Creating the main PRADO build"/>
+
+ <target name="dist-pear" depends="build-pear-package" description="Create PRADO PEAR package">
+ <delete file="${dist.pearfile}"/>
+ <mkdir dir="${dist.base.dir}"/>
+ <tar compression="gzip" destFile="${dist.pearfile}" basedir="${build.base.dir}/pear"/>
+ <exec command="pear package-validate ${dist.pearfile}" dir="." passthru="true"/>
+ </target>
<target name="dist" depends="build" description="Create PRADO distributions">
<!--<tar compression="gzip" destFile="${dist.tarfile}" basedir="${build.base.dir}/standard"/>-->
diff --git a/buildscripts/phing/tasks/BuildPradoPEARPackageTask.php b/buildscripts/phing/tasks/BuildPradoPEARPackageTask.php
new file mode 100644
index 00000000..212c6f9c
--- /dev/null
+++ b/buildscripts/phing/tasks/BuildPradoPEARPackageTask.php
@@ -0,0 +1,201 @@
+<?php
+require_once 'phing/tasks/system/MatchingTask.php';
+include_once 'phing/types/FileSet.php';
+include_once 'phing/tasks/ext/pearpackage/Fileset.php';
+require_once 'PEAR/PackageFileManager.php';
+require_once 'PEAR/PackageFileManager/File.php';
+
+/**
+ * Task for creating a PEAR package definition file package.xml to be used with
+ * the PEAR distribution of PRADO.
+ *
+ * @author Knut Urdalen <knut.urdalen@gmail.com>
+ * @package phing.tasks.ext
+ */
+class BuildPradoPEARPackageTask extends MatchingTask {
+
+ /* Base directory for reading files. */
+ private $dir;
+
+ /* PRADO version */
+ private $version;
+
+ /* PRADO state */
+ private $state = 'stable';
+ private $notes;
+ private $filesets = array();
+
+ /* Package file */
+ private $packageFile;
+
+ /**
+ * Intitialize the task and throw a BuildException if something is missing.
+ */
+ public function init() {
+ include_once 'PEAR/PackageFileManager2.php';
+ if(!class_exists('PEAR_PackageFileManager2')) {
+ throw new BuildException("You must have installed PEAR_PackageFileManager2 (PEAR_PackageFileManager >= 1.6.0) in order to create a PEAR package.xml file.");
+ }
+ }
+
+ /**
+ * Helper function to set PEAR package options.
+ *
+ * @param PEAR_PackageFileManager2 $pkg
+ */
+ private function setOptions($pkg) {
+ $options['baseinstalldir'] = 'prado';
+ $options['packagedirectory'] = $this->dir->getAbsolutePath();
+
+ if(empty($this->filesets)) {
+ throw new BuildException("You must use a <fileset> tag to specify the files to include in the package.xml");
+ }
+
+ $options['filelistgenerator'] = 'Fileset';
+
+ // Some Phing-specific options needed by our Fileset reader
+ $options['phing_project'] = $this->getProject();
+ $options['phing_filesets'] = $this->filesets;
+
+ if($this->packageFile !== null) {
+ // Create one with full path
+ $f = new PhingFile($this->packageFile->getAbsolutePath());
+ $options['packagefile'] = $f->getName();
+ // Must end in trailing slash
+ $options['outputdirectory'] = $f->getParent().DIRECTORY_SEPARATOR;
+ $this->log("Creating package file: ".$f->getPath(), PROJECT_MSG_INFO);
+ } else {
+ $this->log("Creating [default] package.xml file in base directory.", PROJECT_MSG_INFO);
+ }
+ $pkg->setOptions($options);
+ }
+
+ /**
+ * Main entry point.
+ * @return void
+ */
+ public function main() {
+
+ if($this->dir === null) {
+ throw new BuildException("You must specify the \"dir\" attribute for PEAR package task.");
+ }
+
+ if($this->version === null) {
+ throw new BuildException("You must specify the \"version\" attribute for PEAR package task.");
+ }
+
+ $package = new PEAR_PackageFileManager2();
+ $this->setOptions($package);
+
+ // the hard-coded stuff
+ $package->setPackage('prado');
+ $package->setSummary('PRADO is a component-based and event-driven framework for rapid Web programming in PHP 5.');
+ $package->setDescription('PRADO reconceptualizes Web application development in terms of components, events and properties instead of procedures, URLs and query parameters.
+
+A PRADO component is a combination of a specification file (in XML), an HTML template and a PHP class. PRADO components are combined together to form larger components or complete PRADO pages.
+
+Developing PRADO Web applications mainly involves instantiating prebuilt and application-specific component types, configuring them by setting their properties, responding to their events by writing handler functions, and composing them into application tasks. Event-driven programming
+
+PRADO provides the following benefits for Web application developers:
+
+o Reusability - Codes following the PRADO component protocol are highly reusable. Everything in PRADO is a reusable component.
+o Ease of Use - Creating and using components are extremely easy. Usually they simply involve configuring component properties.
+o Robustness - PRADO frees developers from writing boring, buggy code. They code in terms of objects, methods and properties, instead of URLs and query parameters. The latest PHP5 exception mechanism is exploited that enables line-precise error reporting.
+o Performance - PRADO uses a cache technique to ensure the performance of applications based on it. The performance is in fact comparable to those based on commonly used template engines.
+o Team Integration - PRADO enables separation of content and presentation. Components, typically pages, have their content (logic) and presentation stored in different files.');
+ $package->setChannel('pear.pradosoft.com');
+ $package->setPackageType('php');
+
+ $package->setReleaseVersion($this->version);
+ $package->setAPIVersion($this->version);
+
+ $package->setReleaseStability($this->state);
+ $package->setAPIStability($this->state);
+
+ $package->setNotes($this->notes);
+
+ $package->setLicense('BSD', 'http://www.opensource.org/licenses/bsd-license.php');
+
+ // Add package maintainers
+ $package->addMaintainer('lead', 'xue', 'Qiang Xue', 'qiang.xue@gmail.com');
+
+ // "core" dependencies
+ $package->setPhpDep('5.0.0');
+ $package->setPearinstallerDep('1.4.0');
+
+ $package->generateContents();
+
+ $e = $package->writePackageFile();
+
+ if(PEAR::isError($e)) {
+ throw new BuildException("Unable to write package file.", new Exception($e->getMessage()));
+ }
+ }
+
+ /**
+ * Used by the PEAR_PackageFileManager_PhingFileSet lister.
+ * @return array FileSet[]
+ */
+ public function getFileSets() {
+ return $this->filesets;
+ }
+
+ // -------------------------------
+ // Set properties from XML
+ // -------------------------------
+
+ /**
+ * Nested creator, creates a FileSet for this task
+ *
+ * @return FileSet The created fileset object
+ */
+ function createFileSet() {
+ $num = array_push($this->filesets, new FileSet());
+ return $this->filesets[$num-1];
+ }
+
+ /**
+ * Set the version we are building.
+ * @param string $v
+ * @return void
+ */
+ public function setVersion($v){
+ $this->version = $v;
+ }
+
+ /**
+ * Set the state we are building.
+ * @param string $v
+ * @return void
+ */
+ public function setState($v) {
+ $this->state = $v;
+ }
+
+ /**
+ * Sets release notes field.
+ * @param string $v
+ * @return void
+ */
+ public function setNotes($v) {
+ $this->notes = $v;
+ }
+ /**
+ * Sets "dir" property from XML.
+ * @param PhingFile $f
+ * @return void
+ */
+ public function setDir(PhingFile $f) {
+ $this->dir = $f;
+ }
+
+ /**
+ * Sets the file to use for generated package.xml
+ */
+ public function setDestFile(PhingFile $f) {
+ $this->packageFile = $f;
+ }
+
+}
+
+
diff --git a/demos/quickstart/protected/pages/Controls/Samples/TMultiView/Home.page b/demos/quickstart/protected/pages/Controls/Samples/TMultiView/Home.page
index b0e2386d..7cc98ce6 100644
--- a/demos/quickstart/protected/pages/Controls/Samples/TMultiView/Home.page
+++ b/demos/quickstart/protected/pages/Controls/Samples/TMultiView/Home.page
@@ -5,8 +5,8 @@
<com:TMultiView ID="MultiView" ActiveViewIndex="0" OnActiveViewChanged="viewChanged">
<com:TView ID="View1">
<h2>View 1</h2>
- <p>Please enter a paragraph:</p>
- <com:THtmlArea ID="Memo" />
+ <p>Please enter a memo:</p>
+ <com:TTextBox ID="Memo" />
<hr/>
<com:TButton Text="View 2" CommandName="NextView" />
<com:TButton Text="View 3" CommandName="SwitchViewIndex" CommandParameter="2" />
diff --git a/framework/Web/Javascripts/TJavaScript.php b/framework/Web/Javascripts/TJavaScript.php
index a3848201..75fc2438 100644
--- a/framework/Web/Javascripts/TJavaScript.php
+++ b/framework/Web/Javascripts/TJavaScript.php
@@ -84,6 +84,26 @@ class TJavaScript
else
return strtr($js,array("\t"=>'\t',"\n"=>'\n',"\r"=>'\r','"'=>'\"','\''=>'\\\'','\\'=>'\\\\'));
}
+
+ /**
+ * @return string considers the string as raw javascript function code
+ */
+ public static function quoteFunction($js)
+ {
+ if(self::isFunction($js))
+ return $js;
+ else
+ return 'javascript:'.$js;
+ }
+
+ /**
+ * @return boolean true if string is raw javascript function code, i.e., if
+ * the string begins with <tt>javascript:</tt>
+ */
+ public static function isFunction($js)
+ {
+ return preg_match('/^\s*javascript:/', $js);
+ }
/**
* Encodes a PHP variable into javascript representation.
@@ -96,16 +116,12 @@ class TJavaScript
* //expects the following javascript code
* // {'onLoading':'doit','onComplete':'more'}
* </code>
- *
- * To pass raw javascript statements start strings with
- * <tt>javascript:</tt>. E.g.
- * <code>
- * $options['onLoading'] = "javascript:function(){ alert('hello'); }";
- * //outputs {'onLoading':function(){ alert('hello'); }}
- * </code>
*
- * For higher complexity data structures use {@link jsonEncode} and {@link
- * jsonDecode} to serialize and unserialize.
+ * For higher complexity data structures use {@link jsonEncode} and {@link jsonDecode}
+ * to serialize and unserialize.
+ *
+ * Note: strings begining with <tt>javascript:</tt> will be considered as
+ * raw javascript code and no encoding of that string will be enforced.
*
* @param mixed PHP variable to be encoded
* @param boolean whether the output is a map or a list.
@@ -122,9 +138,11 @@ class TJavaScript
if(($first==='[' && $last===']') || ($first==='{' && $last==='}'))
return $value;
}
- else if(strpos($value, 'javascript:')===0)
- return substr($value,11);
- return "'".self::quoteString($value)."'";
+ // if string begins with javascript: return the raw string minus the prefix
+ if(self::isFunction($value))
+ return preg_replace('/^\s*javascript:/', '', $value);
+ else
+ return "'".self::quoteString($value)."'";
}
else if(is_bool($value))
return $value?'true':'false';
diff --git a/framework/Web/Javascripts/js/prado.js b/framework/Web/Javascripts/js/prado.js
index c7145188..394d5eeb 100644
--- a/framework/Web/Javascripts/js/prado.js
+++ b/framework/Web/Javascripts/js/prado.js
@@ -1803,9 +1803,9 @@ var newdate=new Date(year,month-1,date, 0, 0, 0);
return newdate;
}
});
-var Prado =
-{
-Version: '3.0a',
+var Prado =
+{
+Version: '3.0.0',
Browser : function()
{
var info = { Version : "1.0" };
@@ -1830,11 +1830,11 @@ info.opera7 = ( ( info.agent.toLowerCase().indexOf( 'opera 7' ) > -1 ) || ( info
info.operaOld = info.opera && !info.opera7;
return info;
},
-ImportCss : function(doc, css_file)
+ImportCss : function(doc, css_file)
{
if (Prado.Browser().ie)
var styleSheet = doc.createStyleSheet(css_file);
-else
+else
{
var elm = doc.createElement("link");
elm.rel = "stylesheet";
@@ -1850,7 +1850,7 @@ var form = $(options['FormID']);
var canSubmit = true;
if(options['CausesValidation'] && typeof(Prado.Validation) != "undefined")
{
-if(!Prado.Validation.validate(options['FormID'], options['ValidationGroup']))
+if(!Prado.Validation.validate(options['FormID'], options['ValidationGroup'], $(options['ID'])))
return Event.stop(event);
}
if(options['PostBackUrl'] && options['PostBackUrl'].length > 0)
diff --git a/framework/Web/Javascripts/js/validator.js b/framework/Web/Javascripts/js/validator.js
index 8659d2e9..5e23df50 100644
--- a/framework/Web/Javascripts/js/validator.js
+++ b/framework/Web/Javascripts/js/validator.js
@@ -3,11 +3,11 @@ Prado.Validation =Class.create();
Object.extend(Prado.Validation,
{
managers : {},
-validate : function(formID, groupID)
+validate : function(formID, groupID, invoker)
{
if(this.managers[formID])
{
-return this.managers[formID].validate(groupID);
+return this.managers[formID].validate(groupID, invoker);
}
else
{
@@ -49,14 +49,14 @@ initialize : function(options)
this.options = options;
Prado.Validation.managers[options.FormID] = this;
},
-validate : function(group)
+validate : function(group, invoker)
{
if(group)
-return this._validateGroup(group);
+return this._validateGroup(group, invoker);
else
-return this._validateNonGroup();
+return this._validateNonGroup(invoker);
},
-_validateGroup: function(groupID)
+_validateGroup: function(groupID, invoker)
{
var valid = true;
if(this.groups.include(groupID))
@@ -64,7 +64,7 @@ if(this.groups.include(groupID))
this.validators.each(function(validator)
{
if(validator.group == groupID)
-valid = valid & validator.validate();
+valid = valid & validator.validate(invoker);
else
validator.hide();
});
@@ -72,13 +72,13 @@ validator.hide();
this.updateSummary(groupID, true);
return valid;
},
-_validateNonGroup : function()
+_validateNonGroup : function(invoker)
{
var valid = true;
this.validators.each(function(validator)
{
if(!validator.group)
-valid = valid & validator.validate();
+valid = valid & validator.validate(invoker);
else
validator.hide();
});
@@ -275,11 +275,9 @@ options : {},
_isObserving : {},
group : null,
manager : null,
+message : null,
initialize : function(options)
{
-options.OnValidate = options.OnValidate || Prototype.emptyFunction;
-options.OnSuccess = options.OnSuccess || Prototype.emptyFunction;
-options.OnError = options.OnError || Prototype.emptyFunction;
this.options = options;
this.control = $(options.ControlToValidate);
this.message = $(options.ID);
@@ -321,16 +319,34 @@ this.isValid = true;
this.updateControl();
this.visible = false;
},
-validate : function()
+validate : function(invoker)
{
+if(typeof(this.options.OnValidate) == "function")
+this.options.OnValidate(this, invoker);
if(this.enabled)
this.isValid = this.evaluateIsValid();
-this.options.OnValidate(this);
-this.updateControl();
if(this.isValid)
-this.options.OnSuccess(this);
+{
+if(typeof(this.options.OnSuccess) == "function")
+{
+this.visible = true;
+this.updateControlCssClass(this.control, this.isValid);
+this.options.OnSuccess(this, invoker);
+}
+else
+this.updateControl();
+}
else
-this.options.OnError(this);
+{
+if(typeof(this.options.OnError) == "function")
+{
+this.visible = true;
+this.updateControlCssClass(this.control, this.isValid);
+this.options.OnError(this, invoker);
+}
+else
+this.updateControl();
+}
this.observeChanges(this.control);
return this.isValid;
},
@@ -353,7 +369,7 @@ validator.manager.updateSummary(validator.group);
this._isObserving[control.id+this.options.ID] = true;
}
},
-_trim : function(value)
+trim : function(value)
{
return typeof(value) == "string" ? value.trim() : "";
},
@@ -393,20 +409,20 @@ getValidationValue : function(control)
{
case 'TDatePicker':
if(control.type == "text")
- return this._trim($F(control));
+ return this.trim($F(control));
else
{
- this._observeDatePickerChanges();
+ this.observeDatePickerChanges();
return Prado.WebUI.TDatePicker.getDropDownDate(control).getTime();
}
default:
- if(this._isListControlType())
- return this._getFirstSelectedListValue();
+ if(this.isListControlType())
+ return this.getFirstSelectedListValue();
else
- return this._trim($F(control));
+ return this.trim($F(control));
}
},
-_observeDatePickerChanges : function()
+observeDatePickerChanges : function()
{
if(Prado.Browser().ie)
{
@@ -416,11 +432,11 @@ this.observeChanges(DatePicker.getMonthListControl(this.control));
this.observeChanges(DatePicker.getYearListControl(this.control));
}
},
-_getSelectedValuesAndChecks : function(elements, initialValue)
+getSelectedValuesAndChecks : function(elements, initialValue)
{
var checked = 0;
var values = [];
-var isSelected = this._isCheckBoxType(elements[0]) ? 'checked' : 'selected';
+var isSelected = this.isCheckBoxType(elements[0]) ? 'checked' : 'selected';
elements.each(function(element)
{
if(element[isSelected] && element.value != initialValue)
@@ -431,7 +447,7 @@ values.push(element.value);
});
return {'checks' : checked, 'values' : values};
},
-_getListElements : function()
+getListElements : function()
{
switch(this.options.ControlType)
{
@@ -440,7 +456,7 @@ var elements = [];
for(var i = 0; i < this.options.TotalItems; i++)
{
var element = $(this.options.ControlToValidate+"_"+i);
-if(this._isCheckBoxType(element))
+if(this.isCheckBoxType(element))
elements.push(element);
}
return elements;
@@ -457,7 +473,7 @@ default:
return [];
}
},
-_isCheckBoxType : function(element)
+isCheckBoxType : function(element)
{
if(element && element.type)
{
@@ -466,18 +482,18 @@ return type == "checkbox" || type == "radio";
}
return false;
},
-_isListControlType : function()
+isListControlType : function()
{
var list = ['TCheckBoxList', 'TRadioButtonList', 'TListBox'];
return list.include(this.options.ControlType);
},
-_getFirstSelectedListValue : function()
+getFirstSelectedListValue : function()
{
var initial = "";
if(typeof(this.options.InitialValue) != "undefined")
initial = this.options.InitialValue;
-var elements = this._getListElements();
-var selection = this._getSelectedValuesAndChecks(elements, initial);
+var elements = this.getListElements();
+var selection = this.getSelectedValuesAndChecks(elements, initial);
return selection.values.length > 0 ? selection.values[0] : initial;
}
}
@@ -493,7 +509,7 @@ return true;
else
{
var a = this.getValidationValue();
-var b = this._trim(this.options.InitialValue);
+var b = this.trim(this.options.InitialValue);
return(a != b);
}
}
@@ -595,16 +611,16 @@ Prado.WebUI.TListControlValidator = Class.extend(Prado.WebUI.TBaseValidator,
{
evaluateIsValid : function()
{
-var elements = this._getListElements();
+var elements = this.getListElements();
if(elements && elements.length <= 0)
return true;
this.observeListElements(elements);
-var selection = this._getSelectedValuesAndChecks(elements);
+var selection = this.getSelectedValuesAndChecks(elements);
return this.isValidList(selection.checks, selection.values);
},
observeListElements : function(elements)
{
-if(Prado.Browser().ie && this._isCheckBoxType(elements[0]))
+if(Prado.Browser().ie && this.isCheckBoxType(elements[0]))
{
var validator = this;
elements.each(function(element)
@@ -640,13 +656,13 @@ required = this.options.Required.split(/,\s*/);
return required;
}
});
-Prado.WebUI.TDataTypeValidator = Class.extend(Prado.WebUI.TBaseValidator,
-{
-evaluateIsValid : function()
-{
-var value = this.getValidationValue();
-if(value.length <= 0)
-return true;
-return this.convert(this.options.DataType, value) != null;
-}
-});
+Prado.WebUI.TDataTypeValidator = Class.extend(Prado.WebUI.TBaseValidator,
+{
+evaluateIsValid : function()
+{
+var value = this.getValidationValue();
+if(value.length <= 0)
+return true;
+return this.convert(this.options.DataType, value) != null;
+}
+});
diff --git a/framework/Web/Javascripts/prado/form.js b/framework/Web/Javascripts/prado/form.js
index 2beb945b..aec9395d 100644
--- a/framework/Web/Javascripts/prado/form.js
+++ b/framework/Web/Javascripts/prado/form.js
@@ -107,7 +107,7 @@ Prado.PostBack = function(event,options)
if(options['CausesValidation'] && typeof(Prado.Validation) != "undefined")
{
- if(!Prado.Validation.validate(options['FormID'], options['ValidationGroup']))
+ if(!Prado.Validation.validate(options['FormID'], options['ValidationGroup'], $(options['ID'])))
return Event.stop(event);
}
diff --git a/framework/Web/Javascripts/prado/prado.js b/framework/Web/Javascripts/prado/prado.js
index e63c2718..ad51e2f7 100644
--- a/framework/Web/Javascripts/prado/prado.js
+++ b/framework/Web/Javascripts/prado/prado.js
@@ -1,8 +1,8 @@
-var Prado =
-{
- Version: '3.0a',
-
+var Prado =
+{
+ Version: '3.0.0',
+
/**
* Returns browser information. Example
* <code>
@@ -36,12 +36,12 @@ var Prado =
info.operaOld = info.opera && !info.opera7;
return info;
},
-
- ImportCss : function(doc, css_file)
+
+ ImportCss : function(doc, css_file)
{
if (Prado.Browser().ie)
var styleSheet = doc.createStyleSheet(css_file);
- else
+ else
{
var elm = doc.createElement("link");
@@ -51,5 +51,5 @@ var Prado =
if (headArr = doc.getElementsByTagName("head"))
headArr[0].appendChild(elm);
}
- }
+ }
};
diff --git a/framework/Web/Javascripts/prado/validation.js b/framework/Web/Javascripts/prado/validation.js
deleted file mode 100644
index 454f53f0..00000000
--- a/framework/Web/Javascripts/prado/validation.js
+++ /dev/null
@@ -1,767 +0,0 @@
-
-/**
- * Prado client-side javascript validation class.
- */
-Prado.Validation = Class.create();
-
-/**
- * Utilities for validation. Static class.
- */
-Prado.Validation.Util = Class.create();
-
-/**
- * Convert a string into integer, returns null if not integer.
- * @param {string} the string to convert to integer
- * @type {integer|null} null if string does not represent an integer.
- */
-Prado.Validation.Util.toInteger = function(value)
-{
- var exp = /^\s*[-\+]?\d+\s*$/;
- if (value.match(exp) == null)
- return null;
- var num = parseInt(value, 10);
- return (isNaN(num) ? null : num);
-}
-
-/**
- * Convert a string into a double/float value. <b>Internationalization
- * is not supported</b>
- * @param {string} the string to convert to double/float
- * @param {string} the decimal character
- * @return {float|null} null if string does not represent a float value
- */
-Prado.Validation.Util.toDouble = function(value, decimalchar)
-{
- decimalchar = undef(decimalchar) ? "." : decimalchar;
- var exp = new RegExp("^\\s*([-\\+])?(\\d+)?(\\" + decimalchar + "(\\d+))?\\s*$");
- var m = value.match(exp);
- if (m == null)
- return null;
- var cleanInput = m[1] + (m[2].length>0 ? m[2] : "0") + "." + m[4];
- var num = parseFloat(cleanInput);
- return (isNaN(num) ? null : num);
-}
-
-/**
- * Convert strings that represent a currency value (e.g. a float with grouping
- * characters) to float. E.g. "10,000.50" will become "10000.50". The number
- * of dicimal digits, grouping and decimal characters can be specified.
- * <i>The currency input format is <b>very</b> strict, null will be returned if
- * the pattern does not match</i>.
- * @param {string} the currency value
- * @param {string} the grouping character, default is ","
- * @param {int} number of decimal digits
- * @param {string} the decimal character, default is "."
- * @type {float|null} the currency value as float.
- */
-Prado.Validation.Util.toCurrency = function(value, groupchar, digits, decimalchar)
-{
- groupchar = undef(groupchar) ? "," : groupchar;
- decimalchar = undef(decimalchar) ? "." : decimalchar;
- digits = undef(digits) ? 2 : digits;
-
- var exp = new RegExp("^\\s*([-\\+])?(((\\d+)\\" + groupchar + ")*)(\\d+)"
- + ((digits > 0) ? "(\\" + decimalchar + "(\\d{1," + digits + "}))?" : "")
- + "\\s*$");
- var m = value.match(exp);
- if (m == null)
- return null;
- var intermed = m[2] + m[5] ;
- var cleanInput = m[1] + intermed.replace(
- new RegExp("(\\" + groupchar + ")", "g"), "")
- + ((digits > 0) ? "." + m[7] : "");
- var num = parseFloat(cleanInput);
- return (isNaN(num) ? null : num);
-}
-
-/**
- * Get the date from string using the prodivided date format string.
- * The format notations are
- * # day -- %d or %e
- * # month -- %m
- * # year -- %y or %Y
- * # hour -- %H, %I, %k, or %l
- * # minutes -- %M
- * # P.M. -- %p or %P
- * @param {string} the formatted date string
- * @param {string} the date format
- * @type {Date} the date represented in the string
- */
-Prado.Validation.Util.toDate = function(value, format)
-{
- var y = 0;
- var m = -1;
- var d = 0;
- var a = value.split(/\W+/);
- var b = format.match(/%./g);
- var i = 0, j = 0;
- var hr = 0;
- var min = 0;
- for (i = 0; i < a.length; ++i) {
- if (!a[i])
- continue;
- switch (b[i]) {
- case "%d":
- case "%e":
- d = parseInt(a[i], 10);
- break;
-
- case "%m":
- m = parseInt(a[i], 10) - 1;
- break;
-
- case "%Y":
- case "%y":
- y = parseInt(a[i], 10);
- (y < 100) && (y += (y > 29) ? 1900 : 2000);
- break;
-
- case "%H":
- case "%I":
- case "%k":
- case "%l":
- hr = parseInt(a[i], 10);
- break;
-
- case "%P":
- case "%p":
- if (/pm/i.test(a[i]) && hr < 12)
- hr += 12;
- break;
-
- case "%M":
- min = parseInt(a[i], 10);
- break;
- }
- }
- if (y != 0 && m != -1 && d != 0)
- {
- var date = new Date(y, m, d, hr, min, 0);
- return (isObject(date)
- && y == date.getFullYear()
- && m == date.getMonth()
- && d == date.getDate()) ? date.valueOf() : null;
- }
- return null;
-}
-
-/**
- * Trim the value, if the value is undefined, empty string is return.
- * @param {string} string to be trimmed.
- * @type {string} trimmed string.
- */
-Prado.Validation.trim = function(value)
-{
- if(isString(value)) return value.trim();
- return "";
-}
-
-/**
- * A delayed focus on a particular element
- * @param {element} element to apply focus()
- */
-Prado.Validation.Util.focus = function(element)
-{
- var obj = $(element);
- if(isObject(obj) && isdef(obj.focus))
- setTimeout(function(){ obj.focus(); }, 100);
- return false;
-}
-
-/**
- * List of validator instances.
- */
-Prado.Validation.validators = [];
-
-/**
- * List of forms.
- * @type {int}
- */
-Prado.Validation.forms = [];
-
-/**
- * List of summary controls.
- */
-Prado.Validation.summaries = [];
-
-/**
- * Validation groups.
- */
-Prado.Validation.groups = [];
-
-
-/**
- * Second type of grouping.
- */
-Prado.Validation.TargetGroups = {};
-
-
-/**
- * Current Target group.
- */
-Prado.Validation.CurrentTargetGroup = null;
-
-Prado.Validation.HasTargetGroup = false;
-
-/**
- * Targets that can cause validation.
- */
-Prado.Validation.ActiveTarget = null;
-
-
-/**
- * Determine if group validation is active.
- */
-Prado.Validation.IsGroupValidation = false;
-
-/**
- * Add a form for validation.
- * @param {string} form ID
- */
-Prado.Validation.AddForm = function(id)
-{
- Prado.Validation.forms.push($(id));
-}
-
-/**
- * Add a target that causes validation. Only elements that have been added
- * can cause validation.
- * @param {string} target id
- */
-Prado.Validation.AddTarget = function(id, group)
-{
- var target = $(id);
- Event.observe(target, "click", function()
- {
- Prado.Validation.ActiveTarget = target;
- Prado.Validation.CurrentTargetGroup = Prado.Validation.TargetGroups[id];
- });
- if(group)
- {
- Prado.Validation.TargetGroups[id] = group;
- Prado.Validation.HasTargetGroup = true;
- }
-}
-
-Prado.Validation.SetActiveGroup = function(target, group)
-{
- Prado.Validation.ActiveTarget = target;
- Prado.Validation.CurrentTargetGroup = group;
-}
-
-/**
- * Associate a list of validators to a particular control element.
- * This essentially allows a set of validators to be grouped to a particular button.
- * @param {list} group array show have, {group : "id", target : "target button"}
- * @param {array} validator ids
- */
-Prado.Validation.AddGroup = function(group, validators)
-{
- group.active = false; //default active status is false.
- group.target = $(group.target);
- group.validators = validators;
- Prado.Validation.groups.push(group);
-
- //update the active group when the button is clicked.
- Event.observe(group.target, "click", Prado.Validation.UpdateActiveGroup);
-}
-
-/**
- * Update the active group, if call manually it will deactivate all groups.
- * @param {string}
- * @type {int}
- */
-Prado.Validation.UpdateActiveGroup = function(ev)
-{
- var groups = Prado.Validation.groups;
- for (var i = 0; i < groups.length; i++)
- {
- groups[i].active = (isdef(ev) && groups[i].target == Event.element(ev));
- }
- Prado.Validation.IsGroupValidation = isdef(ev);
-}
-
-/**
- * Determine if validation is sucessful. Iterate through the list
- * of validator instances and call validate(). Only validators that
- * for a particular form are evaluated. Other validators will be disabled.
- * If performing group validation, only active validators are visible.
- * @param {element} the form for the controls to validate.
- * @type {boolean} true is all validators are valid, false otherwise.
- */
-Prado.Validation.IsValid = function(form)
-{
- var valid = true;
- var validators = Prado.Validation.validators;
-
- for(var i = 0; i < validators.length; i++)
- {
- //prevent validating multiple forms
- validators[i].enabled = !validators[i].control || undef(validators[i].control.form) || validators[i].control.form == form;
- //when group validation, only validators in the active group are visible.
- validators[i].visible = Prado.Validation.IsGroupValidation ? validators[i].inActiveGroup() : true;
-
- if(Prado.Validation.HasTargetGroup)
- validators[i].enabled = Prado.Validation.CurrentTargetGroup == validators[i].group
-
- valid &= validators[i].validate();
- }
-
- //show the summary including the alert box
- Prado.Validation.ShowSummary(form);
- //reset all the group active status to false
- Prado.Validation.UpdateActiveGroup();
-
- return valid;
-}
-
-/**
- * Base validator class. Supply a different validation function
- * to obtain a different validator. E.g. to use the RequiredFieldValidator
- * <code>new Prado.Validation(Prado.Validation.RequiredFieldValidator, options);</code>
- * or to use the CustomValidator,
- * <code>new Prado.Validation(Prado.Validation.CustomValidator, options);</code>
- */
-Prado.Validation.prototype =
-{
- /**
- * Initialize the validator.
- * @param {function} the function to call to evaluate if
- * the validator is valid
- * @param {string|element} the control ID or element
- * @param {array} the list of attributes for the validator
- */
- initialize : function(validator, attr)
- {
- this.evaluateIsValid = validator;
- this.attr = undef(attr) ? [] : attr;
- this.message = $(attr.id);
- this.control = $(attr.controltovalidate);
- this.enabled = isdef(attr.enabled) ? attr.enabled : true;
- this.visible = isdef(attr.visible) ? attr.visible : true;
- this.group = isdef(attr.validationgroup) ? attr.validationgroup : null;
- this.isValid = true;
- Prado.Validation.validators.push(this);
- if(this.evaluateIsValid)
- this.evaluateIsValid.bind(this);
- },
-
- /**
- * Evaluate the validator only when visible and enabled.
- * @type {boolean} true if valid, false otherwise.
- */
- validate : function()
- {
- if(this.visible && this.enabled && this.evaluateIsValid)
- this.isValid = this.evaluateIsValid();
- else
- this.isValid = true;
-
- this.observe(); //watch for changes to the control values
- this.update(); //update the validation messages
- return this.isValid;
- },
-
- /**
- * Hide or show the error messages for "Dynamic" displays.
- */
- update : function()
- {
- if(this.attr.display == "Dynamic")
- this.isValid ? Element.hide(this.message) : Element.show(this.message);
-
- if(this.message)
- this.message.style.visibility = this.isValid ? "hidden" : "visible";
-
- //update the control css class name
- var className = this.attr.controlcssclass;
- if(this.control && isString(className) && className.length>0)
- Element.condClassName(this.control, className, !this.isValid);
- Prado.Validation.ShowSummary();
-
- var focus = this.attr.focusonerror;
- var hasGroup = Prado.Validation.HasTargetGroup;
- var inGroup = this.group == Prado.Validation.CurrentTargetGroup;
-
- if(focus && (!hasGroup || (hasGroup && inGroup)))
- Prado.Element.focus(this.attr.focuselementid);
- },
-
- /**
- * Change the validity of the validator, calls update().
- * @param {boolean} change the isValid state of the validator.
- */
- setValid : function(valid)
- {
- this.isValid = valid;
- this.update();
- },
-
- /**
- * Observe changes to the control values, add "onchange" event to the control once.
- */
- observe : function()
- {
- if(undef(this.observing))
- {
- if(this.control && this.control.form)
- Event.observe(this.control, "change", this.validate.bind(this));
- this.observing = true;
- }
- },
-
- /**
- * Convert the value of the control to a specific data type.
- * @param {string} the data type, "Integer", "Double", "Currency" or "Date".
- * @param {string} the value to convert, null to get the value from the control.
- * @type {mixed|null} the converted data value.
- */
- convert : function(dataType, value)
- {
- if(undef(value))
- value = Form.Element.getValue(this.control);
- switch(dataType)
- {
- case "Integer":
- return Prado.Validation.Util.toInteger(value);
- case "Double" :
- case "Float" :
- return Prado.Validation.Util.toDouble(value, this.attr.decimalchar);
- case "Currency" :
- return Prado.Validation.Util.toCurrency(
- value, this.attr.groupchar, this.attr.digits, this.attr.decimalchar);
- case "Date":
- return Prado.Validation.Util.toDate(value, this.attr.dateformat);
- }
- return value.toString();
- },
-
- /**
- * Determine if the current validator is part of a active validation group.
- * @type {boolean} true if part of active validation group, false otherwise.
- */
- inActiveGroup : function()
- {
- var groups = Prado.Validation.groups;
- for (var i = 0; i < groups.length; i++)
- {
- if(groups[i].active && groups[i].validators.contains(this.attr.id))
- return true;
- }
- return false;
- }
-}
-
-/**
- * Validation summary class.
- */
-Prado.Validation.Summary = Class.create();
-Prado.Validation.Summary.prototype =
-{
- /**
- * Initialize a validation summary.
- * @param {array} summary options.
- */
- initialize : function(attr)
- {
- this.attr = attr;
- this.div = $(attr.id);
- this.visible = false;
- this.enabled = false;
- this.group = isdef(attr.validationgroup) ? attr.validationgroup : null;
- Prado.Validation.summaries.push(this);
- },
-
- /**
- * Show the validation summary.
- * @param {boolean} true to allow alert message
- */
- show : function(warn)
- {
- var refresh = warn || this.attr.refresh == "1";
- var messages = this.getMessages();
- if(messages.length <= 0 || !this.visible || !this.enabled)
- {
- if(refresh)
- {
- if(this.attr.display == "None" || this.attr.display == "Dynamic")
- Element.hide(this.div);
- else
- this.div.style.visibility="hidden";
- }
- return;
- }
-
- if(Prado.Validation.HasTargetGroup)
- {
- if(Prado.Validation.CurrentTargetGroup != this.group)
- {
- if(refresh)
- {
- if(this.attr.display == "None" || this.attr.display == "Dynamic")
- Element.hide(this.div);
- else
- this.div.style.visibility="hidden";
- }
- return;
- }
- }
-
- if(this.attr.showsummary != "False" && refresh)
- {
- //Element.show(this.div);
- this.div.style.display = "block";
- this.div.style.visibility = "visible";
- while(this.div.childNodes.length > 0)
- this.div.removeChild(this.div.lastChild);
- new Insertion.Bottom(this.div, this.formatSummary(messages));
- }
-
- if(warn)
- window.scrollTo(this.div.offsetLeft-20, this.div.offsetTop-20);
-
- var summary = this;
- if(warn && this.attr.showmessagebox == "True" && refresh)
- setTimeout(function(){alert(summary.formatMessageBox(messages));},20);
- },
-
- /**
- * Get a list of error messages from the validators.
- * @type {array} list of messages
- */
- getMessages : function()
- {
- var validators = Prado.Validation.validators;
- var messages = [];
- for(var i = 0; i < validators.length; i++)
- {
- if(validators[i].isValid == false
- && isString(validators[i].attr.errormessage)
- && validators[i].attr.errormessage.length > 0)
- {
-
- messages.push(validators[i].attr.errormessage);
- }
- }
- return messages;
- },
-
- /**
- * Return the format parameters for the summary.
- * @param {string} format type, "List", "SingleParagraph" or "BulletList"
- * @type {array} formatting parameters
- */
- formats : function(type)
- {
- switch(type)
- {
- case "List":
- return { header : "<br />", first : "", pre : "", post : "<br />", last : ""};
- case "SingleParagraph":
- return { header : " ", first : "", pre : "", post : " ", last : "<br />"};
- case "BulletList":
- default:
- return { header : "", first : "<ul>", pre : "<li>", post : "</li>", last : "</ul>"};
- }
- },
-
- /**
- * Format the message summary.
- * @param {array} list of error messages.
- * @type {string} formatted message
- */
- formatSummary : function(messages)
- {
- var format = this.formats(this.attr.displaymode);
- var output = isdef(this.attr.headertext) ? this.attr.headertext + format.header : "";
- output += format.first;
- for(var i = 0; i < messages.length; i++)
- output += (messages[i].length>0) ? format.pre + messages[i] + format.post : "";
- output += format.last;
- return output;
- },
- /**
- * Format the message alert box.
- * @param {array} a list of error messages.
- * @type {string} format message for alert.
- */
- formatMessageBox : function(messages)
- {
- var output = isdef(this.attr.headertext) ? this.attr.headertext + "\n" : "";
- for(var i = 0; i < messages.length; i++)
- {
- switch(this.attr.displaymode)
- {
- case "List":
- output += messages[i] + "\n";
- break;
- case "BulletList":
- default:
- output += " - " + messages[i] + "\n";
- break;
- case "SingleParagraph":
- output += messages[i] + " ";
- break;
- }
- }
- return output;
- },
-
- /**
- * Determine if this summary belongs to an active group.
- * @type {boolean} true if belongs to an active group.
- */
- inActiveGroup : function()
- {
- var groups = Prado.Validation.groups;
- for (var i = 0; i < groups.length; i++)
- {
- if(groups[i].active && groups[i].id == this.attr.group)
- return true;
- }
- return false;
- }
-}
-
-/**
- * Show the validation error message summary.
- * @param {element} the form that activated the summary call.
- */
-Prado.Validation.ShowSummary = function(form)
-{
- var summary = Prado.Validation.summaries;
- for(var i = 0; i < summary.length; i++)
- {
- if(isdef(form))
- {
- if(Prado.Validation.IsGroupValidation)
- {
- summary[i].visible = summary[i].inActiveGroup();
- }
- else
- {
- summary[i].visible = undef(summary[i].attr.group);
- }
-
- summary[i].enabled = $(summary[i].attr.form) == form;
- }
- summary[i].show(form);
- }
-}
-
-
-
-/**
- * When a form is try to submit, check the validators, submit
- * the form only when all validators are valid.
- * @param {event} form submit event.
- */
-Prado.Validation.OnSubmit = function(ev)
-{
- //HTML text editor, tigger save first.
- //alert(tinyMCE);
- if(typeof tinyMCE != "undefined")
- tinyMCE.triggerSave();
-
- //no active target?
- if(!Prado.Validation.ActiveTarget) return true;
- var valid = Prado.Validation.IsValid(Event.element(ev) || ev);
-
- //not valid? do not submit the form
- if(Event.element(ev) && !valid)
- Event.stop(ev);
-
- //reset the target
- Prado.Validation.ActiveTarget = null;
- //Prado.Validation.CurrentTargetGroup = null;
-
- return valid;
-}
-
-/**
- * During window onload event, attach onsubmit event for each of the
- * forms in Prado.Validation.forms.
- */
-Prado.Validation.OnLoad = function()
-{
- Event.observe(Prado.Validation.forms,"submit", Prado.Validation.OnSubmit);
-}
-
-
-/**
- * Validate Validator Groups.
- * @param string ValidatorGroup
- * @return boolean true if valid, false otherwise
- */
-Prado.Validation.ValidateValidatorGroup = function(groupId)
-{
- var groups = Prado.Validation.groups;
- var group = null;
- for(var i = 0; i < groups.length; i++)
- {
- if(groups[i].id == groupId)
- {
- group = groups[i];
- Prado.Validation.groups[i].active = true;
- Prado.Validation.CurrentTargetGroup = null;
- Prado.Validation.IsGroupValidation = true;
- }
- else
- {
- Prado.Validation.groups[i].active = false;
- }
- }
- if(group)
- {
- return Prado.Validation.IsValid(group.target.form);
- }
- return true;
-};
-
-/**
- * Validate ValidationGroup
- * @param string ValidationGroup
- * @return boolean true if valid, false otherwise.
- */
-Prado.Validation.ValidateValidationGroup= function(groupId)
-{
- var groups = Prado.Validation.TargetGroups;
- for(var id in groups)
- {
- if(groups[id] == groupId)
- {
- var target = $(id);
- Prado.Validation.ActiveTarget = target;
- Prado.Validation.CurrentTargetGroup = groupId;
- Prado.Validation.IsGroupValidation = false;
- return Prado.Validation.IsValid(target.form);
- }
- }
-
- return true;
-};
-
-/**
- * Validate the page
- * @return boolean true if valid, false otherwise.
- */
-Prado.Validation.ValidateNonGroup= function(formId)
-{
- if(Prado.Validation)
- {
- var form = $(formId);
- form = form || document.forms[0];
- Prado.Validation.ActiveTarget = form;
- Prado.Validation.CurrentTargetGroup = null;
- Prado.Validation.IsGroupValidation = false;
- return Prado.Validation.IsValid(form);
- }
- return true;
-};
-
-
-
-/**
- * Register Prado.Validation.Onload() for window.onload event.
- */
-Event.OnLoad(Prado.Validation.OnLoad); \ No newline at end of file
diff --git a/framework/Web/Javascripts/prado/validation3.js b/framework/Web/Javascripts/prado/validation3.js
index 40472e7e..3ed31744 100644
--- a/framework/Web/Javascripts/prado/validation3.js
+++ b/framework/Web/Javascripts/prado/validation3.js
@@ -75,12 +75,13 @@ Object.extend(Prado.Validation,
* then only validators belonging to that group will be validated.
* @param string ID of the form to validate
* @param string ID of the group to validate.
+ * @param HTMLElement element that calls for validation
*/
- validate : function(formID, groupID)
+ validate : function(formID, groupID, invoker)
{
if(this.managers[formID])
{
- return this.managers[formID].validate(groupID);
+ return this.managers[formID].validate(groupID, invoker);
}
else
{
@@ -162,22 +163,24 @@ Prado.ValidationManager.prototype =
/**
* Validate the validators managed by this validation manager.
* @param string only validate validators belonging to a group (optional)
+ * @param HTMLElement element that calls for validation
* @return boolean true if all validators are valid, false otherwise.
*/
- validate : function(group)
+ validate : function(group, invoker)
{
if(group)
- return this._validateGroup(group);
+ return this._validateGroup(group, invoker);
else
- return this._validateNonGroup();
+ return this._validateNonGroup(invoker);
},
/**
* Validate a particular group of validators.
* @param string ID of the form
+ * @param HTMLElement element that calls for validation
* @return boolean false if group is not valid, true otherwise.
*/
- _validateGroup: function(groupID)
+ _validateGroup: function(groupID, invoker)
{
var valid = true;
if(this.groups.include(groupID))
@@ -185,7 +188,7 @@ Prado.ValidationManager.prototype =
this.validators.each(function(validator)
{
if(validator.group == groupID)
- valid = valid & validator.validate();
+ valid = valid & validator.validate(invoker);
else
validator.hide();
});
@@ -197,14 +200,15 @@ Prado.ValidationManager.prototype =
/**
* Validate validators that doesn't belong to any group.
* @return boolean false if not valid, true otherwise.
+ * @param HTMLElement element that calls for validation
*/
- _validateNonGroup : function()
+ _validateNonGroup : function(invoker)
{
var valid = true;
this.validators.each(function(validator)
{
if(!validator.group)
- valid = valid & validator.validate();
+ valid = valid & validator.validate(invoker);
else
validator.hide();
});
@@ -523,6 +527,7 @@ Prado.WebUI.TBaseValidator.prototype =
_isObserving : {},
group : null,
manager : null,
+ message : null,
/**
* <code>
@@ -543,10 +548,10 @@ Prado.WebUI.TBaseValidator.prototype =
*/
initialize : function(options)
{
- options.OnValidate = options.OnValidate || Prototype.emptyFunction;
+ /* options.OnValidate = options.OnValidate || Prototype.emptyFunction;
options.OnSuccess = options.OnSuccess || Prototype.emptyFunction;
options.OnError = options.OnError || Prototype.emptyFunction;
-
+ */
this.options = options;
this.control = $(options.ControlToValidate);
this.message = $(options.ID);
@@ -617,21 +622,39 @@ Prado.WebUI.TBaseValidator.prototype =
/**
* Calls evaluateIsValid() function to set the value of isValid property.
* Triggers onValidate event and onSuccess or onError event.
+ * @param HTMLElement element that calls for validation
* @return boolean true if valid.
*/
- validate : function()
+ validate : function(invoker)
{
+ if(typeof(this.options.OnValidate) == "function")
+ this.options.OnValidate(this, invoker);
+
if(this.enabled)
this.isValid = this.evaluateIsValid();
-
- this.options.OnValidate(this);
-
- this.updateControl();
-
+
if(this.isValid)
- this.options.OnSuccess(this);
+ {
+ if(typeof(this.options.OnSuccess) == "function")
+ {
+ this.visible = true;
+ this.updateControlCssClass(this.control, this.isValid);
+ this.options.OnSuccess(this, invoker);
+ }
+ else
+ this.updateControl();
+ }
else
- this.options.OnError(this);
+ {
+ if(typeof(this.options.OnError) == "function")
+ {
+ this.visible = true;
+ this.updateControlCssClass(this.control, this.isValid);
+ this.options.OnError(this, invoker);
+ }
+ else
+ this.updateControl();
+ }
this.observeChanges(this.control);
@@ -641,7 +664,7 @@ Prado.WebUI.TBaseValidator.prototype =
/**
* Observe changes to the control input, re-validate upon change. If
* the validator is not visible, no updates are propagated.
- * @param HTMLElement control to observe changes
+ * @param HTMLElement element that calls for validation
*/
observeChanges : function(control)
{
@@ -667,9 +690,9 @@ Prado.WebUI.TBaseValidator.prototype =
},
/**
- * @return string _trims the string value, empty string if value is not string.
+ * @return string trims the string value, empty string if value is not string.
*/
- _trim : function(value)
+ trim : function(value)
{
return typeof(value) == "string" ? value.trim() : "";
},
@@ -720,26 +743,25 @@ Prado.WebUI.TBaseValidator.prototype =
{
case 'TDatePicker':
if(control.type == "text")
- return this._trim($F(control));
+ return this.trim($F(control));
else
{
- this._observeDatePickerChanges();
+ this.observeDatePickerChanges();
return Prado.WebUI.TDatePicker.getDropDownDate(control).getTime();
}
default:
- if(this._isListControlType())
- return this._getFirstSelectedListValue();
+ if(this.isListControlType())
+ return this.getFirstSelectedListValue();
else
- return this._trim($F(control));
+ return this.trim($F(control));
}
},
/**
* Observe changes in the drop down list date picker, IE only.
- * @private
*/
- _observeDatePickerChanges : function()
+ observeDatePickerChanges : function()
{
if(Prado.Browser().ie)
{
@@ -754,13 +776,12 @@ Prado.WebUI.TBaseValidator.prototype =
* Gets numeber selections and their values.
* @return object returns selected values in <tt>values</tt> property
* and number of selections in <tt>checks</tt> property.
- * @private
*/
- _getSelectedValuesAndChecks : function(elements, initialValue)
+ getSelectedValuesAndChecks : function(elements, initialValue)
{
var checked = 0;
var values = [];
- var isSelected = this._isCheckBoxType(elements[0]) ? 'checked' : 'selected';
+ var isSelected = this.isCheckBoxType(elements[0]) ? 'checked' : 'selected';
elements.each(function(element)
{
if(element[isSelected] && element.value != initialValue)
@@ -776,9 +797,8 @@ Prado.WebUI.TBaseValidator.prototype =
* Gets an array of the list control item input elements, for TCheckBoxList
* checkbox inputs are returned, for TListBox HTML option elements are returned.
* @return array list control option elements.
- * @private
*/
- _getListElements : function()
+ getListElements : function()
{
switch(this.options.ControlType)
{
@@ -787,7 +807,7 @@ Prado.WebUI.TBaseValidator.prototype =
for(var i = 0; i < this.options.TotalItems; i++)
{
var element = $(this.options.ControlToValidate+"_"+i);
- if(this._isCheckBoxType(element))
+ if(this.isCheckBoxType(element))
elements.push(element);
}
return elements;
@@ -807,9 +827,8 @@ Prado.WebUI.TBaseValidator.prototype =
/**
* @return boolean true if element is of checkbox or radio type.
- * @private
*/
- _isCheckBoxType : function(element)
+ isCheckBoxType : function(element)
{
if(element && element.type)
{
@@ -821,9 +840,8 @@ Prado.WebUI.TBaseValidator.prototype =
/**
* @return boolean true if control to validate is of some of the TListControl type.
- * @private
*/
- _isListControlType : function()
+ isListControlType : function()
{
var list = ['TCheckBoxList', 'TRadioButtonList', 'TListBox'];
return list.include(this.options.ControlType);
@@ -831,15 +849,14 @@ Prado.WebUI.TBaseValidator.prototype =
/**
* @return string gets the first selected list value, initial value if none found.
- * @private
*/
- _getFirstSelectedListValue : function()
+ getFirstSelectedListValue : function()
{
var initial = "";
if(typeof(this.options.InitialValue) != "undefined")
initial = this.options.InitialValue;
- var elements = this._getListElements();
- var selection = this._getSelectedValuesAndChecks(elements, initial);
+ var elements = this.getListElements();
+ var selection = this.getSelectedValuesAndChecks(elements, initial);
return selection.values.length > 0 ? selection.values[0] : initial;
}
}
@@ -868,7 +885,7 @@ Prado.WebUI.TRequiredFieldValidator = Class.extend(Prado.WebUI.TBaseValidator,
else
{
var a = this.getValidationValue();
- var b = this._trim(this.options.InitialValue);
+ var b = this.trim(this.options.InitialValue);
return(a != b);
}
}
@@ -1105,13 +1122,13 @@ Prado.WebUI.TListControlValidator = Class.extend(Prado.WebUI.TBaseValidator,
*/
evaluateIsValid : function()
{
- var elements = this._getListElements();
+ var elements = this.getListElements();
if(elements && elements.length <= 0)
return true;
this.observeListElements(elements);
- var selection = this._getSelectedValuesAndChecks(elements);
+ var selection = this.getSelectedValuesAndChecks(elements);
return this.isValidList(selection.checks, selection.values);
},
@@ -1120,7 +1137,7 @@ Prado.WebUI.TListControlValidator = Class.extend(Prado.WebUI.TBaseValidator,
*/
observeListElements : function(elements)
{
- if(Prado.Browser().ie && this._isCheckBoxType(elements[0]))
+ if(Prado.Browser().ie && this.isCheckBoxType(elements[0]))
{
var validator = this;
elements.each(function(element)
@@ -1171,25 +1188,26 @@ Prado.WebUI.TListControlValidator = Class.extend(Prado.WebUI.TBaseValidator,
}
});
-/**
- * TDataTypeValidator verifies if the input data is of the type specified
- * by <tt>DataType</tt> option.
- * The following data types are supported:
- * - <b>Integer</b> A 32-bit signed integer data type.
- * - <b>Float</b> A double-precision floating point number data type.
- * - <b>Date</b> A date data type.
- * - <b>String</b> A string data type.
- * For <b>Date</b> type, the option <tt>DateFormat</tt>
- * will be used to determine how to parse the date string.
- */
-Prado.WebUI.TDataTypeValidator = Class.extend(Prado.WebUI.TBaseValidator,
-{
- evaluateIsValid : function()
- {
- var value = this.getValidationValue();
- if(value.length <= 0)
- return true;
- return this.convert(this.options.DataType, value) != null;
- }
-});
+
+/**
+ * TDataTypeValidator verifies if the input data is of the type specified
+ * by <tt>DataType</tt> option.
+ * The following data types are supported:
+ * - <b>Integer</b> A 32-bit signed integer data type.
+ * - <b>Float</b> A double-precision floating point number data type.
+ * - <b>Date</b> A date data type.
+ * - <b>String</b> A string data type.
+ * For <b>Date</b> type, the option <tt>DateFormat</tt>
+ * will be used to determine how to parse the date string.
+ */
+Prado.WebUI.TDataTypeValidator = Class.extend(Prado.WebUI.TBaseValidator,
+{
+ evaluateIsValid : function()
+ {
+ var value = this.getValidationValue();
+ if(value.length <= 0)
+ return true;
+ return this.convert(this.options.DataType, value) != null;
+ }
+});
diff --git a/framework/Web/Javascripts/prado/validators.js b/framework/Web/Javascripts/prado/validators.js
deleted file mode 100644
index 5aa732b4..00000000
--- a/framework/Web/Javascripts/prado/validators.js
+++ /dev/null
@@ -1,222 +0,0 @@
-/**
- * Validates that a given field has some input,
- * @param ${parameter}
- * @return ${return}
- */
-Prado.Validation.TRequiredFieldValidator=function(){
- var inputType = this.control.getAttribute("type");
- if(inputType == 'file'){
- return true;
- }
- else{
- var a= Prado.Validation.trim($F(this.control));
- var b= Prado.Validation.trim(this.attr.initialvalue);
- return(a != b);
- }
-}
-
-
-Prado.Validation.TRegularExpressionValidator = function()
-{
- var value = Prado.Validation.trim($F(this.control));
- if (value == "") return true;
- var rx = new RegExp(this.attr.validationexpression);
- var matches = rx.exec(value);
- return (matches != null && value == matches[0]);
-}
-
-Prado.Validation.TEmailAddressValidator = Prado.Validation.TRegularExpressionValidator;
-
-Prado.Validation.TCustomValidator = function()
-{
- var value = isNull(this.control) ? null : $F(this.control);
- var func = this.attr.clientvalidationfunction;
- eval("var validate = "+func);
- return validate && isFunction(validate) ? validate(this, value) : true;
-}
-
-Prado.Validation.TRangeValidator = function()
-{
- var value = Prado.Validation.trim($F(this.control));
- if (value == "") return true;
-
- var minval = this.attr.minimumvalue;
- var maxval = this.attr.maximumvalue;
-
- if (undef(minval) && undef(maxval))
- return true;
-
- if (minval == "") minval = 0;
- if (maxval == "") maxval = 0;
-
- var dataType = this.attr.type;
-
- if(undef(dataType))
- return (parseFloat(value) >= parseFloat(minval)) && (parseFloat(value) <= parseFloat(maxval));
-
- //now do datatype range check.
- var min = this.convert(dataType, minval);
- var max = this.convert(dataType, maxval);
- value = this.convert(dataType, value);
- return value >= min && value <= max;
-}
-
-Prado.Validation.TCompareValidator = function()
-{
- var value = Prado.Validation.trim($F(this.control));
- if (value.length == 0) return true;
-
- var compareTo;
-
- var comparee = $(this.attr.controlhookup);;
-
- if(comparee)
- compareTo = Prado.Validation.trim($F(comparee));
- else
- {
- compareTo = isString(this.attr.valuetocompare) ? this.attr.valuetocompare : "";
- }
-
- var compare = Prado.Validation.TCompareValidator.compare;
-
- var isValid = compare.bind(this)(value, compareTo);
-
- //update the comparee control css class name and add onchange event once.
- if(comparee)
- {
- var className = this.attr.controlcssclass;
- if(isString(className) && className.length>0)
- Element.condClassName(comparee, className, !isValid);
- if(undef(this.observingComparee))
- {
- Event.observe(comparee, "change", this.validate.bind(this));
- this.observingComparee = true;
- }
- }
- return isValid;
-}
-
-/**
- * Compare the two values, also performs data type check.
- * @param {string} value to compare with
- * @param {string} value to compare
- * @type {boolean} true if comparison or type check is valid, false otherwise.
- */
-Prado.Validation.TCompareValidator.compare = function(operand1, operand2)
-{
- var op1, op2;
- if ((op1 = this.convert(this.attr.type, operand1)) == null)
- return false;
- if (this.attr.operator == "DataTypeCheck")
- return true;
- if ((op2 = this.convert(this.attr.type, operand2)) == null)
- return true;
- switch (this.attr.operator)
- {
- case "NotEqual":
- return (op1 != op2);
- case "GreaterThan":
- return (op1 > op2);
- case "GreaterThanEqual":
- return (op1 >= op2);
- case "LessThan":
- return (op1 < op2);
- case "LessThanEqual":
- return (op1 <= op2);
- default:
- return (op1 == op2);
- }
-}
-
-Prado.Validation.TRequiredListValidator = function()
-{
- var min = undef(this.attr.min) ? Number.NEGATIVE_INFINITY : parseInt(this.attr.min);
- var max = undef(this.attr.max) ? Number.POSITIVE_INFINITY : parseInt(this.attr.max);
-
- var elements = document.getElementsByName(this.attr.selector);
-
- if(elements.length <= 0)
- return true;
-
- var required = new Array();
- if(isString(this.attr.required) && this.attr.required.length > 0)
- required = this.attr.required.split(/,\s* /);
-
- var isValid = true;
-
- var validator = Prado.Validation.TRequiredListValidator;
-
- switch(elements[0].type)
- {
- case 'radio':
- case 'checkbox':
- isValid = validator.IsValidRadioList(elements, min, max, required);
- break;
- case 'select-multiple':
- isValid = validator.IsValidSelectMultipleList(elements, min, max, required);
- break;
- }
-
- var className = this.attr.elementcssclass;
- if(isString(className) && className.length>0)
- map(elements, function(element){ condClass(element, className, !isValid); });
- if(undef(this.observingRequiredList))
- {
- Event.observe(elements, "change", this.validate.bind(this));
- this.observingRequiredList = true;
- }
- return isValid;
-}
-
-//radio group selection
-Prado.Validation.TRequiredListValidator.IsValidRadioList = function(elements, min, max, required)
-{
- var checked = 0;
- var values = new Array();
- for(var i = 0; i < elements.length; i++)
- {
- if(elements[i].checked)
- {
- checked++;
- values.push(elements[i].value);
- }
- }
- return Prado.Validation.TRequiredListValidator.IsValidList(checked, values, min, max, required);
-}
-
-//multiple selection check
-Prado.Validation.TRequiredListValidator.IsValidSelectMultipleList = function(elements, min, max, required)
-{
- var checked = 0;
- var values = new Array();
- for(var i = 0; i < elements.length; i++)
- {
- var selection = elements[i];
- for(var j = 0; j < selection.options.length; j++)
- {
- if(selection.options[j].selected)
- {
- checked++;
- values.push(selection.options[j].value);
- }
- }
- }
- return Prado.Validation.TRequiredListValidator.IsValidList(checked, values, min, max, required);
-}
-
-//check if the list was valid
-Prado.Validation.TRequiredListValidator.IsValidList = function(checkes, values, min, max, required)
-{
- var exists = true;
-
- if(required.length > 0)
- {
- //required and the values must at least be have same lengths
- if(values.length < required.length)
- return false;
- for(var k = 0; k < required.length; k++)
- exists = exists && values.contains(required[k]);
- }
-
- return exists && checkes >= min && checkes <= max;
-}
diff --git a/framework/Web/UI/WebControls/TBaseValidator.php b/framework/Web/UI/WebControls/TBaseValidator.php
index adbc85ae..4ca4c1f6 100644
--- a/framework/Web/UI/WebControls/TBaseValidator.php
+++ b/framework/Web/UI/WebControls/TBaseValidator.php
@@ -41,6 +41,10 @@
* and {@link setText Text} are empty, the body content of the validator will
* be displayed. Error display is controlled by {@link setDisplay Display} property.
*
+ * You can also customized the client-side behaviour by adding javascript
+ * code to the subproperties of the {@link getClientValidation ClientValidation}
+ * property.
+ *
* You can also place a {@link TValidationSummary} control on a page to display error messages
* from the validators together. In this case, only the {@link setErrorMessage ErrorMessage}
* property of the validators will be displayed in the {@link TValidationSummary} control.
@@ -75,6 +79,8 @@ abstract class TBaseValidator extends TLabel implements IValidator
* @var boolean whether the validator has been registered with the page
*/
private $_registered=false;
+
+ private $_clientScript;
/**
* Constructor.
@@ -145,8 +151,43 @@ abstract class TBaseValidator extends TLabel implements IValidator
$options['ControlToValidate'] = $control->getClientID();
$options['ControlCssClass'] = $this->getControlCssClass();
$options['ControlType'] = get_class($control);
+
+ if(!is_null($this->_clientScript))
+ $options = array_merge($options,$this->_clientScript->getOptions());
+
return $options;
}
+
+ /**
+ * Gets the TValidatorClientScript that allows modification of the client-
+ * side validator events.
+ *
+ * The client-side validator supports the following events.
+ * # <tt>OnValidate</tt> -- raised before client-side validation is
+ * executed.
+ * # <tt>OnSuccess</tt> -- raised after client-side validation is completed
+ * and is successfull, overrides default validator error messages updates.
+ * # <tt>OnError</tt> -- raised after client-side validation is completed
+ * and failed, overrides default validator error message updates.
+ *
+ * You can attach custom javascript code to each of these events
+ *
+ * @return TValidatorClientScript javascript validator event options.
+ */
+ public function getClientValidation()
+ {
+ if(is_null($this->_clientScript))
+ $this->_clientScript = $this->createClientScript();
+ return $this->_clientScript;
+ }
+
+ /**
+ * @return TValidatorClientScript javascript validator event options.
+ */
+ protected function createClientScript()
+ {
+ return new TValidatorClientScript($this->getPage()->getClientScript());
+ }
/**
* Renders the javascript code to the end script.
@@ -446,4 +487,74 @@ abstract class TBaseValidator extends TLabel implements IValidator
parent::renderContents($writer);
}
}
+
+/**
+ * TValidatorClientScript class.
+ *
+ * @todo Add doc to quickstart and classes.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Revision: $ $Date: $
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TValidatorClientScript extends TComponent
+{
+ private $_options;
+ private $_manager;
+ private $_effectsEnabled = false;
+
+ public function __construct($manager)
+ {
+ $this->_options = new TMap;
+ $this->_manager = $manager;
+ }
+
+ public function getOnValidate()
+ {
+ return $this->_options->itemAt['OnValidate'];
+ }
+
+ public function setOnValidate($javascript)
+ {
+ $this->_options->add('OnValidate', $this->ensureFunction($javascript));
+ }
+
+ public function setOnSuccess($javascript)
+ {
+ $this->_options->add('OnSuccess', $this->ensureFunction($javascript));
+ }
+
+ public function getOnSuccess()
+ {
+ return $this->_options->itemAt('OnSuccess');
+ }
+
+ public function setOnError($javascript)
+ {
+ $this->_options->add('OnError', $this->ensureFunction($javascript));
+ }
+
+ public function getOnError()
+ {
+ return $this->_options->itemAt('OnError');
+ }
+
+ public function getOptions()
+ {
+ return $this->_options->toArray();
+ }
+
+ private function ensureFunction($javascript)
+ {
+ if(TJavascript::isFunction($javascript))
+ return $javascript;
+ else
+ {
+ $code = "function(validator, invoker){ {$javascript} }";
+ return TJavascript::quoteFunction($code);
+ }
+ }
+}
+
?> \ No newline at end of file
diff --git a/framework/Web/UI/WebControls/TClientScript.php b/framework/Web/UI/WebControls/TClientScript.php
new file mode 100644
index 00000000..23aa1425
--- /dev/null
+++ b/framework/Web/UI/WebControls/TClientScript.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * TClientScript class file
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $Date: $
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TClientScript class
+ *
+ * Allows importing of Prado Client Scripts from template via the
+ * {@link setUsingPradoScripts UsingPradoScripts} property. Multiple Prado
+ * client-scripts can be specified using comma delimited string of the
+ * javascript library to include on the page. For example,
+ *
+ * <code>
+ * <com:TClientScript UsingPradoScripts="effects, rico" />
+ * </code>
+ *
+ * @TODO May be use it to include stylesheets as well.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Revision: $ $Date: $
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TClientScript extends TControl
+{
+ /**
+ * @return string comma delimited list of javascript libraries to included
+ * on the page.
+ */
+ public function getUsingPradoScripts()
+ {
+ return $this->getViewState('PradoScripts', '');
+ }
+
+ /**
+ * Include javascript library to the current page. The current supported
+ * libraries are: "prado", "effects", "ajax", "validator", "logger",
+ * "datepicker", "rico", "colorpicker". Library dependencies are
+ * automatically resolved.
+ *
+ * @param string comma delimited list of javascript libraries to include.
+ */
+ public function setUsingPradoScripts($value)
+ {
+ $this->setViewState('PradoScripts', $value, '');
+ }
+
+ /**
+ * Calls the client script manager to add each of the requested client
+ * script libraries.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $scripts = preg_split('/,|\s+/', $this->getUsingPradoScripts());
+ $cs = $this->getPage()->getClientScript();
+ foreach($scripts as $script)
+ {
+ $script = trim($script);
+ if(strlen($script) > 0)
+ $cs->registerPradoScript($script);
+ }
+ }
+}
+
+?> \ No newline at end of file
diff --git a/framework/Web/UI/WebControls/TLiteral.php b/framework/Web/UI/WebControls/TLiteral.php
index f335499f..60e4a6f6 100644
--- a/framework/Web/UI/WebControls/TLiteral.php
+++ b/framework/Web/UI/WebControls/TLiteral.php
@@ -80,7 +80,7 @@ class TLiteral extends TControl
$writer->write($text);
}
else
- parent::renderContents($writer);
+ parent::render($writer);
}
}
diff --git a/tests/FunctionalTests/features/protected/controls/Layout.tpl b/tests/FunctionalTests/features/protected/controls/Layout.tpl
index d1b33d94..dbd433b8 100644
--- a/tests/FunctionalTests/features/protected/controls/Layout.tpl
+++ b/tests/FunctionalTests/features/protected/controls/Layout.tpl
@@ -16,6 +16,11 @@
margin-top: 2em;
display: block;
}
+ .required
+ {
+ border:1px solid red;
+ background-color: #fdd;
+ }
/*]]>*/
</style>
</com:THead>
diff --git a/tests/FunctionalTests/features/protected/pages/ValidatorEffects.page b/tests/FunctionalTests/features/protected/pages/ValidatorEffects.page
new file mode 100644
index 00000000..47d99969
--- /dev/null
+++ b/tests/FunctionalTests/features/protected/pages/ValidatorEffects.page
@@ -0,0 +1,91 @@
+<com:TContent ID="Content">
+
+<h1>Validator Visual Effects Test</h1>
+<fieldset id="quickRegistration">
+ <legend>Create New Account</legend>
+
+<com:TClientScript UsingPradoScripts="effects" />
+
+<div class="username">
+ Username:
+ <com:TTextBox ID="Username" />
+ <com:TRequiredFieldValidator
+ ID="UsernameVal"
+ ControlToValidate="Username"
+ ValidationGroup="registration"
+ ControlCssClass="required"
+ Display="Dynamic"
+ ErrorMessage="a username is required.">
+ <prop:ClientValidation.OnError>
+ Effect.Shake(validator.control);
+ Effect.Appear(validator.message);
+ </prop:ClientValidation.OnError>
+ <prop:ClientValidation.OnSuccess>
+ Effect.Fade(validator.message);
+ </prop:ClientValidation.OnSuccess>
+ </com:TRequiredFieldValidator>
+</div>
+<div class="password">
+ Password
+ <com:TTextBox ID="Password" TextMode="Password" />
+ <!-- alternate synatx : see
+ http://encytemedia.com/blog/articles/2006/03/07/prototype-gets-some-serious-syntactic-sugar
+ -->
+<com:TRequiredFieldValidator
+ ID="PasswordVal"
+ ControlToValidate="Password"
+ ValidationGroup="registration"
+ ControlCssClass="required"
+ Display="Dynamic"
+ ClientValidation.OnError="validator.message.visualEffect('appear')"
+ ClientValidation.OnSuccess="validator.message.visualEffect('fade')"
+ ErrorMessage="a password is required." />
+</div>
+<div class="create">
+ <com:TButton ID="Create" ValidationGroup="registration" Text="Create New Account"/>
+</div>
+
+</fieldset>
+
+
+<fieldset id="LoginForm">
+ <legend>Sign In</legend>
+
+<div class="username">
+ Login Name:
+ <com:TTextBox ID="UserID" />
+
+ <com:TRequiredFieldValidator
+ ID="UserVal1"
+ ControlToValidate="UserID"
+ Display="None"
+ ValidationGroup="signin"
+ ErrorMessage="the username or email was not provided" />
+</div>
+
+<div class="password" >
+ Password:
+ <com:TTextBox ID="Pass" TextMode="Password" />
+ <com:TRequiredFieldValidator
+ ID="loginValidator3"
+ ControlToValidate="Pass"
+ Display="None"
+ ValidationGroup="signin"
+ ErrorMessage="the password was not provided" />
+</div>
+
+
+<com:TButton ID="login" ValidationGroup="signin" CssClass="button" Text="Sign In" />
+
+<div class="validation">
+ <com:TValidationSummary
+ ID="summary2"
+ ValidationGroup="signin"
+ AutoUpdate="false"
+ HeaderText="<p>You could not login because</p>" />
+</div>
+
+</fieldset>
+
+
+</com:TContent> \ No newline at end of file
diff --git a/tests/FunctionalTests/quickstart/Controls/ExpressionTestCase.php b/tests/FunctionalTests/quickstart/Controls/ExpressionTestCase.php
new file mode 100644
index 00000000..dfa1036f
--- /dev/null
+++ b/tests/FunctionalTests/quickstart/Controls/ExpressionTestCase.php
@@ -0,0 +1,15 @@
+<?php
+
+class ExpressionTestCase extends SeleniumTestCase
+{
+ function test ()
+ {
+ $this->open("../../demos/quickstart/index.php?page=Controls.Samples.TExpression.Home&amp;notheme=true", "");
+
+ $this->verifyTitle("PRADO QuickStart Sample", "");
+
+ $this->verifyTextPresent('PRADO QuickStart Sample');
+ }
+}
+
+?> \ No newline at end of file
diff --git a/tests/FunctionalTests/quickstart/Controls/HtmlAreaTestCase.php b/tests/FunctionalTests/quickstart/Controls/HtmlAreaTestCase.php
new file mode 100644
index 00000000..212ff6b9
--- /dev/null
+++ b/tests/FunctionalTests/quickstart/Controls/HtmlAreaTestCase.php
@@ -0,0 +1,15 @@
+<?php
+
+class HtmlAreaTestCase extends SeleniumTestCase
+{
+ function test ()
+ {
+ $this->open("../../demos/quickstart/index.php?page=Controls.Samples.THtmlArea.Home&amp;notheme=true", "");
+
+ $this->verifyTitle("PRADO QuickStart Sample", "");
+
+ // can't perform any test
+ }
+}
+
+?> \ No newline at end of file
diff --git a/tests/FunctionalTests/quickstart/Controls/MultiViewTestCase.php b/tests/FunctionalTests/quickstart/Controls/MultiViewTestCase.php
new file mode 100644
index 00000000..c94a325c
--- /dev/null
+++ b/tests/FunctionalTests/quickstart/Controls/MultiViewTestCase.php
@@ -0,0 +1,38 @@
+<?php
+
+class MultiViewTestCase extends SeleniumTestCase
+{
+ function test ()
+ {
+ $this->open("../../demos/quickstart/index.php?page=Controls.Samples.TMultiView.Home&amp;notheme=true", "");
+
+ $this->verifyTitle("PRADO QuickStart Sample", "");
+
+ // view 1 : type in a string
+ $this->verifyNotVisible('ctl0_body_Result1');
+ $this->verifyNotVisible('ctl0_body_Result2');
+ $this->type('ctl0_body_Memo','test');
+ $this->clickAndWait('ctl0$body$ctl1');
+
+ // view 3 : check if the output is updated
+ $this->verifyTextPresent('Your text input is: test');
+ $this->verifyTextPresent('Your color choice is: Red');
+ $this->clickAndWait('ctl0$body$ctl7');
+
+ // view 2 : update dropdownlist
+ $this->verifyNotVisible('ctl0_body_Result1');
+ $this->verifyNotVisible('ctl0_body_Result2');
+ $this->select('ctl0$body$DropDownList', "label=Blue");
+ $this->clickAndWait('ctl0$body$ctl4');
+
+ // view 3 : check if the output is updated
+ $this->verifyTextPresent('Your text input is: test');
+ $this->verifyTextPresent('Your color choice is: Blue');
+ $this->clickAndWait('ctl0$body$ctl7');
+
+ // view 2 : check if dropdownlist maintains state
+ $this->verifySelected('ctl0$body$DropDownList', "label=Blue");
+ }
+}
+
+?> \ No newline at end of file
diff --git a/tests/FunctionalTests/quickstart/Controls/StatementsTestCase.php b/tests/FunctionalTests/quickstart/Controls/StatementsTestCase.php
new file mode 100644
index 00000000..93844296
--- /dev/null
+++ b/tests/FunctionalTests/quickstart/Controls/StatementsTestCase.php
@@ -0,0 +1,15 @@
+<?php
+
+class StatementsTestCase extends SeleniumTestCase
+{
+ function test ()
+ {
+ $this->open("../../demos/quickstart/index.php?page=Controls.Samples.TStatements.Home&amp;notheme=true", "");
+
+ $this->verifyTitle("PRADO QuickStart Sample", "");
+
+ $this->verifyTextPresent('UniqueID is \'ctl0$body$ctl0\'');
+ }
+}
+
+?> \ No newline at end of file
diff --git a/tests/FunctionalTests/quickstart/Controls/Wizard1TestCase.php b/tests/FunctionalTests/quickstart/Controls/Wizard1TestCase.php
new file mode 100644
index 00000000..ea071612
--- /dev/null
+++ b/tests/FunctionalTests/quickstart/Controls/Wizard1TestCase.php
@@ -0,0 +1,26 @@
+<?php
+
+class Wizard1TestCase extends SeleniumTestCase
+{
+ function test ()
+ {
+ $this->open("../../demos/quickstart/index.php?page=Controls.Samples.TWizard.Sample1&amp;notheme=true", "");
+
+ $this->verifyTitle("PRADO QuickStart Sample", "");
+
+ // step 1
+ $this->verifyTextPresent('Wizard Step 1');
+ $this->verifyTextNotPresent('Wizard Step 2');
+ $this->verifyVisible('ctl0_body_Wizard1_SideBarList_ctl0_SideBarButton');
+ $this->verifyAttribute('ctl0_body_Wizard1_SideBarList_ctl1_SideBarButton@disabled','regexp:true|disabled');
+ $this->select('ctl0$body$Wizard1$DropDownList1', "label=Purple");
+ $this->clickAndWait('ctl0$body$Wizard1$ctl8$ctl1');
+
+ // step 2
+ $this->verifyTextPresent('Your favorite color is: Purple');
+ $this->verifyTextNotPresent('Wizard Step 1');
+ $this->verifyTextPresent('Wizard Step 2');
+ }
+}
+
+?> \ No newline at end of file
diff --git a/tests/FunctionalTests/quickstart/Controls/Wizard2TestCase.php b/tests/FunctionalTests/quickstart/Controls/Wizard2TestCase.php
new file mode 100644
index 00000000..ca94bb19
--- /dev/null
+++ b/tests/FunctionalTests/quickstart/Controls/Wizard2TestCase.php
@@ -0,0 +1,26 @@
+<?php
+
+class Wizard2TestCase extends SeleniumTestCase
+{
+ function test ()
+ {
+ $this->open("../../demos/quickstart/index.php?page=Controls.Samples.TWizard.Sample2&amp;notheme=true", "");
+
+ $this->verifyTitle("PRADO QuickStart Sample", "");
+
+ // step 1
+ $this->verifyTextPresent('Please let us know your preference');
+ $this->verifyTextNotPresent('Thank you for your answer');
+ $this->verifyVisible('ctl0_body_Wizard1_SideBarList_ctl0_SideBarButton');
+ $this->verifyAttribute('ctl0_body_Wizard1_SideBarList_ctl1_SideBarButton@disabled','regexp:true|disabled');
+ $this->select('ctl0$body$Wizard1$DropDownList1', "label=Blue");
+ $this->clickAndWait('ctl0$body$Wizard1$ctl8$ctl1');
+
+ // step 2
+ $this->verifyTextPresent('Your favorite color is: Blue');
+ $this->verifyTextNotPresent('Please let us know your preference');
+ $this->verifyTextPresent('Thank you for your answer');
+ }
+}
+
+?> \ No newline at end of file
diff --git a/tests/FunctionalTests/quickstart/Controls/Wizard3TestCase.php b/tests/FunctionalTests/quickstart/Controls/Wizard3TestCase.php
new file mode 100644
index 00000000..807e7dc6
--- /dev/null
+++ b/tests/FunctionalTests/quickstart/Controls/Wizard3TestCase.php
@@ -0,0 +1,46 @@
+<?php
+
+class Wizard3TestCase extends SeleniumTestCase
+{
+ function test ()
+ {
+ $this->open("../../demos/quickstart/index.php?page=Controls.Samples.TWizard.Sample3&amp;notheme=true", "");
+
+ $this->verifyTitle("PRADO QuickStart Sample", "");
+
+ // step 1
+ $this->verifyTextPresent('A Mini Survey');
+ $this->verifyTextPresent('PRADO QuickStart Sample');
+ $this->click('ctl0_body_Wizard3_StudentCheckBox');
+ $this->clickAndWait('ctl0$body$Wizard3$ctl8$ctl0');
+
+ // step 2
+ $this->select('ctl0$body$Wizard3$DropDownList11', "label=Chemistry");
+ $this->clickAndWait('ctl0$body$Wizard3$ctl9$ctl1');
+
+ // step 3
+ $this->select('ctl0$body$Wizard3$DropDownList22', "label=Tennis");
+ $this->clickAndWait('ctl0$body$Wizard3$ctl10$ctl1');
+
+ // step 4
+ $this->verifyTextPresent('You are a college student');
+ $this->verifyTextPresent('You are in major: Chemistry');
+ $this->verifyTextPresent('Your favorite sport is: Tennis');
+
+ // run the example again. this time we skip the page asking about major
+ $this->open("../../demos/quickstart/index.php?page=Controls.Samples.TWizard.Sample3&amp;notheme=true", "");
+
+ // step 1
+ $this->clickAndWait('ctl0$body$Wizard3$ctl8$ctl0');
+
+ // step 3
+ $this->select('ctl0$body$Wizard3$DropDownList22', "label=Baseball");
+ $this->clickAndWait('ctl0$body$Wizard3$ctl10$ctl1');
+
+ // step 4
+ $this->verifyTextNotPresent('You are a college student');
+ $this->verifyTextPresent('Your favorite sport is: Baseball');
+ }
+}
+
+?> \ No newline at end of file
diff --git a/tests/FunctionalTests/quickstart/Controls/Wizard4TestCase.php b/tests/FunctionalTests/quickstart/Controls/Wizard4TestCase.php
new file mode 100644
index 00000000..41fd7dd2
--- /dev/null
+++ b/tests/FunctionalTests/quickstart/Controls/Wizard4TestCase.php
@@ -0,0 +1,44 @@
+<?php
+
+class Wizard4TestCase extends SeleniumTestCase
+{
+ function test ()
+ {
+ $this->open("../../demos/quickstart/index.php?page=Controls.Samples.TWizard.Sample4&amp;notheme=true", "");
+
+ $this->verifyTitle("PRADO QuickStart Sample", "");
+
+ // step 1
+ $this->verifyTextPresent('Step 1 of 3');
+ $this->select('ctl0_body_Wizard1_DropDownList1', "label=Cyan");
+ $this->clickAndWait('ctl0_body_Wizard1_SideBarList_ctl2_SideBarButton');
+
+ // step 3
+ $this->verifyTextPresent('Step 3 of 3');
+ $this->verifyTextPresent('Thank you for completing this survey.');
+ $this->clickAndWait('ctl0_body_Wizard1_SideBarList_ctl0_SideBarButton');
+
+ // step 1
+ $this->verifySelected('ctl0_body_Wizard1_DropDownList1', "label=Cyan");
+ $this->select('ctl0_body_Wizard1_DropDownList1', "label=Black");
+ $this->clickAndWait('ctl0_body_Wizard1_ctl4_ctl0');
+
+ // step 2
+ $this->verifyTextPresent('Step 2 of 3');
+ $this->verifyTextPresent('Your favorite color is: Black');
+ $this->clickAndWait('ctl0_body_Wizard1_ctl5_ctl0');
+
+ // step 1
+ $this->verifyTextPresent('Step 1 of 3');
+ $this->verifySelected('ctl0_body_Wizard1_DropDownList1', "label=Black");
+ $this->clickAndWait('ctl0_body_Wizard1_ctl4_ctl0');
+
+ // step 2
+ $this->clickAndWait('ctl0_body_Wizard1_ctl5_ctl1');
+
+ // step 3
+ $this->verifyTextPresent('Step 3 of 3');
+ }
+}
+
+?> \ No newline at end of file
diff --git a/tests/FunctionalTests/quickstart/Controls/Wizard5TestCase.php b/tests/FunctionalTests/quickstart/Controls/Wizard5TestCase.php
new file mode 100644
index 00000000..e25ce86d
--- /dev/null
+++ b/tests/FunctionalTests/quickstart/Controls/Wizard5TestCase.php
@@ -0,0 +1,37 @@
+<?php
+
+class Wizard5TestCase extends SeleniumTestCase
+{
+ function test ()
+ {
+ $this->open("../../demos/quickstart/index.php?page=Controls.Samples.TWizard.Sample5&amp;notheme=true", "");
+
+ $this->verifyTitle("PRADO QuickStart Sample", "");
+
+ // step 1
+ $this->verifyTextPresent('Please let us know your preference');
+ $this->verifyVisible('ctl0_body_Wizard1_SideBarList_ctl0_SideBarButton');
+ $this->verifyVisible('ctl0_body_Wizard1_SideBarList_ctl1_SideBarButton');
+ $this->verifyAttribute('ctl0_body_Wizard1_SideBarList_ctl2_SideBarButton@disabled','regexp:true|disabled');
+ $this->select('ctl0_body_Wizard1_DropDownList1', "label=Cyan");
+ $this->clickAndWait('ctl0$body$Wizard1$ctl6$ctl0');
+
+ // step 2
+ $this->select('ctl0_body_Wizard1_Step2_DropDownList2','label=Football');
+ $this->clickAndWait('ctl0$body$Wizard1$ctl8$ctl0');
+
+ // step 1
+ $this->verifySelected('ctl0_body_Wizard1_DropDownList1','label=Cyan');
+ $this->clickAndWait('ctl0_body_Wizard1_SideBarList_ctl1_SideBarButton');
+
+ // step 2
+ $this->verifySelected('ctl0_body_Wizard1_Step2_DropDownList2','label=Football');
+ $this->clickAndWait('ctl0$body$Wizard1$ctl8$ctl1');
+
+ // step 3
+ $this->verifyTextPresent('Your favorite color is: Cyan');
+ $this->verifyTextPresent('Your favorite sport is: Football');
+ }
+}
+
+?> \ No newline at end of file