From 0226f8f5f430d34b3cead40c4eb7b458933d16c6 Mon Sep 17 00:00:00 2001 From: wei <> Date: Wed, 18 Jan 2006 04:20:26 +0000 Subject: update javascript library and usage in web controls --- framework/Web/Javascripts/TClientScript.php | 139 ++++ framework/Web/Javascripts/TJSON.php | 761 +++++++++++++++++++++ .../Web/Javascripts/TJavascriptSerializer.php | 141 ++++ framework/Web/Javascripts/build.bat | 2 - framework/Web/Javascripts/extended/base.js | 2 +- framework/Web/Javascripts/extended/event.js | 18 +- framework/Web/Javascripts/js/prado.js | 131 ++-- framework/Web/Javascripts/prado/controls.js | 92 ++- framework/Web/Javascripts/prado/form.js | 37 +- framework/Web/UI/TClientScriptManager.php | 355 ++-------- framework/Web/UI/TControl.php | 7 + framework/Web/UI/TPage.php | 4 +- framework/Web/UI/WebControls/TBaseValidator.php | 5 +- framework/Web/UI/WebControls/TBulletedList.php | 90 ++- framework/Web/UI/WebControls/TButton.php | 42 +- framework/Web/UI/WebControls/TCheckBox.php | 22 +- framework/Web/UI/WebControls/THead.php | 4 +- framework/Web/UI/WebControls/TJavascriptLogger.php | 2 +- framework/Web/UI/WebControls/TLinkButton.php | 32 +- framework/Web/UI/WebControls/TListControl.php | 16 +- framework/Web/UI/WebControls/TPanel.php | 4 +- framework/Web/UI/WebControls/TRadioButton.php | 7 +- framework/Web/UI/WebControls/TSafeHtml.php | 42 ++ framework/Web/UI/WebControls/TTextBox.php | 19 +- .../Web/UI/WebControls/TValidationSummary.php | 9 +- 25 files changed, 1481 insertions(+), 502 deletions(-) create mode 100644 framework/Web/Javascripts/TClientScript.php create mode 100644 framework/Web/Javascripts/TJSON.php create mode 100644 framework/Web/Javascripts/TJavascriptSerializer.php delete mode 100644 framework/Web/Javascripts/build.bat create mode 100644 framework/Web/UI/WebControls/TSafeHtml.php (limited to 'framework/Web') diff --git a/framework/Web/Javascripts/TClientScript.php b/framework/Web/Javascripts/TClientScript.php new file mode 100644 index 00000000..5f11758a --- /dev/null +++ b/framework/Web/Javascripts/TClientScript.php @@ -0,0 +1,139 @@ +base basic javascript utilities, e.g. $() + * - dom DOM and Form functions, e.g. $F(inputID) to retrive form input values. + * - effects Effects such as fade, shake, move + * - controls Prado client-side components, e.g. Slider, AJAX components + * - validator Prado client-side validators. + * - ajax Prado AJAX library including Prototype's AJAX and JSON. + * + * Dependencies for each library are automatically resolved. + * + * Namespace: System.Web.UI + * + * @author Wei Zhuo + * @version $Revision: 1.1 $ $Date: 2005/11/06 23:02:33 $ + * @package System.Web.UI + */ +class TClientScript +{ + protected $_manager; + + /** + * Client-side javascript library dependencies + * @var array + */ + protected static $_dependencies = array( + 'prado' => array('prado'), + 'effects' => array('prado', 'effects'), + 'ajax' => array('prado', 'effects', 'ajax'), + 'validator' => array('prado', 'validator'), + 'logger' => array('prado', 'logger'), + 'datepicker' => array('prado', 'datepicker'), + 'rico' => array('prado', 'effects', 'ajax', 'rico') + ); + + public function __construct($manager) + { + $this->_manager = $manager; + } + + /** + * Resolve dependencies for the given library. + * @param array list of libraries to load. + * @return array list of libraries including its dependencies. + */ + public function getScripts($scripts) + { + $files = array(); + if(!is_array($scripts)) $scripts = array($scripts); + foreach($scripts as $script) + { + if(isset(self::$_dependencies[$script])) + $files = array_merge($files, self::$_dependencies[$script]); + $files[] = $script; + } + $files = array_unique($files); + return $files; + } + + + /** + * TODO: clean up + * + public function getPostBackEventReference($control,$parameter='',$options=null,$javascriptPrefix=true) + { + if(!$options || (!$options->getPerformValidation() && !$options->getTrackFocus() && $options->getClientSubmit() && $options->getActionUrl()=='')) + { + $this->registerPostBackScript(); + if(($form=$this->_page->getForm())!==null) + $formID=$form->getClientID(); + else + throw new TConfigurationException('clientscriptmanager_form_required'); + $postback=self::POSTBACK_FUNC.'(\''.$formID.'\',\''.$control->getUniqueID().'\',\''.THttpUtility::quoteJavaScriptString($parameter).'\')'; + if($options && $options->getAutoPostBack()) + $postback='setTimeout(\''.THttpUtility::quoteJavaScriptString($postback).'\',0)'; + return $javascriptPrefix?'javascript:'.$postback:$postback; + } + $opt=''; + $flag=false; + if($options->getPerformValidation()) + { + $flag=true; + $this->registerValidationScript(); + $opt.=',true,'; + } + else + $opt.=',false,'; + if($options->getValidationGroup()!=='') + { + $flag=true; + $opt.='"'.$options->getValidationGroup().'",'; + } + else + $opt.='\'\','; + if($options->getActionUrl()!=='') + { + $flag=true; + $this->_page->setCrossPagePostBack(true); + $opt.='"'.$options->getActionUrl().'",'; + } + else + $opt.='null,'; + if($options->getTrackFocus()) + { + $flag=true; + $this->registerFocusScript(); + $opt.='true,'; + } + else + $opt.='false,'; + if($options->getClientSubmit()) + { + $flag=true; + $opt.='true'; + } + else + $opt.='false'; + if(!$flag) + return ''; + $this->registerPostBackScript(); + if(($form=$this->_page->getForm())!==null) + $formID=$form->getClientID(); + else + throw new TConfigurationException('clientscriptmanager_form_required'); + $postback=self::POSTBACK_FUNC.'(\''.$formID.'\',\''.$control->getUniqueID().'\',\''.THttpUtility::quoteJavaScriptString($parameter).'\''.$opt.')'; + if($options && $options->getAutoPostBack()) + $postback='setTimeout(\''.THttpUtility::quoteJavaScriptString($postback).'\',0)'; + return $javascriptPrefix?'javascript:'.$postback:$postback; + }*/ + +} + +?> \ No newline at end of file diff --git a/framework/Web/Javascripts/TJSON.php b/framework/Web/Javascripts/TJSON.php new file mode 100644 index 00000000..76a19d27 --- /dev/null +++ b/framework/Web/Javascripts/TJSON.php @@ -0,0 +1,761 @@ + +* @author Matt Knapp +* @author Brett Stimmerman +* @copyright 2005 Michal Migurski +* @license http://www.opensource.org/licenses/bsd-license.php +* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 +*/ + +/** +* Converts to and from JSON format. +* +* @package System.Web.Services.AJAX +* @author Michal Migurski +* @author Matt Knapp +* @author Brett Stimmerman +* @copyright 2005 Michal Migurski +* @license http://www.php.net/license/3_0.txt PHP License 3.0 +*/ +class TJSON +{ + /** + * Marker constant for JSON::decode(), used to flag stack state + */ + const JSON_SLICE = 1; + + /** + * Marker constant for JSON::decode(), used to flag stack state + */ + const JSON_IN_STR = 2; + + /** + * Marker constant for JSON::decode(), used to flag stack state + */ + const JSON_IN_ARR = 4; + + /** + * Marker constant for JSON::decode(), used to flag stack state + */ + const JSON_IN_OBJ = 8; + + /** + * Marker constant for JSON::decode(), used to flag stack state + */ + const JSON_IN_CMT = 16; + + /** + * Behavior switch for JSON::decode() + */ + const JSON_LOOSE_TYPE = 10; + + /** + * Behavior switch for JSON::decode() + */ + const JSON_STRICT_TYPE = 11; + + /** + * constructs a new JSON instance + * + * @param int $use object behavior: when encoding or decoding, + * be loose or strict about object/array usage + * + * possible values: + * self::JSON_STRICT_TYPE - strict typing, default + * "{...}" syntax creates objects in decode. + * self::JSON_LOOSE_TYPE - loose typing + * "{...}" syntax creates associative arrays in decode. + */ + public function __construct($use=self::JSON_STRICT_TYPE) + { + $this->use = $use; + } + + /** + * encodes an arbitrary variable into JSON format + * + * @param mixed $var any number, boolean, string, array, or object to be encoded. + * see argument 1 to JSON() above for array-parsing behavior. + * if var is a strng, note that encode() always expects it + * to be in ASCII or UTF-8 format! + * + * @return string JSON string representation of input var + * @access public + */ + public function encode($var) + { + switch (gettype($var)) { + case 'boolean': + return $var ? 'true' : 'false'; + + case 'NULL': + return 'null'; + + case 'integer': + return (int) $var; + + case 'double': + case 'float': + return (float) $var; + + case 'string': + // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT + $ascii = ''; + $strlen_var = strlen($var); + + /* + * Iterate over every character in the string, + * escaping with a slash or encoding to UTF-8 where necessary + */ + for ($c = 0; $c < $strlen_var; ++$c) { + + $ord_var_c = ord($var{$c}); + + switch (true) { + case $ord_var_c == 0x08: + $ascii .= '\b'; + break; + case $ord_var_c == 0x09: + $ascii .= '\t'; + break; + case $ord_var_c == 0x0A: + $ascii .= '\n'; + break; + case $ord_var_c == 0x0C: + $ascii .= '\f'; + break; + case $ord_var_c == 0x0D: + $ascii .= '\r'; + break; + + case $ord_var_c == 0x22: + case $ord_var_c == 0x2F: + case $ord_var_c == 0x5C: + // double quote, slash, slosh + $ascii .= '\\'.$var{$c}; + break; + + case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): + // characters U-00000000 - U-0000007F (same as ASCII) + $ascii .= $var{$c}; + break; + + case (($ord_var_c & 0xE0) == 0xC0): + // characters U-00000080 - U-000007FF, mask 110XXXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, ord($var{$c+1})); + $c+=1; + $utf16 = $this->utf8_to_utf16be($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF0) == 0xE0): + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c+1}), + ord($var{$c+2})); + $c+=2; + $utf16 = $this->utf8_to_utf16be($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF8) == 0xF0): + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c+1}), + ord($var{$c+2}), + ord($var{$c+3})); + $c+=3; + $utf16 = $this->utf8_to_utf16be($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFC) == 0xF8): + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c+1}), + ord($var{$c+2}), + ord($var{$c+3}), + ord($var{$c+4})); + $c+=4; + $utf16 = $this->utf8_to_utf16be($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFE) == 0xFC): + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c+1}), + ord($var{$c+2}), + ord($var{$c+3}), + ord($var{$c+4}), + ord($var{$c+5})); + $c+=5; + $utf16 = $this->utf8_to_utf16be($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + } + } + + return '"'.$ascii.'"'; + + case 'array': + /* + * As per JSON spec if any array key is not an integer + * we must treat the the whole array as an object. We + * also try to catch a sparsely populated associative + * array with numeric keys here because some JS engines + * will create an array with empty indexes up to + * max_index which can cause memory issues and because + * the keys, which may be relevant, will be remapped + * otherwise. + * + * As per the ECMA and JSON specification an object may + * have any string as a property. Unfortunately due to + * a hole in the ECMA specification if the key is a + * ECMA reserved word or starts with a digit the + * parameter is only accessible using ECMAScript's + * bracket notation. + */ + + // treat as a JSON object + if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { + return '{' . + join(',', array_map(array($this, 'name_value'), + array_keys($var), + array_values($var))) + . '}'; + } + + // treat it like a regular array + return '[' . join(',', array_map(array($this, 'encode'), $var)) . ']'; + + case 'object': + $vars = get_object_vars($var); + return '{' . + join(',', array_map(array($this, 'name_value'), + array_keys($vars), + array_values($vars))) + . '}'; + + default: + return ''; + } + } + + /** + * encodes an arbitrary variable into JSON format, alias for encode() + * @see JSON::encode() + * + * @param mixed $var any number, boolean, string, array, or object to be encoded. + * see argument 1 to JSON() above for array-parsing behavior. + * if var is a strng, note that encode() always expects it + * to be in ASCII or UTF-8 format! + * + * @return string JSON string representation of input var + * @access public + */ + public function enc($var) + { + return $this->encode($var); + } + + /** function name_value + * array-walking function for use in generating JSON-formatted name-value pairs + * + * @param string $name name of key to use + * @param mixed $value reference to an array element to be encoded + * + * @return string JSON-formatted name-value pair, like '"name":value' + * @access private + */ + protected function name_value($name, $value) + { + return $this->encode(strval($name)) . ':' . $this->encode($value); + } + + /** + * reduce a string by removing leading and trailing comments and whitespace + * + * @param $str string string value to strip of comments and whitespace + * + * @return string string value stripped of comments and whitespace + * @access private + */ + protected function reduce_string($str) + { + $str = preg_replace(array( + + // eliminate single line comments in '// ...' form + '#^\s*//(.+)$#m', + + // eliminate multi-line comments in '/* ... */' form, at start of string + '#^\s*/\*(.+)\*/#Us', + + // eliminate multi-line comments in '/* ... */' form, at end of string + '#/\*(.+)\*/\s*$#Us' + + ), '', $str); + + // eliminate extraneous space + return trim($str); + } + + /** + * decodes a JSON string into appropriate variable + * + * @param string $str JSON-formatted string + * + * @return mixed number, boolean, string, array, or object + * corresponding to given JSON input string. + * See argument 1 to JSON() above for object-output behavior. + * Note that decode() always returns strings + * in ASCII or UTF-8 format! + * @access public + */ + public function decode($str) + { + $str = $this->reduce_string($str); + + switch (strtolower($str)) { + case 'true': + return true; + + case 'false': + return false; + + case 'null': + return null; + + default: + if (is_numeric($str)) { + // Lookie-loo, it's a number + + // This would work on its own, but I'm trying to be + // good about returning integers where appropriate: + // return (float)$str; + + // Return float or int, as appropriate + return ((float)$str == (integer)$str) + ? (integer)$str + : (float)$str; + + } elseif (preg_match('/^("|\').+(\1)$/s', $str, $m) && $m[1] == $m[2]) { + // STRINGS RETURNED IN UTF-8 FORMAT + $delim = substr($str, 0, 1); + $chrs = substr($str, 1, -1); + $utf8 = ''; + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c < $strlen_chrs; ++$c) { + + $substr_chrs_c_2 = substr($chrs, $c, 2); + $ord_chrs_c = ord($chrs{$c}); + + switch (true) { + case $substr_chrs_c_2 == '\b': + $utf8 .= chr(0x08); + ++$c; + break; + case $substr_chrs_c_2 == '\t': + $utf8 .= chr(0x09); + ++$c; + break; + case $substr_chrs_c_2 == '\n': + $utf8 .= chr(0x0A); + ++$c; + break; + case $substr_chrs_c_2 == '\f': + $utf8 .= chr(0x0C); + ++$c; + break; + case $substr_chrs_c_2 == '\r': + $utf8 .= chr(0x0D); + ++$c; + break; + + case $substr_chrs_c_2 == '\\"': + case $substr_chrs_c_2 == '\\\'': + case $substr_chrs_c_2 == '\\\\': + case $substr_chrs_c_2 == '\\/': + if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || + ($delim == "'" && $substr_chrs_c_2 != '\\"')) { + $utf8 .= $chrs{++$c}; + } + break; + + case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): + // single, escaped unicode character + $utf16 = chr(hexdec(substr($chrs, ($c+2), 2))) + . chr(hexdec(substr($chrs, ($c+4), 2))); + $utf8 .= $this->utf16be_to_utf8($utf16); + $c+=5; + break; + + case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): + $utf8 .= $chrs{$c}; + break; + + case ($ord_chrs_c & 0xE0) == 0xC0: + // characters U-00000080 - U-000007FF, mask 110XXXXX + //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 2); + ++$c; + break; + + case ($ord_chrs_c & 0xF0) == 0xE0: + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 3); + $c += 2; + break; + + case ($ord_chrs_c & 0xF8) == 0xF0: + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 4); + $c += 3; + break; + + case ($ord_chrs_c & 0xFC) == 0xF8: + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 5); + $c += 4; + break; + + case ($ord_chrs_c & 0xFE) == 0xFC: + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 6); + $c += 5; + break; + + } + + } + + return $utf8; + + } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { + // array, or object notation + + if ($str{0} == '[') { + $stk = array(self::JSON_IN_ARR); + $arr = array(); + } else { + if ($this->use == self::JSON_LOOSE_TYPE) { + $stk = array(self::JSON_IN_OBJ); + $obj = array(); + } else { + $stk = array(self::JSON_IN_OBJ); + $obj = new stdClass(); + } + } + + array_push($stk, array('what' => self::JSON_SLICE, + 'where' => 0, + 'delim' => false)); + + $chrs = substr($str, 1, -1); + $chrs = $this->reduce_string($chrs); + + if ($chrs == '') { + if (reset($stk) == self::JSON_IN_ARR) { + return $arr; + + } else { + return $obj; + + } + } + + //print("\nparsing {$chrs}\n"); + + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c <= $strlen_chrs; ++$c) { + + $top = end($stk); + $substr_chrs_c_2 = substr($chrs, $c, 2); + + if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == self::JSON_SLICE))) { + // found a comma that is not inside a string, array, etc., + // OR we've reached the end of the character list + $slice = substr($chrs, $top['where'], ($c - $top['where'])); + array_push($stk, array('what' => self::JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); + //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + if (reset($stk) == self::JSON_IN_ARR) { + // we are in an array, so just push an element onto the stack + array_push($arr, $this->decode($slice)); + + } elseif (reset($stk) == self::JSON_IN_OBJ) { + // we are in an object, so figure + // out the property name and set an + // element in an associative array, + // for now + if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // "name":value pair + $key = $this->decode($parts[1]); + $val = $this->decode($parts[2]); + + if ($this->use == self::JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // name:value pair, where name is unquoted + $key = $parts[1]; + $val = $this->decode($parts[2]); + + if ($this->use == self::JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } + + } + + } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != self::JSON_IN_STR)) { + // found a quote, and we are not inside a string + array_push($stk, array('what' => self::JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); + //print("Found start of string at {$c}\n"); + + } elseif (($chrs{$c} == $top['delim']) && + ($top['what'] == self::JSON_IN_STR) && + (($chrs{$c - 1} != "\\") || + ($chrs{$c - 1} == "\\" && $chrs{$c - 2} == "\\"))) { + // found a quote, we're in a string, and it's not escaped + array_pop($stk); + //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '[') && + in_array($top['what'], array(self::JSON_SLICE, self::JSON_IN_ARR, self::JSON_IN_OBJ))) { + // found a left-bracket, and we are in an array, object, or slice + array_push($stk, array('what' => self::JSON_IN_ARR, 'where' => $c, 'delim' => false)); + //print("Found start of array at {$c}\n"); + + } elseif (($chrs{$c} == ']') && ($top['what'] == self::JSON_IN_ARR)) { + // found a right-bracket, and we're in an array + array_pop($stk); + //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '{') && + in_array($top['what'], array(self::JSON_SLICE, self::JSON_IN_ARR, self::JSON_IN_OBJ))) { + // found a left-brace, and we are in an array, object, or slice + array_push($stk, array('what' => self::JSON_IN_OBJ, 'where' => $c, 'delim' => false)); + //print("Found start of object at {$c}\n"); + + } elseif (($chrs{$c} == '}') && ($top['what'] == self::JSON_IN_OBJ)) { + // found a right-brace, and we're in an object + array_pop($stk); + //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($substr_chrs_c_2 == '/*') && + in_array($top['what'], array(self::JSON_SLICE, self::JSON_IN_ARR, self::JSON_IN_OBJ))) { + // found a comment start, and we are in an array, object, or slice + array_push($stk, array('what' => self::JSON_IN_CMT, 'where' => $c, 'delim' => false)); + $c++; + //print("Found start of comment at {$c}\n"); + + } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == self::JSON_IN_CMT)) { + // found a comment end, and we're in one now + array_pop($stk); + $c++; + + for ($i = $top['where']; $i <= $c; ++$i) + $chrs = substr_replace($chrs, ' ', $i, 1); + + //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } + + } + + if (reset($stk) == self::JSON_IN_ARR) { + return $arr; + + } elseif (reset($stk) == self::JSON_IN_OBJ) { + return $obj; + + } + + } + } + } + + /** + * decodes a JSON string into appropriate variable; alias for decode() + * @see JSON::decode() + * + * @param string $str JSON-formatted string + * + * @return mixed number, boolean, string, array, or object + * corresponding to given JSON input string. + * See argument 1 to JSON() above for object-output behavior. + * Note that decode() always returns strings + * in ASCII or UTF-8 format! + */ + public function dec($var) + { + return $this->decode($var); + } + + + /** + * This function returns any UTF-8 encoded text as a list of + * Unicode values: + * + * @author Scott Michael Reynen + * @link http://www.randomchaos.com/document.php?source=php_and_unicode + * @see unicode_to_utf8() + */ + protected function utf8_to_unicode( &$str ) + { + $unicode = array(); + $values = array(); + $lookingFor = 1; + + for ($i = 0; $i < strlen( $str ); $i++ ) + { + $thisValue = ord( $str[ $i ] ); + if ( $thisValue < 128 ) + $unicode[] = $thisValue; + else + { + if ( count( $values ) == 0 ) + $lookingFor = ( $thisValue < 224 ) ? 2 : 3; + $values[] = $thisValue; + if ( count( $values ) == $lookingFor ) + { + $number = ( $lookingFor == 3 ) ? + ( ( $values[0] % 16 ) * 4096 ) + ( ( $values[1] % 64 ) * 64 ) + ( $values[2] % 64 ): + ( ( $values[0] % 32 ) * 64 ) + ( $values[1] % 64 ); + $unicode[] = $number; + $values = array(); + $lookingFor = 1; + } + } + } + return $unicode; + } + + /** + * This function converts a Unicode array back to its UTF-8 representation + * + * @author Scott Michael Reynen + * @link http://www.randomchaos.com/document.php?source=php_and_unicode + * @see utf8_to_unicode() + */ + protected function unicode_to_utf8( &$str ) + { + $utf8 = ''; + foreach( $str as $unicode ) + { + if ( $unicode < 128 ) + { + $utf8.= chr( $unicode ); + } + elseif ( $unicode < 2048 ) + { + $utf8.= chr( 192 + ( ( $unicode - ( $unicode % 64 ) ) / 64 ) ); + $utf8.= chr( 128 + ( $unicode % 64 ) ); + } + else + { + $utf8.= chr( 224 + ( ( $unicode - ( $unicode % 4096 ) ) / 4096 ) ); + $utf8.= chr( 128 + ( ( ( $unicode % 4096 ) - ( $unicode % 64 ) ) / 64 ) ); + $utf8.= chr( 128 + ( $unicode % 64 ) ); + } + } + return $utf8; + } + + /** + * UTF-8 to UTF-16BE conversion. + * + * Maybe really UCS-2 without mb_string due to utf8_to_unicode limits + */ + protected function utf8_to_utf16be(&$str, $bom = false) + { + $out = $bom ? "\xFE\xFF" : ''; + if(function_exists('mb_convert_encoding')) + return $out.mb_convert_encoding($str,'UTF-16BE','UTF-8'); + + $uni = $this->utf8_to_unicode($str); + foreach($uni as $cp) + $out .= pack('n',$cp); + return $out; + } + + /** + * UTF-8 to UTF-16BE conversion. + * + * Maybe really UCS-2 without mb_string due to utf8_to_unicode limits + */ + protected function utf16be_to_utf8(&$str) + { + $uni = unpack('n*',$str); + return unicode_to_utf8($uni); + } + +} + +?> \ No newline at end of file diff --git a/framework/Web/Javascripts/TJavascriptSerializer.php b/framework/Web/Javascripts/TJavascriptSerializer.php new file mode 100644 index 00000000..65567762 --- /dev/null +++ b/framework/Web/Javascripts/TJavascriptSerializer.php @@ -0,0 +1,141 @@ + + * $options['onLoading'] = "doit"; + * $options['onComplete'] = "more"; + * $js = new TJavascriptSerializer($options); + * echo $js->toMap(); + * //expects the following javascript code + * // {'onLoading':'doit','onComplete':'more'} + * + * + * For higher complexity data structures use TJSON to serialize and unserialize. + * + * Namespace: System.Web.UI + * + * @author Wei Zhuo + * @version $Revision: 1.3 $ $Date: 2005/11/10 23:43:26 $ + * @package System.Web.UI + */ +class TJavascriptSerializer +{ + protected $data; + + /** + * Serialize php data type into equivalent javascript type. + * @param mixed data to seralize + */ + public function __construct($data) + { + $this->data = $data; + } + + /** + * Converts data to javascript data string + * @return string javascript equivalent + */ + public function toJavascript($strict=false,$toMap=true) + { + $type = 'to_'.gettype($this->data); + return $this->$type($strict,$toMap); + } + + /** + * Coverts PHP arrays (only the array values) into javascript array. + * @param boolean if true empty string and empty array will be converted + * @return string javascript array as string. + */ + public function toList($strict=false) + { + return $this->to_array($strict); + } + + /** + * Coverts PHP arrays (both key and value) into javascript objects. + * @param boolean if true empty string and empty array will be converted + * @return string javascript object as string. + */ + public function toMap($strict=false) + { + return $this->to_array($strict, true); + } + + protected function to_array($strict=false,$toMap=false) + { + $results = array(); + foreach($this->data as $k => $v) + { + if($strict || (!$strict && $v !== '' && $v !== array())) + { + $serializer = new TJavascriptSerializer($v); + $result = $serializer->toJavascript($strict,$toMap); + $results[] = $toMap ? "'{$k}':$result" : $result; + } + } + $brackets = $toMap ? array('{','}') : array('[',']'); + return $brackets[0].implode(',', $results).$brackets[1]; + } + + protected function to_object($strict=false,$toMap=false) + { + if($this->data instanceof TComponent) + return $this->to_component($strict=false,$toMap=false); + + $serializer = new TJavascriptSerializer(get_object_vars($this->data)); + return $serializer->toMap($strict,$toMap); + } + + protected function to_component($strict=false,$toMap=false) + { + throw new TException("component object too complex to serialize"); + } + + protected function to_boolean() + { + return $this->data ? 'true' : 'false'; + } + + protected function to_integer() + { + return "{$this->data}"; + } + + protected function to_double() + { + if($this->data === -INF) + return 'Number.NEGATIVE_INFINITY'; + if($this->data === INF) + return 'Number.POSITIVE_INFINITY'; + return "{$this->data}"; + } + + /** + * Escapes string to javascript strings. If data to convert is string + * and is bracketed with {} or [], it is assumed that the data + * is already a javascript object or array and no further coversion is done. + */ + protected function to_string() + { + //ignore strings surrounded with {} or [], assume they are list or map + if(strlen($this->data)>1) + { + $first = $this->data[0]; $last = $this->data[strlen($this->data)-1]; + if($first == '[' && $last == ']' || + ($first == '{' && $last == '}')) + return $this->data; + } + return "'".preg_replace("/\r\n/", '\n', addslashes($this->data))."'"; + } + + protected function to_null() + { + return 'null'; + } +} + +?> \ No newline at end of file diff --git a/framework/Web/Javascripts/build.bat b/framework/Web/Javascripts/build.bat deleted file mode 100644 index 30561e68..00000000 --- a/framework/Web/Javascripts/build.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -php ../../../tools/jsbuilder/build.php %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/framework/Web/Javascripts/extended/base.js b/framework/Web/Javascripts/extended/base.js index d3d8fb63..8975e1cc 100644 --- a/framework/Web/Javascripts/extended/base.js +++ b/framework/Web/Javascripts/extended/base.js @@ -29,7 +29,7 @@ function $(n,d) { Function.prototype.bindEvent = function() { var __method = this, args = $A(arguments), object = args.shift(); return function(event) { - return __method.call(object, [event || window.event].concat(args)); + return __method.apply(object, [event || window.event].concat(args)); } } diff --git a/framework/Web/Javascripts/extended/event.js b/framework/Web/Javascripts/extended/event.js index dd72d60e..a7514cda 100644 --- a/framework/Web/Javascripts/extended/event.js +++ b/framework/Web/Javascripts/extended/event.js @@ -16,7 +16,7 @@ Object.extend(Event, { if (name == 'keypress' && ((navigator.appVersion.indexOf('AppleWebKit') > 0) - || (element && element.attachEvent))) + || element.attachEvent)) name = 'keydown'; this._observeAndCache(element, name, observer, useCapture); @@ -26,20 +26,20 @@ Object.extend(Event, { return e.keyCode != null ? e.keyCode : e.charCode }, - fireEvent : function(el,type) + fireEvent : function(element,type) { if(document.createEvent) { - var evt = document.createEvent('HTMLEvents'); - evt.initEvent(type, true, true); - el.dispatchEvent(evt); + var event = document.createEvent('HTMLEvents'); + event.initEvent(type, true, true); + element.dispatchEvent(event); } - else if(el.fireEvent) + else if(element.fireEvent) { - el.fireEvent('on'+type); - el[type](); + element.fireEvent('on'+type); + element[type](); } else - el[type](); + element[type](); } }); \ No newline at end of file diff --git a/framework/Web/Javascripts/js/prado.js b/framework/Web/Javascripts/js/prado.js index 6df4abd0..53ff4aba 100644 --- a/framework/Web/Javascripts/js/prado.js +++ b/framework/Web/Javascripts/js/prado.js @@ -193,7 +193,7 @@ return x; Function.prototype.bindEvent=function(){ var _6=this,args=$A(arguments),object=args.shift(); return function(_7){ -return _6.call(object,[_7||window.event].concat(args)); +return _6.apply(object,[_7||window.event].concat(args)); }; }; @@ -1145,17 +1145,17 @@ _9="keydown"; this._observeAndCache(_8,_9,_10,_11); },keyCode:function(e){ return e.keyCode!=null?e.keyCode:e.charCode; -},fireEvent:function(el,_14){ +},fireEvent:function(_13,_14){ if(document.createEvent){ -var evt=document.createEvent("HTMLEvents"); -evt.initEvent(_14,true,true); -el.dispatchEvent(evt); +var _15=document.createEvent("HTMLEvents"); +_15.initEvent(_14,true,true); +_13.dispatchEvent(_15); }else{ -if(el.fireEvent){ -el.fireEvent("on"+_14); -el[_14](); +if(_13.fireEvent){ +_13.fireEvent("on"+_14); +_13[_14](); }else{ -el[_14](); +_13[_14](); } } }}); @@ -2177,51 +2177,31 @@ return true; } return true; }; -Prado.doPostBack=function(_13,_14,_15,_16,_17,_18,_19,_20){ -if(typeof (_16)=="undefined"){ -var _16=false; -var _17=""; -var _18=null; -var _19=false; -var _20=true; -} -var _21=document.getElementById?document.getElementById(_13):document.forms[_13]; -var _22=true; -if(_16){ -_22=Prado.Validation.IsValid(_21); -} -if(_22){ -if(_18!=null&&(_18.length>0)){ -_21.action=_18; -} -if(_19){ -var _23=_21.elements["PRADO_LASTFOCUS"]; -if((typeof (_23)!="undefined")&&(_23!=null)){ -var _24=document.activeElement; -if(typeof (_24)=="undefined"){ -_23.value=_14; -}else{ -if((_24!=null)&&(typeof (_24.id)!="undefined")){ -if(_24.id.length>0){ -_23.value=_24.id; -}else{ -if(typeof (_24.name)!="undefined"){ -_23.value=_24.name; -} -} -} +Prado.PostBack=function(_13,_14){ +var _15=$(_14["FormID"]); +var _16=true; +if(_14["CausesValidation"]&&Prado.Validation){ +if(Prado.Validation.IsValid(_15)==false){ +return; } } +if(_14["PostBackUrl"]&&_14["PostBackUrl"].length>0){ +_15.action=_14["PostBackUrl"]; } -if(!_20){ -_22=false; +if(_14["TrackFocus"]){ +var _17=$("PRADO_LASTFOCUS"); +if(_17){ +var _18=document.activeElement; +if(_18){ +_17.value=_18.id; +}else{ +_17.value=_14["EventTarget"]; } } -if(_22&&(!_21.onsubmit||_21.onsubmit())){ -_21.PRADO_POSTBACK_TARGET.value=_14; -_21.PRADO_POSTBACK_PARAMETER.value=_15; -_21.submit(); } +$("PRADO_POSTBACK_TARGET").value=_14["EventTarget"]; +$("PRADO_POSTBACK_PARAMETER").value=_14["EventParameter"]; +Event.fireEvent(_15,"submit"); }; Prado.Element={setValue:function(_1,_2){ @@ -2351,31 +2331,52 @@ _41=new Element.ClassNames(_41); _41.set(_42); }}}); -Prado.Button=Class.create(); -Object.extend(Prado.Button,{buttonFired:false,fireButton:function(e,_2){ -var _3=!this.buttonFired&&Event.keyCode(e)==Event.KEY_RETURN; -var _4=Event.element(e).targName.toLowerCase()=="textarea"; -if(_3&&!_4){ -var _5=$(_2); -if(_5){ -Prado.Button.buttonFired=true; -Event.fireEvent(_5,"click"); -Event.stop(e); -return false; +Prado.WebUI=Class.create(); +Prado.WebUI.PostBackControl=Class.create(); +Object.extend(Prado.WebUI.PostBackControl.prototype,{initialize:function(_1){ +this.element=$(_1["ID"]); +if(_1["CausesValidation"]&&Prado.Validation){ +Prado.Validation.AddTarget(_1["ID"],_1["ValidationGroup"]); } +if(this.onInit){ +this.onInit(_1); } -return true; }}); -Prado.TextBox=Class.create(); -Object.extend(Prado.TextBox,{handleReturnKey:function(e){ +Prado.WebUI.createPostBackComponent=function(_2){ +var _3=Class.create(); +Object.extend(_3.prototype,Prado.WebUI.PostBackControl.prototype); +if(_2){ +Object.extend(_3.prototype,_2); +} +return _3; +}; +Prado.WebUI.TButton=Prado.WebUI.createPostBackComponent(); +Prado.WebUI.ClickableComponent=Prado.WebUI.createPostBackComponent({onInit:function(_4){ +Event.observe(this.element,"click",Prado.PostBack.bindEvent(this,_4)); +}}); +Prado.WebUI.TLinkButton=Prado.WebUI.ClickableComponent; +Prado.WebUI.TCheckBox=Prado.WebUI.ClickableComponent; +Prado.WebUI.TRadioButton=Prado.WebUI.ClickableComponent; +Prado.WebUI.TBulletedList=Prado.WebUI.ClickableComponent; +Prado.WebUI.TTextBox=Prado.WebUI.createPostBackComponent({onInit:function(_5){ +if(_5["TextMode"]!="MultiLine"){ +Event.observe(this.element,"keypress",this.handleReturnKey.bind(this)); +} +Event.observe(this.element,"change",Prado.PostBack.bindEvent(this,_5)); +},handleReturnKey:function(e){ if(Event.keyCode(e)==Event.KEY_RETURN){ -var _6=Event.element(e); -if(_6){ -Event.fireEvent(_6,"change"); +var _7=Event.element(e); +if(_7){ +Event.fireEvent(_7,"change"); Event.stop(e); return false; } } return true; }}); +Prado.WebUI.TListControl=Prado.WebUI.createPostBackComponent({onInit:function(_8){ +Event.observe(this.element.id,"change",Prado.PostBack.bindEvent(this,_8)); +}}); +Prado.WebUI.TListBox=Prado.WebUI.TListControl; +Prado.WebUI.TDropDownList=Prado.WebUI.TListControl; diff --git a/framework/Web/Javascripts/prado/controls.js b/framework/Web/Javascripts/prado/controls.js index 08b7e94f..34c734f9 100644 --- a/framework/Web/Javascripts/prado/controls.js +++ b/framework/Web/Javascripts/prado/controls.js @@ -1,17 +1,97 @@ +Prado.WebUI = Class.create(); + +//base postback-able controls +Prado.WebUI.PostBackControl = Class.create(); +Object.extend(Prado.WebUI.PostBackControl.prototype, +{ + initialize : function(options) + { + this.element = $(options['ID']); + if(options['CausesValidation'] && Prado.Validation) + Prado.Validation.AddTarget(options['ID'], options['ValidationGroup']); + + //TODO: what do the following options do? + //options['PostBackUrl'] + //options['ClientSubmit'] + + if(this.onInit) + this.onInit(options); + } +}); + +//short cut to create postback components +Prado.WebUI.createPostBackComponent = function(definition) +{ + var component = Class.create(); + Object.extend(component.prototype, Prado.WebUI.PostBackControl.prototype); + if(definition) Object.extend(component.prototype, definition); + return component; +} + +Prado.WebUI.TButton = Prado.WebUI.createPostBackComponent(); + +Prado.WebUI.ClickableComponent = Prado.WebUI.createPostBackComponent( +{ + onInit : function(options) + { + Event.observe(this.element, "click", Prado.PostBack.bindEvent(this,options)); + } +}); + +Prado.WebUI.TLinkButton = Prado.WebUI.ClickableComponent; +Prado.WebUI.TCheckBox = Prado.WebUI.ClickableComponent; +Prado.WebUI.TRadioButton = Prado.WebUI.ClickableComponent; +Prado.WebUI.TBulletedList = Prado.WebUI.ClickableComponent; + +Prado.WebUI.TTextBox = Prado.WebUI.createPostBackComponent( +{ + onInit : function(options) + { + if(options['TextMode'] != 'MultiLine') + Event.observe(this.element, "keypress", this.handleReturnKey.bind(this)); + Event.observe(this.element, "change", Prado.PostBack.bindEvent(this,options)); + }, + + handleReturnKey : function(e) + { + if(Event.keyCode(e) == Event.KEY_RETURN) + { + var target = Event.element(e); + if(target) + { + Event.fireEvent(target, "change"); + Event.stop(e); + return false; + } + } + return true; + } +}); + +Prado.WebUI.TListControl = Prado.WebUI.createPostBackComponent( +{ + onInit : function(options) + { + Event.observe(this.element.id, "change", Prado.PostBack.bindEvent(this,options)); + } +}); + +Prado.WebUI.TListBox = Prado.WebUI.TListControl; +Prado.WebUI.TDropDownList = Prado.WebUI.TListControl; -Prado.Button = Class.create(); +//Prado.Button = Class.create(); /** * Usage: Event.observe("panelID", "keypress", Prado.fireButton.bindEvent($("panelID"), "targetButtonID")); */ -Object.extend(Prado.Button, +/*Object.extend(Prado.Button, { buttonFired : false, fireButton : function(e, target) { var eventFired = !this.buttonFired && Event.keyCode(e) == Event.KEY_RETURN; - var isTextArea = Event.element(e).targName.toLowerCase() == "textarea"; + var isTextArea = Event.element(e).tagName.toLowerCase() == "textarea"; if (eventFired && !isTextArea) { var defaultButton = $(target); @@ -28,11 +108,11 @@ Object.extend(Prado.Button, }); Prado.TextBox = Class.create(); - +*/ /** * Usage: Event.observe("textboxID", "keypress", Prado.fireButton.bindEvent($("textboxID"))); */ -Object.extend(Prado.TextBox, +/*Object.extend(Prado.TextBox, { handleReturnKey : function(e) { @@ -48,4 +128,4 @@ Object.extend(Prado.TextBox, } return true; } -}); +});*/ diff --git a/framework/Web/Javascripts/prado/form.js b/framework/Web/Javascripts/prado/form.js index 810acbd8..03d9ab30 100644 --- a/framework/Web/Javascripts/prado/form.js +++ b/framework/Web/Javascripts/prado/form.js @@ -98,6 +98,38 @@ Prado.Focus.isVisible = function(element) return true; } +Prado.PostBack = function(event,options) +{ + var form = $(options['FormID']); + var canSubmit = true; + if(options['CausesValidation'] && Prado.Validation) + { + if(Prado.Validation.IsValid(form) == false) + return; + } + + if(options['PostBackUrl'] && options['PostBackUrl'].length > 0) + form.action = options['PostBackUrl']; + + if(options['TrackFocus']) + { + var lastFocus = $('PRADO_LASTFOCUS'); + if(lastFocus) + { + var active = document.activeElement; //where did this come from + if(active) + lastFocus.value = active.id; + else + lastFocus.value = options['EventTarget']; + } + } + + $('PRADO_POSTBACK_TARGET').value = options['EventTarget']; + $('PRADO_POSTBACK_PARAMETER').value = options['EventParameter']; + Event.fireEvent(form,"submit"); +} + +/* Prado.doPostBack = function(formID, eventTarget, eventParameter, performValidation, validationGroup, actionUrl, trackFocus, clientSubmit) { @@ -114,11 +146,11 @@ Prado.doPostBack = function(formID, eventTarget, eventParameter, performValidati if (performValidation) { //canSubmit = Prado.Validation.validate(validationGroup); - /* Prado.Validation.ActiveTarget = theForm; + * Prado.Validation.ActiveTarget = theForm; Prado.Validation.CurrentTargetGroup = null; Prado.Validation.IsGroupValidation = false; canSubmit = Prado.Validation.IsValid(theForm); - Logger.debug(canSubmit);*/ + Logger.debug(canSubmit);* canSubmit = Prado.Validation.IsValid(theForm); } if (canSubmit) @@ -165,3 +197,4 @@ Prado.doPostBack = function(formID, eventTarget, eventParameter, performValidati theForm.submit(); } } +*/ \ No newline at end of file diff --git a/framework/Web/UI/TClientScriptManager.php b/framework/Web/UI/TClientScriptManager.php index c5b828dc..72b4ce21 100644 --- a/framework/Web/UI/TClientScriptManager.php +++ b/framework/Web/UI/TClientScriptManager.php @@ -70,127 +70,77 @@ class TPostBackOptions extends TComponent } } +Prado::using('System.Web.Javascripts.*'); + class TClientScriptManager extends TComponent { const SCRIPT_DIR='Web/Javascripts/js'; - const POSTBACK_FUNC='Prado.doPostBack'; + //const POSTBACK_FUNC='Prado.doPostBack'; + private $_page; private $_hiddenFields=array(); private $_beginScripts=array(); private $_endScripts=array(); private $_scriptFiles=array(); - private $_headScriptFiles=array(); - private $_headScripts=array(); + + //private $_headScriptFiles=array(); + //private $_headScripts=array(); + private $_styleSheetFiles=array(); private $_styleSheets=array(); - private $_onSubmitStatements=array(); + + private $_client; + + /*private $_onSubmitStatements=array(); private $_arrayDeclares=array(); private $_expandoAttributes=array(); private $_postBackScriptRegistered=false; private $_focusScriptRegistered=false; private $_scrollScriptRegistered=false; + */ + private $_publishedScriptFiles=array(); + public function __construct(TPage $owner) { $this->_page=$owner; + $this->_client = new TClientScript($this); } - - public function getPostBackEventReference($control,$parameter='',$options=null,$javascriptPrefix=true) + + + public function registerPostBackControl($control,$namespace='Prado.WebUI') { - if(!$options || (!$options->getPerformValidation() && !$options->getTrackFocus() && $options->getClientSubmit() && $options->getActionUrl()=='')) - { - $this->registerPostBackScript(); - if(($form=$this->_page->getForm())!==null) - $formID=$form->getClientID(); - else - throw new TConfigurationException('clientscriptmanager_form_required'); - $postback=self::POSTBACK_FUNC.'(\''.$formID.'\',\''.$control->getUniqueID().'\',\''.THttpUtility::quoteJavaScriptString($parameter).'\')'; - if($options && $options->getAutoPostBack()) - $postback='setTimeout(\''.THttpUtility::quoteJavaScriptString($postback).'\',0)'; - return $javascriptPrefix?'javascript:'.$postback:$postback; - } - $opt=''; - $flag=false; - if($options->getPerformValidation()) - { - $flag=true; - $this->registerValidationScript(); - $opt.=',true,'; - } - else - $opt.=',false,'; - if($options->getValidationGroup()!=='') - { - $flag=true; - $opt.='"'.$options->getValidationGroup().'",'; - } - else - $opt.='\'\','; - if($options->getActionUrl()!=='') - { - $flag=true; - $this->_page->setCrossPagePostBack(true); - $opt.='"'.$options->getActionUrl().'",'; - } - else - $opt.='null,'; - if($options->getTrackFocus()) - { - $flag=true; - $this->registerFocusScript(); - $opt.='true,'; - } - else - $opt.='false,'; - if($options->getClientSubmit()) - { - $flag=true; - $opt.='true'; - } - else - $opt.='false'; - if(!$flag) - return ''; - $this->registerPostBackScript(); - if(($form=$this->_page->getForm())!==null) - $formID=$form->getClientID(); - else - throw new TConfigurationException('clientscriptmanager_form_required'); - $postback=self::POSTBACK_FUNC.'(\''.$formID.'\',\''.$control->getUniqueID().'\',\''.THttpUtility::quoteJavaScriptString($parameter).'\''.$opt.')'; - if($options && $options->getAutoPostBack()) - $postback='setTimeout(\''.THttpUtility::quoteJavaScriptString($postback).'\',0)'; - return $javascriptPrefix?'javascript:'.$postback:$postback; + $options = $this->getPostBackOptions($control); + $type = get_class($control); + $code = "new {$namespace}.{$type}($options);"; + $this->registerEndScript(sprintf('%08X', crc32($code)), $code); + + $this->registerHiddenField(TPage::FIELD_POSTBACK_TARGET,''); + $this->registerHiddenField(TPage::FIELD_POSTBACK_PARAMETER,''); + $this->registerClientScript('prado'); } - /*public function registerPradoScript($script) + protected function getPostBackOptions($control) { - foreach(TPradoClientScript::getScripts($script) as $scriptFile) - { - if(isset($this->_publishedScriptFiles[$scriptFile])) - $url=$this->_publishedScriptFiles[$scriptFile]; - else - { - $base = Prado::getFrameworkPath(); - $clientScripts = self::SCRIPT_DIR; - $file = "{$base}/{$clientScripts}/{$scriptFile}.js"; - $assetManager = $this->_page->getService()->getAssetManager(); - $url= $assetManager->publishFilePath($file); - $this->_publishedScriptFiles[$scriptFile]=$url; - $this->registerScriptFile('prado:'.$scriptFile,$url); - } - } - //return $url; - }*/ + $postback = $control->getPostBackOptions(); + if(!isset($postback['ID'])) + $postback['ID'] = $control->getClientID(); + if(!isset($postback['FormID'])) + $postback['FormID'] = $this->_page->getForm()->getClientID(); + $options = new TJavascriptSerializer($postback); + return $options->toJavascript(); + } + /** - * Register Prado client scripts. + * Register client scripts. */ - public function registerPradoScript($script) + public function registerClientScript($script) { static $scripts = array(); $scripts = array_unique(array_merge($scripts, - TPradoClientScript::getScripts($script))); + TClientScript::getScripts($script))); $this->publishClientScriptAssets($scripts); @@ -205,7 +155,7 @@ class TClientScriptManager extends TComponent /** * Publish each individual javascript file. */ - private function publishClientScriptAssets($scripts) + protected function publishClientScriptAssets($scripts) { foreach($scripts as $lib) { @@ -224,7 +174,7 @@ class TClientScriptManager extends TComponent /** * @return string URL of the compressor asset script. */ - private function publishClientScriptCompressorAsset() + protected function publishClientScriptCompressorAsset() { $scriptFile = 'clientscripts.php'; if(isset($this->_publishedScriptFiles[$scriptFile])) @@ -241,8 +191,7 @@ class TClientScriptManager extends TComponent } } - - protected function registerPostBackScript() +/* protected function registerPostBackScript() { if(!$this->_postBackScriptRegistered) { @@ -279,12 +228,12 @@ class TClientScriptManager extends TComponent $this->registerPradoScript('prado'); $button = $target->getClientID(); $panel = $source->getClientID(); - return "Event.observe('{$panel}', 'keypress', Prado.Button.fireButton.bindEvent($('{$panel}'), '$button'));"; + return "Event.observe('{$panel}', 'keyup', Prado.Button.fireButton.bindEvent($('{$panel}'), '$button'));"; } public function registerValidationScript() { - } + }*/ public function isHiddenFieldRegistered($key) { @@ -311,7 +260,7 @@ class TClientScriptManager extends TComponent return isset($this->_endScripts[$key]); } - public function isHeadScriptFileRegistered($key) +/* public function isHeadScriptFileRegistered($key) { return isset($this->_headScriptFiles[$key]); } @@ -320,6 +269,7 @@ class TClientScriptManager extends TComponent { return isset($this->_headScripts[$key]); } +*/ public function isStyleSheetFileRegistered($key) { @@ -331,7 +281,7 @@ class TClientScriptManager extends TComponent return isset($this->_styleSheets[$key]); } - public function isOnSubmitStatementRegistered($key) +/* public function isOnSubmitStatementRegistered($key) { return isset($this->_onSubmitStatements[$key]); } @@ -340,7 +290,7 @@ class TClientScriptManager extends TComponent { $this->_arrayDeclares[$name][]=$value; } - +*/ public function registerScriptFile($key,$url) { $this->_scriptFiles[$key]=$url; @@ -353,11 +303,11 @@ class TClientScriptManager extends TComponent $this->_hiddenFields[$name]=$value; } - public function registerOnSubmitStatement($key,$script) +/* public function registerOnSubmitStatement($key,$script) { $this->_onSubmitStatements[$key]=$script; } - +*/ public function registerBeginScript($key,$script) { $this->_beginScripts[$key]=$script; @@ -368,7 +318,7 @@ class TClientScriptManager extends TComponent $this->_endScripts[$key]=$script; } - public function registerHeadScriptFile($key,$url) +/* public function registerHeadScriptFile($key,$url) { $this->_headScriptFiles[$key]=$url; } @@ -377,7 +327,7 @@ class TClientScriptManager extends TComponent { $this->_headScripts[$key]=$script; } - +*/ public function registerStyleSheetFile($key,$url) { $this->_styleSheetFiles[$key]=$url; @@ -388,7 +338,7 @@ class TClientScriptManager extends TComponent $this->_styleSheets[$key]=$css; } - public function registerExpandoAttribute($controlID,$name,$value) +/* public function registerExpandoAttribute($controlID,$name,$value) { $this->_expandoAttributes[$controlID][$name]=$value; } @@ -404,7 +354,7 @@ class TClientScriptManager extends TComponent $writer->write($str); } } - +*/ public function renderScriptFiles($writer) { $str=''; @@ -413,11 +363,11 @@ class TClientScriptManager extends TComponent $writer->write($str); } - public function renderOnSubmitStatements($writer) +/* public function renderOnSubmitStatements($writer) { // ??? } - +*/ public function renderBeginScripts($writer) { if(count($this->_beginScripts)) @@ -448,7 +398,7 @@ class TClientScriptManager extends TComponent $writer->write("
\n".$str."
\n"); } - public function renderExpandoAttributes($writer) +/* public function renderExpandoAttributes($writer) { if(count($this->_expandoAttributes)) { @@ -468,8 +418,9 @@ class TClientScriptManager extends TComponent $writer->write($str); } } +*/ - public function renderHeadScriptFiles($writer) +/* public function renderHeadScriptFiles($writer) { $str=''; foreach($this->_headScriptFiles as $url) @@ -482,6 +433,7 @@ class TClientScriptManager extends TComponent if(count($this->_headScripts)) $writer->write("\n"); } +*/ public function renderStyleSheetFiles($writer) { @@ -504,12 +456,12 @@ class TClientScriptManager extends TComponent return count($this->_hiddenFields)>0; } - public function getHasSubmitStatements() +/* public function getHasSubmitStatements() { return count($this->_onSubmitStatements)>0; } - - public function registerClientEvent($control, $event, $code) +*/ +/* public function registerClientEvent($control, $event, $code) { if(empty($code)) return; $this->registerPradoScript("prado"); @@ -517,7 +469,7 @@ class TClientScriptManager extends TComponent $key = "prado:{$control->ClientID}:{$event}"; $this->registerEndScript($key, $script); } - +*/ /* @@ -532,181 +484,4 @@ class TClientScriptManager extends TComponent */ } -/** - * TJavascript class file. Javascript utilties, converts basic PHP types into - * appropriate javascript types. - * - * Example: - * - * $options['onLoading'] = "doit"; - * $options['onComplete'] = "more"; - * $js = TJavascript::toList($options); - * //expects the following javascript code - * // {'onLoading':'doit','onComplete':'more'} - * - * - * Namespace: System.Web.UI - * - * @author Wei Zhuo - * @version $Revision: 1.3 $ $Date: 2005/11/10 23:43:26 $ - * @package System.Web.UI - */ -class TJavascript -{ - /** - * Coverts PHP arrays (only the array values) into javascript array. - * @param array the array data to convert - * @param string append additional javascript array data - * @param boolean if true empty string and empty array will be converted - * @return string javascript array as string. - */ - public static function toArray($array,$append=null,$strict=false) - { - $results = array(); - $converter = new TJavascript(); - foreach($array as $v) - { - if($strict || (!$strict && $v !== '' && $v !== array())) - { - $type = 'to_'.gettype($v); - if($type == 'to_array') - $results[] = $converter->toArray($v, $append, $strict); - else - $results[] = $converter->{$type}($v); - } - } - $extra = ''; - if(strlen($append) > 0) - $extra .= count($results) > 0 ? ','.$append : $append; - return '['.implode(',', $results).$extra.']'; - } - - /** - * Coverts PHP arrays (both key and value) into javascript objects. - * @param array the array data to convert - * @param string append additional javascript object data - * @param boolean if true empty string and empty array will be converted - * @return string javascript object as string. - */ - public static function toList($array,$append=null, $strict=false) - { - $results = array(); - $converter = new TJavascript(); - foreach($array as $k => $v) - { - if($strict || (!$strict && $v !== '' && $v !== array())) - { - $type = 'to_'.gettype($v); - if($type == 'to_array') - $results[] = "'{$k}':".$converter->toList($v, $append, $strict); - else - $results[] = "'{$k}':".$converter->{$type}($v); - } - } - $extra = ''; - if(strlen($append) > 0) - $extra .= count($results) > 0 ? ','.$append : $append; - - return '{'.implode(',', $results).$extra.'}'; - } - - public function to_boolean($v) - { - return $v ? 'true' : 'false'; - } - - public function to_integer($v) - { - return "{$v}"; - } - - public function to_double($v) - { - return "{$v}"; - } - - /** - * If string begins with [ and ends ], or begins with { and ends } - * it is assumed to be javascript arrays or objects and no further - * conversion is applied. - */ - public function to_string($v) - { - if(strlen($v)>1) - { - $first = $v{0}; $last = $v{strlen($v)-1}; - if($first == '[' && $last == ']' || - ($first == '{' && $last == '}')) - return $v; - } - return "'".addslashes($v)."'"; - } - - public function to_array($v) - { - return TJavascript::toArray($v); - } - - public function to_null($v) - { - return 'null'; - } -} - -/** - * PradoClientScript class. - * - * Resolves Prado client script dependencies. e.g. TPradoClientScript::getScripts("dom"); - * - * - base basic javascript utilities, e.g. $() - * - dom DOM and Form functions, e.g. $F(inputID) to retrive form input values. - * - effects Effects such as fade, shake, move - * - controls Prado client-side components, e.g. Slider, AJAX components - * - validator Prado client-side validators. - * - ajax Prado AJAX library including Prototype's AJAX and JSON. - * - * Dependencies for each library are automatically resolved. - * - * Namespace: System.Web.UI - * - * @author Wei Zhuo - * @version $Revision: 1.1 $ $Date: 2005/11/06 23:02:33 $ - * @package System.Web.UI - */ -class TPradoClientScript -{ - /** - * Client-side javascript library dependencies - * @var array - */ - protected static $dependencies = array( - 'prado' => array('prado'), - 'effects' => array('prado', 'effects'), - 'ajax' => array('prado', 'effects', 'ajax'), - 'validator' => array('prado', 'validator'), - 'logger' => array('prado', 'logger'), - 'datepicker' => array('prado', 'datepicker'), - 'rico' => array('prado', 'effects', 'ajax', 'rico') - ); - - /** - * Resolve dependencies for the given library. - * @param array list of libraries to load. - * @return array list of libraries including its dependencies. - */ - public static function getScripts($scripts) - { - $files = array(); - if(!is_array($scripts)) $scripts = array($scripts); - foreach($scripts as $script) - { - if(isset(self::$dependencies[$script])) - $files = array_merge($files, self::$dependencies[$script]); - $files[] = $script; - } - $files = array_unique($files); - return $files; - } -} - ?> \ No newline at end of file diff --git a/framework/Web/UI/TControl.php b/framework/Web/UI/TControl.php index 26aa5dc4..f9c07a8a 100644 --- a/framework/Web/UI/TControl.php +++ b/framework/Web/UI/TControl.php @@ -1549,6 +1549,13 @@ interface IPostBackEventHandler * @param string the parameter associated with the postback event */ public function raisePostBackEvent($param); + + /** + * Return an array of postback options. + * The array of options are serialized to passed to corresponding javascript component code. + * @return array options for javascript postback control + */ + public function getPostBackOptions(); } diff --git a/framework/Web/UI/TPage.php b/framework/Web/UI/TPage.php index 9808e143..ba0d8003 100644 --- a/framework/Web/UI/TPage.php +++ b/framework/Web/UI/TPage.php @@ -737,8 +737,8 @@ class TPage extends TTemplateControl $cs->registerScrollScript($x,$y); } $cs->renderHiddenFields($writer); - $cs->renderArrayDeclarations($writer); - $cs->renderExpandoAttributes($writer); + //$cs->renderArrayDeclarations($writer); + //$cs->renderExpandoAttributes($writer); $cs->renderScriptFiles($writer); $cs->renderEndScripts($writer); } diff --git a/framework/Web/UI/WebControls/TBaseValidator.php b/framework/Web/UI/WebControls/TBaseValidator.php index e3fc8b2f..9c4dd1be 100644 --- a/framework/Web/UI/WebControls/TBaseValidator.php +++ b/framework/Web/UI/WebControls/TBaseValidator.php @@ -159,7 +159,7 @@ abstract class TBaseValidator extends TLabel implements IValidator $scriptKey = "TBaseValidator"; if($this->getEnableClientScript() && !$scripts->isEndScriptRegistered($scriptKey)) { - $scripts->registerPradoScript('validator'); + $scripts->registerClientScript('validator'); $formID=$this->getPage()->getForm()->getClientID(); $js = "Prado.Validation.AddForm('$formID');"; $scripts->registerEndScript($scriptKey, $js); @@ -179,7 +179,8 @@ abstract class TBaseValidator extends TLabel implements IValidator $class = get_class($this); $scriptKey = "prado:".$this->getClientID(); $scripts = $this->getPage()->getClientScript(); - $options = TJavascript::toList($this->getClientScriptOptions()); + $serializer = new TJavascriptSerializer($this->getClientScriptOptions()); + $options = $serializer->toJavascript(); $js = "new Prado.Validation(Prado.Validation.{$class}, {$options});"; $scripts->registerEndScript($scriptKey, $js); } diff --git a/framework/Web/UI/WebControls/TBulletedList.php b/framework/Web/UI/WebControls/TBulletedList.php index 8256237d..63183233 100644 --- a/framework/Web/UI/WebControls/TBulletedList.php +++ b/framework/Web/UI/WebControls/TBulletedList.php @@ -48,6 +48,8 @@ class TBulletedList extends TListControl implements IPostBackEventHandler */ private $_postBackOptions; + private $_currentRenderItemIndex; + /** * Raises the postback event. * This method is required by {@link IPostBackEventHandler} interface. @@ -274,34 +276,12 @@ class TBulletedList extends TListControl implements IPostBackEventHandler switch($this->getDisplayMode()) { case 'Text': - if($item->getEnabled()) - $writer->write(THttpUtility::htmlEncode($item->getText())); - else - { - $writer->addAttribute('disabled','disabled'); - $writer->renderBeginTag('span'); - $writer->write(THttpUtility::htmlEncode($item->getText())); - $writer->renderEndTag(); - } - return; + return $this->renderTextItem($writer, $item, $index); case 'HyperLink': - if(!$this->_isEnabled || !$item->getEnabled()) - $writer->addAttribute('disabled','disabled'); - else - { - $writer->addAttribute('href',$item->getValue()); - if(($target=$this->getTarget())!=='') - $writer->addAttribute('target',$target); - } + $this->renderHyperLinkItem($writer, $item, $index); break; case 'LinkButton': - if(!$this->_isEnabled || !$item->getEnabled()) - $writer->addAttribute('disabled','disabled'); - else - { - $postback=$this->getPage()->getClientScript()->getPostBackEventReference($this,"$index",$this->_postBackOptions); - $writer->addAttribute('href',$postback); - } + $this->renderLinkButtonItem($writer, $item, $index); } if(($accesskey=$this->getAccessKey())!=='') $writer->addAttribute('accesskey',$accesskey); @@ -310,22 +290,62 @@ class TBulletedList extends TListControl implements IPostBackEventHandler $writer->renderEndTag(); } + protected function renderTextItem($writer, $item, $index) + { + if($item->getEnabled()) + $writer->write(THttpUtility::htmlEncode($item->getText())); + else + { + $writer->addAttribute('disabled','disabled'); + $writer->renderBeginTag('span'); + $writer->write(THttpUtility::htmlEncode($item->getText())); + $writer->renderEndTag(); + } + } + + protected function renderHyperLinkItem($writer, $item, $index) + { + if(!$this->_isEnabled || !$item->getEnabled()) + $writer->addAttribute('disabled','disabled'); + else + { + $writer->addAttribute('href',$item->getValue()); + if(($target=$this->getTarget())!=='') + $writer->addAttribute('target',$target); + } + } + + protected function renderLinkButtonItem($writer, $item, $index) + { + if(!$this->_isEnabled || !$item->getEnabled()) + $writer->addAttribute('disabled','disabled'); + else + { + $this->_currentRenderItemIndex = $index; + $this->getPage()->getClientScript()->registerPostbackControl($this); + $writer->addAttribute('id', $this->getClientID().$index); + $writer->addAttribute('href', "javascript:;//".$this->getClientID().$index); + } + } + /** * @return TPostBackOptions postback options used for linkbuttons. */ - protected function getPostBackOptions() + public function getPostBackOptions() + { + $options['ValidationGroup'] = $this->getValidationGroup(); + $options['CausesValidation'] = $this->getCausesValidation(); + $options['EventTarget'] = $this->getUniqueID(); + $options['EventParameter'] = $this->_currentRenderItemIndex; + $options['ID'] = $this->getClientID().$this->_currentRenderItemIndex; + return $options; + } + + protected function canCauseValidation() { - $option=new TPostBackOptions(); $group = $this->getValidationGroup(); $hasValidators = $this->getPage()->getValidators($group)->getCount()>0; - if($this->getCausesValidation() && $hasValidators) - { - $options->setPerformValidation(true); - $options->setValidationGroup($this->getValidationGroup()); - return $options; - } - else - return null; + return $this->getCausesValidation() && $hasValidators; } /** diff --git a/framework/Web/UI/WebControls/TButton.php b/framework/Web/UI/WebControls/TButton.php index 0b4f3e37..bffb4009 100644 --- a/framework/Web/UI/WebControls/TButton.php +++ b/framework/Web/UI/WebControls/TButton.php @@ -76,16 +76,8 @@ class TButton extends TWebControl implements IPostBackEventHandler $writer->addAttribute('value',$this->getText()); if($this->getEnabled(true)) { - $scripts = $this->getPage()->getClientScript(); - if($scripts->isEndScriptRegistered("TBaseValidator")) - { - $group = $this->getValidationGroup(); - $group = strlen($group) ? ",'".$group."'" : ''; - $clientID=$this->getClientID(); - //$script = "Prado.Validation.AddTarget('{$uniqueID}'{$group});"; - $script = "Prado.Validation.AddTarget('{$clientID}'{$group});"; - $scripts->registerEndScript("{$uniqueID}:target", $script); - } + if($this->canCauseValidation()) + $this->getPage()->getClientScript()->registerPostBackControl($this); } else if($this->getEnabled()) // in this case, parent will not render 'disabled' $writer->addAttribute('disabled','disabled'); @@ -94,26 +86,26 @@ class TButton extends TWebControl implements IPostBackEventHandler parent::addAttributesToRender($writer); } + protected function canCauseValidation() + { + $group = $this->getValidationGroup(); + $hasValidators = $this->getPage()->getValidators($group)->getCount()>0; + return $this->getCausesValidation() && $hasValidators; + } + /** * Returns postback specifications for the button. * This method is used by framework and control developers. - * @return TPostBackOptions parameters about how the button defines its postback behavior. + * @return array parameters about how the button defines its postback behavior. */ - protected function getPostBackOptions() + public function getPostBackOptions() { - $option=new TPostBackOptions(); - $group = $this->getValidationGroup(); - $hasValidators = $this->getPage()->getValidators($group)->getCount()>0; - if($this->getCausesValidation() && $hasValidators) - { - $option->setPerformValidation(true); - $option->setValidationGroup($group); - } - if($this->getPostBackUrl()!=='') - $option->setActionUrl($this->getPostBackUrl()); - $option->setClientSubmit(!$this->getUseSubmitBehavior()); - - return $option; + $options['CausesValidation'] = $this->getCausesValidation(); + $options['ValidationGroup'] = $this->getValidationGroup(); + $options['PostBackUrl'] = $this->getPostBackUrl(); + $options['ClientSubmit'] = !$this->getUseSubmitBehavior(); + + return $options; } /** diff --git a/framework/Web/UI/WebControls/TCheckBox.php b/framework/Web/UI/WebControls/TCheckBox.php index 72d15822..385eca06 100644 --- a/framework/Web/UI/WebControls/TCheckBox.php +++ b/framework/Web/UI/WebControls/TCheckBox.php @@ -349,12 +349,7 @@ class TCheckBox extends TWebControl implements IPostBackDataHandler, IValidatabl $page=$this->getPage(); if($this->getAutoPostBack() && $page->getClientSupportsJavaScript()) - { - $options = $this->getAutoPostBackOptions(); - $scripts = $page->getClientScript(); - $postback = $scripts->getPostBackEventReference($this,'',$options,false); - $scripts->registerClientEvent($this, "click", $postback); - } + $page->getClientScript()->registerPostBackControl($this); if(($accesskey=$this->getAccessKey())!=='') $writer->addAttribute('accesskey',$accesskey); @@ -370,17 +365,12 @@ class TCheckBox extends TWebControl implements IPostBackDataHandler, IValidatabl * Sets the post back options for this textbox. * @return TPostBackOptions */ - protected function getAutoPostBackOptions() + public function getPostBackOptions() { - $option=new TPostBackOptions(); - $group = $this->getValidationGroup(); - $hasValidators = $this->getPage()->getValidators($group)->getCount()>0; - if($this->getCausesValidation() && $hasValidators) - { - $option->setPerformValidation(true); - $option->setValidationGroup($group); - } - $option->setAutoPostBack(true); + $options['ValidationGroup'] = $this->getValidationGroup(); + $options['CausesValidation'] = $this->getCausesValidation(); + $options['EventTarget'] = $this->getUniqueID(); + return $options; } } diff --git a/framework/Web/UI/WebControls/THead.php b/framework/Web/UI/WebControls/THead.php index c3d111de..3cdd19aa 100644 --- a/framework/Web/UI/WebControls/THead.php +++ b/framework/Web/UI/WebControls/THead.php @@ -112,8 +112,8 @@ class THead extends TControl $cs=$page->getClientScript(); $cs->renderStyleSheetFiles($writer); $cs->renderStyleSheets($writer); - $cs->renderHeadScriptFiles($writer); - $cs->renderHeadScripts($writer); + $cs->renderScriptFiles($writer); + //$cs->renderHeadScripts($writer); parent::render($writer); $writer->write("\n"); } diff --git a/framework/Web/UI/WebControls/TJavascriptLogger.php b/framework/Web/UI/WebControls/TJavascriptLogger.php index d5761a90..48c752e4 100644 --- a/framework/Web/UI/WebControls/TJavascriptLogger.php +++ b/framework/Web/UI/WebControls/TJavascriptLogger.php @@ -54,7 +54,7 @@ class TJavascriptLogger extends TWebControl */ protected function renderContents($writer) { - $this->Page->ClientScript->registerPradoScript('logger'); + $this->Page->ClientScript->registerClientScript('logger'); $info = '(more info).'; $usage = 'Press ALT-D (Or CTRL-D on OS X) to toggle the javascript log console'; $writer->write("{$usage} {$info}"); diff --git a/framework/Web/UI/WebControls/TLinkButton.php b/framework/Web/UI/WebControls/TLinkButton.php index 16d670b3..01441d99 100644 --- a/framework/Web/UI/WebControls/TLinkButton.php +++ b/framework/Web/UI/WebControls/TLinkButton.php @@ -88,12 +88,7 @@ class TLinkButton extends TWebControl implements IPostBackEventHandler //create unique no-op url references $nop = "javascript:;//".$this->getClientID(); $writer->addAttribute('href', $url ? $url : $nop); - - $scripts = $this->getPage()->getClientScript(); - $options = $this->getPostBackOptions(); - $postback = $scripts->getPostBackEventReference($this, '', $options, false); - $code = "{$postback}; Event.stop(e);"; - $scripts->registerClientEvent($this, "click", $code); + $this->getPage()->getClientScript()->registerPostBackControl($this); } else if($this->getEnabled()) // in this case, parent will not render 'disabled' $writer->addAttribute('disabled','disabled'); @@ -104,25 +99,14 @@ class TLinkButton extends TWebControl implements IPostBackEventHandler * This method is used by framework and control developers. * @return TPostBackOptions parameters about how the button defines its postback behavior. */ - protected function getPostBackOptions() + public function getPostBackOptions() { - $flag=false; - - $option=new TPostBackOptions(); - $group = $this->getValidationGroup(); - $hasValidators = $this->getPage()->getValidators($group)->getCount()>0; - if($this->getCausesValidation() && $hasValidators) - { - $flag=true; - $options->setPerformValidation(true); - $options->setValidationGroup($this->getValidationGroup()); - } - if($this->getPostBackUrl()!=='') - { - $flag=true; - $options->setActionUrl($this->getPostBackUrl()); - } - return $flag?$options:null; + $options['EventTarget'] = $this->getUniqueID(); + $options['CausesValidation'] = $this->getCausesValidation(); + $options['ValidationGroup'] = $this->getValidationGroup(); + $options['PostBackUrl'] = $this->getPostBackUrl(); + + return $options; } /** diff --git a/framework/Web/UI/WebControls/TListControl.php b/framework/Web/UI/WebControls/TListControl.php index cb740124..537df7c5 100644 --- a/framework/Web/UI/WebControls/TListControl.php +++ b/framework/Web/UI/WebControls/TListControl.php @@ -105,10 +105,11 @@ abstract class TListControl extends TDataBoundControl if($this->getAutoPostBack() && $page->getClientSupportsJavaScript()) { $writer->addAttribute('id',$this->getClientID()); - $options = $this->getAutoPostBackOptions(); + $this->getPage()->getClientScript()->registerPostBackControl($this); + /*$options = $this->getAutoPostBackOptions(); $scripts = $this->getPage()->getClientScript(); $postback = $scripts->getPostBackEventReference($this,'',$options,false); - $scripts->registerClientEvent($this, "change", $postback); + $scripts->registerClientEvent($this, "change", $postback);*/ } if($this->getEnabled(true) && !$this->getEnabled()) $writer->addAttribute('disabled','disabled'); @@ -118,9 +119,9 @@ abstract class TListControl extends TDataBoundControl /** * @return TPostBackOptions postback options for JS postback code */ - protected function getAutoPostBackOptions() + public function getPostBackOptions() { - $option=new TPostBackOptions(); +/* $option=new TPostBackOptions(); $group = $this->getValidationGroup(); $hasValidators = $this->getPage()->getValidators($group)->getCount()>0; if($this->getCausesValidation() && $hasValidators) @@ -128,8 +129,11 @@ abstract class TListControl extends TDataBoundControl $option->setPerformValidation(true); $option->setValidationGroup($group); } - $option->setAutoPostBack(true); - return $option; + $option->setAutoPostBack(true);*/ + $options['CausesValidation'] = $this->getCausesValidation(); + $options['ValidationGroup'] = $this->getValidationGroup(); + $options['EventTarget'] = $this->getUniqueID(); + return $options; } /** diff --git a/framework/Web/UI/WebControls/TPanel.php b/framework/Web/UI/WebControls/TPanel.php index 6661eadb..9eab135e 100644 --- a/framework/Web/UI/WebControls/TPanel.php +++ b/framework/Web/UI/WebControls/TPanel.php @@ -72,11 +72,13 @@ class TPanel extends TWebControl throw new TInvalidDataValueException('panel_defaultbutton_invalid',$butt); else { - $scripts = $this->getPage()->getClientScript(); + //TODO + /*$scripts = $this->getPage()->getClientScript(); $js = $scripts->registerDefaultButtonScript($this,$button); $clientID=$this->getClientID(); $scripts->registerEndScript($clientID.'defaultButton', $js); $writer->addAttribute('id',$clientID); + $writer->addAttribute('onkeypress', "return false;");*/ } } } diff --git a/framework/Web/UI/WebControls/TRadioButton.php b/framework/Web/UI/WebControls/TRadioButton.php index a3d4d0c0..d965b64f 100644 --- a/framework/Web/UI/WebControls/TRadioButton.php +++ b/framework/Web/UI/WebControls/TRadioButton.php @@ -161,12 +161,7 @@ class TRadioButton extends TCheckBox $page=$this->getPage(); if($this->getAutoPostBack() && $page->getClientSupportsJavaScript()) - { - $options = $this->getAutoPostBackOptions(); - $scripts = $page->getClientScript(); - $postback = $scripts->getPostBackEventReference($this,'',$options,false); - $scripts->registerClientEvent($this, "click", $postback); - } + $page->getClientScript()->registerPostBackControl($this); if(($accesskey=$this->getAccessKey())!=='') $writer->addAttribute('accesskey',$accesskey); diff --git a/framework/Web/UI/WebControls/TSafeHtml.php b/framework/Web/UI/WebControls/TSafeHtml.php new file mode 100644 index 00000000..b9f1156c --- /dev/null +++ b/framework/Web/UI/WebControls/TSafeHtml.php @@ -0,0 +1,42 @@ + + * @version $Revision: 1.66 $ $Date: ${DATE} ${TIME} $ + * @package ${package} + */ +class TSafeHtml extends TControl +{ + /** + * Renders body content. + * This method overrides parent implementation by removing + * malicious javascript code from the body content + * @param THtmlWriter writer + */ + protected function renderContents($writer) + { + $textWriter=new TTextWriter; + parent::renderContents(new THtmlWriter($textWriter)); + $writer->write($this->parseSafeHtml($textWriter->flush())); + } + + /** + * Use SafeHTML to remove malicous javascript from the HTML content. + * @param string HTML content + * @return string safer HTML content + */ + protected function parseSafeHtml($text) + { + $renderer = new TSafeHtmlParser(); + return $renderer->parse($content); + } +} + +?> \ No newline at end of file diff --git a/framework/Web/UI/WebControls/TTextBox.php b/framework/Web/UI/WebControls/TTextBox.php index 4eb42313..edf74a75 100644 --- a/framework/Web/UI/WebControls/TTextBox.php +++ b/framework/Web/UI/WebControls/TTextBox.php @@ -135,17 +135,18 @@ class TTextBox extends TWebControl implements IPostBackDataHandler, IValidatable $writer->addAttribute('disabled','disabled'); if($this->getAutoPostBack() && $page->getClientSupportsJavaScript()) { - $writer->addAttribute('id',$this->getClientID()); - $options = $this->getAutoPostBackOptions(); + $writer->addAttribute('id',$this->getClientID()); + $this->getPage()->getClientScript()->registerPostBackControl($this); + /*$options = $this->getAutoPostBackOptions(); $scripts = $this->getPage()->getClientScript(); $postback = $scripts->getPostBackEventReference($this,'',$options,false); $scripts->registerClientEvent($this, "change", $postback); - + * if($this->getTextMode() !== 'MultiLine') { $code = "if(Prado.TextBox.handleReturnKey(e)==false) Event.stop(e);"; $scripts->registerClientEvent($this, "keypress", $code); - } + }*/ } parent::addAttributesToRender($writer); } @@ -154,8 +155,14 @@ class TTextBox extends TWebControl implements IPostBackDataHandler, IValidatable * Sets the post back options for this textbox. * @return TPostBackOptions */ - protected function getAutoPostBackOptions() + public function getPostBackOptions() { + $options['EventTarget'] = $this->getUniqueID(); + $options['CausesValidation'] = $this->getCausesValidation(); + $options['ValidationGroup'] = $this->getValidationGroup(); + $options['TextMode'] = $this->getTextMode(); + return $options; + /* $option=new TPostBackOptions(); $group = $this->getValidationGroup(); $hasValidators = $this->getPage()->getValidators($group)->getCount()>0; @@ -164,7 +171,7 @@ class TTextBox extends TWebControl implements IPostBackDataHandler, IValidatable $option->setPerformValidation(true); $option->setValidationGroup($group); } - $option->setAutoPostBack(true); + $option->setAutoPostBack(true);*/ } /** diff --git a/framework/Web/UI/WebControls/TValidationSummary.php b/framework/Web/UI/WebControls/TValidationSummary.php index 14cf869d..0ac7584a 100644 --- a/framework/Web/UI/WebControls/TValidationSummary.php +++ b/framework/Web/UI/WebControls/TValidationSummary.php @@ -213,6 +213,12 @@ class TValidationSummary extends TWebControl return $validators; } + protected function addAttributesToRender($writer) + { + $writer->addAttribute('id',$this->getClientID()); + parent::addAttributesToRender($writer); + } + /** * Render the javascript for validation summary. * @param array list of options for validation summary. @@ -221,7 +227,8 @@ class TValidationSummary extends TWebControl { if(!$this->getEnabled(true) || !$this->getEnableClientScript()) return; - $options = TJavascript::toList($this->getClientScriptOptions()); + $serializer = new TJavascriptSerializer($this->getClientScriptOptions()); + $options = $serializer->toJavascript(); $script = "new Prado.Validation.Summary({$options});"; $this->getPage()->getClientScript()->registerEndScript($this->getClientID(), $script); } -- cgit v1.2.3