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 +- 9 files changed, 1238 insertions(+), 85 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 (limited to 'framework/Web/Javascripts') 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 -- cgit v1.2.3