Changeset 1852
- Timestamp:
- Feb 23, 2007, 2:18:34 PM (18 years ago)
- Location:
- trunk
- Files:
-
- 15 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/admin/include/functions_plugins.inc.php
r1731 r1852 42 42 ) 43 43 { 44 $plugin = array('name'=>$file, 'version'=>'0', 'uri'=>'', 'description'=>''); 44 $plugin = array( 45 'name'=>$file, 46 'version'=>'0', 47 'uri'=>'', 48 'description'=>'', 49 'author'=>'', 50 ); 45 51 $plg_data = implode( '', file($path.'/main.inc.php') ); 46 52 47 if ( preg_match("|Plugin Name: (.*)| i", $plg_data, $val) )53 if ( preg_match("|Plugin Name: (.*)|", $plg_data, $val) ) 48 54 { 49 55 $plugin['name'] = trim( $val[1] ); 50 56 } 51 if (preg_match("|Version: (.*)| i", $plg_data, $val))57 if (preg_match("|Version: (.*)|", $plg_data, $val)) 52 58 { 53 59 $plugin['version'] = trim($val[1]); 54 60 } 55 if ( preg_match("|Plugin URI: (.*)| i", $plg_data, $val) )61 if ( preg_match("|Plugin URI: (.*)|", $plg_data, $val) ) 56 62 { 57 $plugin['uri'] = $val[1];63 $plugin['uri'] = trim($val[1]); 58 64 } 59 if ( preg_match("|Description: (.*)| i", $plg_data, $val) )65 if ( preg_match("|Description: (.*)|", $plg_data, $val) ) 60 66 { 61 67 $plugin['description'] = trim($val[1]); 62 68 } 69 if ( preg_match("|Author: (.*)|", $plg_data, $val) ) 70 { 71 $plugin['author'] = trim($val[1]); 72 } 73 if ( preg_match("|Author URI: (.*)|", $plg_data, $val) ) 74 { 75 $plugin['author uri'] = trim($val[1]); 76 } 77 // IMPORTANT SECURITY ! 78 $plugin = array_map('htmlspecialchars', $plugin); 63 79 $plugins[$file] = $plugin; 64 80 } -
trunk/admin/plugins.php
r1716 r1852 4 4 // | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net | 5 5 // +-----------------------------------------------------------------------+ 6 // | branch : BSF (Best So Far)7 6 // | file : $Id$ 8 7 // | last update : $Date$ … … 39 38 // | perform requested actions | 40 39 // +-----------------------------------------------------------------------+ 41 if ( isset($_ REQUEST['action']) and isset($_REQUEST['plugin']) )42 { 43 $plugin_id = $_ REQUEST['plugin'];40 if ( isset($_GET['action']) and isset($_GET['plugin']) ) 41 { 42 $plugin_id = $_GET['plugin']; 44 43 $crt_db_plugin = get_db_plugins('', $plugin_id); 45 44 if (!empty($crt_db_plugin)) … … 55 54 $file_to_include = PHPWG_PLUGINS_PATH.$plugin_id.'/maintain.inc.php'; 56 55 57 switch ( $_ REQUEST['action'] )56 switch ( $_GET['action'] ) 58 57 { 59 58 case 'install': … … 90 89 if ( !isset($crt_db_plugin) ) 91 90 { 92 array_push($errors, 'CANNOT '. $_ REQUEST['action'] .' - NOT INSTALLED');91 array_push($errors, 'CANNOT '. $_GET['action'] .' - NOT INSTALLED'); 93 92 } 94 93 if ($crt_db_plugin['state']!='inactive') … … 115 114 if ( !isset($crt_db_plugin) ) 116 115 { 117 die ('CANNOT '. $_ REQUEST['action'] .' - NOT INSTALLED');116 die ('CANNOT '. $_GET['action'] .' - NOT INSTALLED'); 118 117 } 119 118 if ($crt_db_plugin['state']!='active') … … 135 134 if ( !isset($crt_db_plugin) ) 136 135 { 137 die ('CANNOT '. $_ REQUEST['action'] .' - NOT INSTALLED');136 die ('CANNOT '. $_GET['action'] .' - NOT INSTALLED'); 138 137 } 139 138 $query = ' … … 182 181 $display_name='<a href="'.$fs_plugin['uri'].'">'.$display_name.'</a>'; 183 182 } 183 $desc = $fs_plugin['description']; 184 if (!empty($fs_plugin['author'])) 185 { 186 $desc.= ' (<em>'; 187 if (!empty($fs_plugin['author uri'])) 188 { 189 $desc.= '<a href="'.$fs_plugin['author uri'].'">'.$fs_plugin['author'].'</a>'; 190 } 191 else 192 { 193 $desc.= $fs_plugin['author']; 194 } 195 $desc.= '</em>)'; 196 } 184 197 $template->assign_block_vars( 'plugins.plugin', 185 198 array( 186 199 'NAME' => $display_name, 187 200 'VERSION' => $fs_plugin['version'], 188 'DESCRIPTION' => $ fs_plugin['description'],201 'DESCRIPTION' => $desc, 189 202 'CLASS' => ($num++ % 2 == 1) ? 'row2' : 'row1', 190 203 ) … … 219 232 ) 220 233 ); 234 $template->assign_block_vars( 'plugins.plugin.action.confirm', array()); 221 235 break; 222 236 } … … 230 244 ) 231 245 ); 246 $template->assign_block_vars( 'plugins.plugin.action.confirm', array()); 232 247 } 233 248 } -
trunk/include/functions_html.inc.php
r1851 r1852 628 628 629 629 /** 630 * exits the current script with 400 code 631 * @param string msg a message to display 632 * @param string alternate_url redirect to this url 633 */ 634 function bad_request($msg, $alternate_url=null) 635 { 636 set_status_header(400); 637 if ($alternate_url==null) 638 $alternate_url = make_index_url(); 639 redirect_html( $alternate_url, 640 '<div style="text-align:left; margin-left:5em;margin-bottom:5em;"> 641 <h1 style="text-align:left; font-size:36px;">Bad request</h1><br/>' 642 .$msg.'</div>', 643 5 ); 644 } 645 646 /** 630 647 * exits the current script with 404 code when a page cannot be found 631 648 * @param string msg a message to display -
trunk/include/functions_tag.inc.php
r1816 r1852 272 272 return $tags; 273 273 } 274 275 /** 276 * return a list of tags corresponding to any of ids, url_names, names 277 * 278 * @param array ids 279 * @param array url_names 280 * @param array names 281 * @return array 282 */ 283 function find_tags($ids, $url_names=array(), $names=array() ) 284 { 285 $where_clauses = array(); 286 if ( !empty($ids) ) 287 { 288 $where_clauses[] = 'id IN ('.implode(',', $ids).')'; 289 } 290 if ( !empty($url_names) ) 291 { 292 $where_clauses[] = 293 'url_name IN ('. 294 implode( 295 ',', 296 array_map( 297 create_function('$s', 'return "\'".$s."\'";'), 298 $url_names 299 ) 300 ) 301 .')'; 302 } 303 if ( !empty($names) ) 304 { 305 $where_clauses[] = 306 'name IN ('. 307 implode( 308 ',', 309 array_map( 310 create_function('$s', 'return "\'".$s."\'";'), 311 $names 312 ) 313 ) 314 .')'; 315 } 316 if (empty($where_clauses)) 317 { 318 return array(); 319 } 320 321 $query = ' 322 SELECT id, url_name, name 323 FROM '.TAGS_TABLE.' 324 WHERE '. implode( ' 325 OR ', $where_clauses); 326 327 $result = pwg_query($query); 328 $tags = array(); 329 while ($row = mysql_fetch_assoc($result)) 330 { 331 array_push($tags, $row); 332 } 333 return $tags; 334 } 274 335 ?> -
trunk/include/section_init.inc.php
r1820 r1852 5 5 // | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net | 6 6 // +-----------------------------------------------------------------------+ 7 // | branch : BSF (Best So Far)8 7 // | file : $Id$ 9 8 // | last update : $Date$ … … 120 119 else 121 120 { 122 die('Fatal:picture identifier is missing');121 bad_request('picture identifier is missing'); 123 122 } 124 123 } … … 160 159 else 161 160 { 162 array_push($requested_tag_url_names, "'".$tokens[$i]."'");161 array_push($requested_tag_url_names, $tokens[$i]); 163 162 } 164 163 $i++; … … 168 167 if ( empty($requested_tag_ids) && empty($requested_tag_url_names) ) 169 168 { 170 die('Fatal: at least one tag required'); 171 } 172 // tag infos 173 $query = ' 174 SELECT name, url_name, id 175 FROM '.TAGS_TABLE.' 176 WHERE '; 177 if ( !empty($requested_tag_ids) ) 178 { 179 $query.= 'id IN ('.implode(',', $requested_tag_ids ).')'; 180 } 181 if ( !empty($requested_tag_url_names) ) 182 { 183 if ( !empty($requested_tag_ids) ) 184 { 185 $query.= ' OR '; 186 } 187 $query.= 'url_name IN ('.implode(',', $requested_tag_url_names ).')'; 188 } 189 $result = pwg_query($query); 190 $tag_infos = array(); 191 while ($row = mysql_fetch_assoc($result)) 192 { 193 $tag_infos[ $row['id'] ] = $row; 194 array_push($page['tags'], $row );//we loose given tag order; is it important? 195 } 169 bad_request('at least one tag required'); 170 } 171 172 $page['tags'] = find_tags($requested_tag_ids, $requested_tag_url_names); 196 173 if ( empty($page['tags']) ) 197 174 { … … 229 206 $next_token++; 230 207 231 preg_match('/(\d+)/', $tokens[$next_token], $matches);208 preg_match('/(\d+)/', @$tokens[$next_token], $matches); 232 209 if (!isset($matches[1])) 233 210 { 234 die('Fatal:search identifier is missing');211 bad_request('search identifier is missing'); 235 212 } 236 213 $page['search'] = $matches[1]; … … 255 232 if (!preg_match('/^\d+(,\d+)*$/', $tokens[$next_token])) 256 233 { 257 die('wrong format on list GET parameter');234 bad_request('wrong format on list GET parameter'); 258 235 } 259 236 foreach (explode(',', $tokens[$next_token]) as $image_id) -
trunk/include/ws_core.inc.php
r1781 r1852 465 465 $flags |= WS_PARAM_OPTIONAL; 466 466 } 467 if ( $flags & WS_PARAM_FORCE_ARRAY ) 468 { 469 $flags |= WS_PARAM_ACCEPT_ARRAY; 470 } 467 471 $options['flags'] = $flags; 468 472 $params[$param] = $options; … … 605 609 'name' => $name, 606 610 'optional' => ($options['flags']&WS_PARAM_OPTIONAL)?true:false, 611 'acceptArray' => ($options['flags']&WS_PARAM_ACCEPT_ARRAY)?true:false, 607 612 ); 608 613 if (isset($options['default'])) -
trunk/include/ws_functions.inc.php
r1849 r1852 270 270 function ws_getVersion($params, &$service) 271 271 { 272 // TODO = Version availability is under control of $conf['show_version'] 273 return PHPWG_VERSION; 272 global $conf; 273 if ($conf['show_version']) 274 return PHPWG_VERSION; 275 else 276 return new PwgError(403, 'Forbidden'); 274 277 } 275 278 … … 337 340 338 341 $order_by = ws_std_image_sql_order($params, 'i.'); 339 if (empty($order_by)) 340 {// TODO check for category order by (image_order) 341 $order_by = $conf['order_by']; 342 } 343 else 344 { 345 $order_by = 'ORDER BY '.$order_by; 346 } 342 if ( empty($order_by) 343 and count($params['cat_id'])==1 344 and isset($cats[ $params['cat_id'][0] ]['image_order']) 345 ) 346 { 347 $order_by = $cats[ $params['cat_id'][0] ]['image_order']; 348 } 349 $order_by = empty($order_by) ? $conf['order_by'] : 'ORDER BY '.$order_by; 350 347 351 $query = ' 348 352 SELECT i.*, GROUP_CONCAT(category_id) cat_ids … … 500 504 function ws_images_addComment($params, &$service) 501 505 { 506 if (!$service->isPost()) 507 { 508 return new PwgError(405, "This method requires HTTP POST"); 509 } 502 510 $params['image_id'] = (int)$params['image_id']; 503 511 $query = ' … … 580 588 if ($image_row==null) 581 589 { 582 return new PwgError( 999, "image_id not found");590 return new PwgError(404, "image_id not found"); 583 591 } 584 592 $image_row = array_merge( $image_row, ws_std_get_urls($image_row) ); … … 860 868 if (!$service->isPost()) 861 869 { 862 return new PwgError(40 0, "This method requiresPOST");870 return new PwgError(405, "This method requires HTTP POST"); 863 871 } 864 872 if (try_log_user($params['username'], $params['password'],false)) … … 943 951 @include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php'); 944 952 global $conf; 945 953 946 954 // first build all the tag_ids we are interested in 947 $ tag_ids = array();948 $tags = get_available_tags();955 $params['tag_id'] = array_map( 'intval',$params['tag_id'] ); 956 $tags = find_tags($params['tag_id'], $params['tag_url_name'], $params['tag_name']); 949 957 $tags_by_id = array(); 950 for( $i=0; $i<count($tags); $i++ )951 {952 $tags[$i]['id']=(int)$tags[$i]['id'];953 }954 958 foreach( $tags as $tag ) 955 959 { 960 $tags['id'] = (int)$tag['id']; 956 961 $tags_by_id[ $tag['id'] ] = $tag; 957 if (958 in_array($tag['name'], $params['tag_name'])959 or960 in_array($tag['url_name'], $params['tag_url_name'])961 or962 in_array($tag['id'], $params['tag_id'])963 )964 {965 $tag_ids[] = $tag['id'];966 }967 962 } 968 963 unset($tags); 969 970 $tag_ids = array_unique( $tag_ids ); 964 $tag_ids = array_keys($tags_by_id); 965 971 966 972 967 $image_ids = array(); -
trunk/plugins/add_index/main.inc.php
r1705 r1852 1 <?php 2 /* 1 <?php /* 3 2 Plugin Name: Add Index 4 Version: 1. 1.0.03 Version: 1.0 5 4 Description: Add file index.php file on all sub-directories of local galleries pictures. / Ajoute le fichier index.php sur les sous-répertoires de galeries d'images locales. 6 5 Plugin URI: http://www.phpwebgallery.net 6 Author: PhpWebGallery team 7 Author URI: http://www.phpwebgallery.net 7 8 */ 8 9 // +-----------------------------------------------------------------------+ -
trunk/plugins/admin_advices/main.inc.php
r1841 r1852 1 1 <?php /* 2 Plugin Name: Admin Advices ! 3 Version: 1.0.0 4 Author: PhpWebGallery team 2 Plugin Name: Admin Advices 3 Version: 1.0 5 4 Description: Give you an advice on the administration page. 6 5 Plugin URI: http://www.phpwebgallery.net 6 Author: PhpWebGallery team 7 Author URI: http://www.phpwebgallery.net 7 8 */ 8 9 -
trunk/plugins/admin_multi_view/main.inc.php
r1821 r1852 4 4 Description: Allows administrators to view gallery as guests and/or change the language and/or theme on the fly. Practical to debug changes ... 5 5 Plugin URI: http://www.phpwebgallery.net 6 Author: PhpWebGallery team 7 Author URI: http://www.phpwebgallery.net 6 8 */ 7 9 -
trunk/plugins/event_tracer/main.inc.php
r1731 r1852 1 <?php 2 /* 1 <?php /* 3 2 Plugin Name: Event tracer 4 3 Version: 1.0 5 4 Description: For developers. Shows all calls to trigger_event. 6 5 Plugin URI: http://www.phpwebgallery.net 6 Author: PhpWebGallery team 7 Author URI: http://www.phpwebgallery.net 7 8 */ 8 9 if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!'); -
trunk/plugins/hello_world/main.inc.php
r1590 r1852 1 1 <?php /* 2 Plugin Name: Hello World ! 2 Plugin Name: Hello World 3 Version: 1.0 4 Description: This example plugin changes the page banner for the administration page. 5 Plugin URI: http://www.phpwebgallery.net 3 6 Author: PhpWebGallery team 4 Description: This example plugin changes the page banner for the administration page. 7 Author URI: http://www.phpwebgallery.net 5 8 */ 6 9 -
trunk/template/yoga/admin/plugins.tpl
r1655 r1852 20 20 <td> 21 21 <!-- BEGIN action --> 22 <a href="{plugins.plugin.action.U_ACTION}" {TAG_INPUT_ENABLED}>{plugins.plugin.action.L_ACTION}</a> 22 <a href="{plugins.plugin.action.U_ACTION}" 23 <!-- BEGIN confirm --> 24 onclick="return confirm('Are you sure?');" 25 <!-- END confirm --> 26 {TAG_INPUT_ENABLED}>{plugins.plugin.action.L_ACTION}</a> 23 27 <!-- END action --> 24 28 </td> -
trunk/tools/prototype.js
r1698 r1852 1 /* Prototype JavaScript framework, version 1. 4.02 * (c) 2005 Sam Stephenson <sam@conio.net>1 /* Prototype JavaScript framework, version 1.5.0 2 * (c) 2005-2007 Sam Stephenson 3 3 * 4 4 * Prototype is freely distributable under the terms of an MIT-style license. … … 8 8 9 9 var Prototype = { 10 Version: '1.4.0', 10 Version: '1.5.0', 11 BrowserFeatures: { 12 XPath: !!document.evaluate 13 }, 14 11 15 ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)', 12 13 16 emptyFunction: function() {}, 14 K: function(x) { return x}17 K: function(x) { return x } 15 18 } 16 19 … … 26 29 27 30 Object.extend = function(destination, source) { 28 for ( property in source) {31 for (var property in source) { 29 32 destination[property] = source[property]; 30 33 } … … 32 35 } 33 36 34 Object.inspect = function(object) { 35 try { 36 if (object == undefined) return 'undefined'; 37 if (object == null) return 'null'; 38 return object.inspect ? object.inspect() : object.toString(); 39 } catch (e) { 40 if (e instanceof RangeError) return '...'; 41 throw e; 42 } 43 } 37 Object.extend(Object, { 38 inspect: function(object) { 39 try { 40 if (object === undefined) return 'undefined'; 41 if (object === null) return 'null'; 42 return object.inspect ? object.inspect() : object.toString(); 43 } catch (e) { 44 if (e instanceof RangeError) return '...'; 45 throw e; 46 } 47 }, 48 49 keys: function(object) { 50 var keys = []; 51 for (var property in object) 52 keys.push(property); 53 return keys; 54 }, 55 56 values: function(object) { 57 var values = []; 58 for (var property in object) 59 values.push(object[property]); 60 return values; 61 }, 62 63 clone: function(object) { 64 return Object.extend({}, object); 65 } 66 }); 44 67 45 68 Function.prototype.bind = function() { … … 51 74 52 75 Function.prototype.bindAsEventListener = function(object) { 53 var __method = this ;76 var __method = this, args = $A(arguments), object = args.shift(); 54 77 return function(event) { 55 return __method. call(object, event || window.event);78 return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments))); 56 79 } 57 80 } … … 78 101 var returnValue; 79 102 80 for (var i = 0 ; i < arguments.length; i++) {103 for (var i = 0, length = arguments.length; i < length; i++) { 81 104 var lambda = arguments[i]; 82 105 try { … … 103 126 104 127 registerCallback: function() { 105 setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); 128 this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); 129 }, 130 131 stop: function() { 132 if (!this.timer) return; 133 clearInterval(this.timer); 134 this.timer = null; 106 135 }, 107 136 … … 110 139 try { 111 140 this.currentlyExecuting = true; 112 this.callback( );141 this.callback(this); 113 142 } finally { 114 143 this.currentlyExecuting = false; … … 117 146 } 118 147 } 119 120 /*--------------------------------------------------------------------------*/ 121 122 function $() { 123 var elements = new Array(); 124 125 for (var i = 0; i < arguments.length; i++) { 126 var element = arguments[i]; 127 if (typeof element == 'string') 128 element = document.getElementById(element); 129 130 if (arguments.length == 1) 131 return element; 132 133 elements.push(element); 134 } 135 136 return elements; 137 } 148 String.interpret = function(value){ 149 return value == null ? '' : String(value); 150 } 151 138 152 Object.extend(String.prototype, { 153 gsub: function(pattern, replacement) { 154 var result = '', source = this, match; 155 replacement = arguments.callee.prepareReplacement(replacement); 156 157 while (source.length > 0) { 158 if (match = source.match(pattern)) { 159 result += source.slice(0, match.index); 160 result += String.interpret(replacement(match)); 161 source = source.slice(match.index + match[0].length); 162 } else { 163 result += source, source = ''; 164 } 165 } 166 return result; 167 }, 168 169 sub: function(pattern, replacement, count) { 170 replacement = this.gsub.prepareReplacement(replacement); 171 count = count === undefined ? 1 : count; 172 173 return this.gsub(pattern, function(match) { 174 if (--count < 0) return match[0]; 175 return replacement(match); 176 }); 177 }, 178 179 scan: function(pattern, iterator) { 180 this.gsub(pattern, iterator); 181 return this; 182 }, 183 184 truncate: function(length, truncation) { 185 length = length || 30; 186 truncation = truncation === undefined ? '...' : truncation; 187 return this.length > length ? 188 this.slice(0, length - truncation.length) + truncation : this; 189 }, 190 191 strip: function() { 192 return this.replace(/^\s+/, '').replace(/\s+$/, ''); 193 }, 194 139 195 stripTags: function() { 140 196 return this.replace(/<\/?[^>]+>/gi, ''); … … 154 210 155 211 evalScripts: function() { 156 return this.extractScripts().map( eval);212 return this.extractScripts().map(function(script) { return eval(script) }); 157 213 }, 158 214 … … 167 223 var div = document.createElement('div'); 168 224 div.innerHTML = this.stripTags(); 169 return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; 170 }, 171 172 toQueryParams: function() { 173 var pairs = this.match(/^\??(.*)$/)[1].split('&'); 174 return pairs.inject({}, function(params, pairString) { 175 var pair = pairString.split('='); 176 params[pair[0]] = pair[1]; 177 return params; 225 return div.childNodes[0] ? (div.childNodes.length > 1 ? 226 $A(div.childNodes).inject('',function(memo,node){ return memo+node.nodeValue }) : 227 div.childNodes[0].nodeValue) : ''; 228 }, 229 230 toQueryParams: function(separator) { 231 var match = this.strip().match(/([^?#]*)(#.*)?$/); 232 if (!match) return {}; 233 234 return match[1].split(separator || '&').inject({}, function(hash, pair) { 235 if ((pair = pair.split('='))[0]) { 236 var name = decodeURIComponent(pair[0]); 237 var value = pair[1] ? decodeURIComponent(pair[1]) : undefined; 238 239 if (hash[name] !== undefined) { 240 if (hash[name].constructor != Array) 241 hash[name] = [hash[name]]; 242 if (value) hash[name].push(value); 243 } 244 else hash[name] = value; 245 } 246 return hash; 178 247 }); 179 248 }, … … 183 252 }, 184 253 254 succ: function() { 255 return this.slice(0, this.length - 1) + 256 String.fromCharCode(this.charCodeAt(this.length - 1) + 1); 257 }, 258 185 259 camelize: function() { 186 var oStringList = this.split('-'); 187 if (oStringList.length == 1) return oStringList[0]; 188 189 var camelizedString = this.indexOf('-') == 0 190 ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) 191 : oStringList[0]; 192 193 for (var i = 1, len = oStringList.length; i < len; i++) { 194 var s = oStringList[i]; 195 camelizedString += s.charAt(0).toUpperCase() + s.substring(1); 196 } 197 198 return camelizedString; 199 }, 200 201 inspect: function() { 202 return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'"; 260 var parts = this.split('-'), len = parts.length; 261 if (len == 1) return parts[0]; 262 263 var camelized = this.charAt(0) == '-' 264 ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) 265 : parts[0]; 266 267 for (var i = 1; i < len; i++) 268 camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); 269 270 return camelized; 271 }, 272 273 capitalize: function(){ 274 return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); 275 }, 276 277 underscore: function() { 278 return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); 279 }, 280 281 dasherize: function() { 282 return this.gsub(/_/,'-'); 283 }, 284 285 inspect: function(useDoubleQuotes) { 286 var escapedString = this.replace(/\\/g, '\\\\'); 287 if (useDoubleQuotes) 288 return '"' + escapedString.replace(/"/g, '\\"') + '"'; 289 else 290 return "'" + escapedString.replace(/'/g, '\\\'') + "'"; 203 291 } 204 292 }); 205 293 294 String.prototype.gsub.prepareReplacement = function(replacement) { 295 if (typeof replacement == 'function') return replacement; 296 var template = new Template(replacement); 297 return function(match) { return template.evaluate(match) }; 298 } 299 206 300 String.prototype.parseQuery = String.prototype.toQueryParams; 301 302 var Template = Class.create(); 303 Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; 304 Template.prototype = { 305 initialize: function(template, pattern) { 306 this.template = template.toString(); 307 this.pattern = pattern || Template.Pattern; 308 }, 309 310 evaluate: function(object) { 311 return this.template.gsub(this.pattern, function(match) { 312 var before = match[1]; 313 if (before == '\\') return match[2]; 314 return before + String.interpret(object[match[3]]); 315 }); 316 } 317 } 207 318 208 319 var $break = new Object(); … … 223 334 if (e != $break) throw e; 224 335 } 336 return this; 337 }, 338 339 eachSlice: function(number, iterator) { 340 var index = -number, slices = [], array = this.toArray(); 341 while ((index += number) < array.length) 342 slices.push(array.slice(index, index+number)); 343 return slices.map(iterator); 225 344 }, 226 345 … … 235 354 236 355 any: function(iterator) { 237 var result = true;356 var result = false; 238 357 this.each(function(value, index) { 239 358 if (result = !!(iterator || Prototype.K)(value, index)) … … 246 365 var results = []; 247 366 this.each(function(value, index) { 248 results.push( iterator(value, index));367 results.push((iterator || Prototype.K)(value, index)); 249 368 }); 250 369 return results; 251 370 }, 252 371 253 detect: function 372 detect: function(iterator) { 254 373 var result; 255 374 this.each(function(value, index) { … … 292 411 }, 293 412 413 inGroupsOf: function(number, fillWith) { 414 fillWith = fillWith === undefined ? null : fillWith; 415 return this.eachSlice(number, function(slice) { 416 while(slice.length < number) slice.push(fillWith); 417 return slice; 418 }); 419 }, 420 294 421 inject: function(memo, iterator) { 295 422 this.each(function(value, index) { … … 301 428 invoke: function(method) { 302 429 var args = $A(arguments).slice(1); 303 return this. collect(function(value) {430 return this.map(function(value) { 304 431 return value[method].apply(value, args); 305 432 }); … … 310 437 this.each(function(value, index) { 311 438 value = (iterator || Prototype.K)(value, index); 312 if ( value >= (result || value))439 if (result == undefined || value >= result) 313 440 result = value; 314 441 }); … … 320 447 this.each(function(value, index) { 321 448 value = (iterator || Prototype.K)(value, index); 322 if ( value <= (result || value))449 if (result == undefined || value < result) 323 450 result = value; 324 451 }); … … 353 480 354 481 sortBy: function(iterator) { 355 return this. collect(function(value, index) {482 return this.map(function(value, index) { 356 483 return {value: value, criteria: iterator(value, index)}; 357 484 }).sort(function(left, right) { … … 362 489 363 490 toArray: function() { 364 return this. collect(Prototype.K);491 return this.map(); 365 492 }, 366 493 … … 372 499 var collections = [this].concat(args).map($A); 373 500 return this.map(function(value, index) { 374 iterator(value = collections.pluck(index)); 375 return value; 376 }); 501 return iterator(collections.pluck(index)); 502 }); 503 }, 504 505 size: function() { 506 return this.toArray().length; 377 507 }, 378 508 … … 395 525 } else { 396 526 var results = []; 397 for (var i = 0 ; i < iterable.length; i++)527 for (var i = 0, length = iterable.length; i < length; i++) 398 528 results.push(iterable[i]); 399 529 return results; … … 403 533 Object.extend(Array.prototype, Enumerable); 404 534 405 Array.prototype._reverse = Array.prototype.reverse; 535 if (!Array.prototype._reverse) 536 Array.prototype._reverse = Array.prototype.reverse; 406 537 407 538 Object.extend(Array.prototype, { 408 539 _each: function(iterator) { 409 for (var i = 0 ; i < this.length; i++)540 for (var i = 0, length = this.length; i < length; i++) 410 541 iterator(this[i]); 411 542 }, … … 426 557 compact: function() { 427 558 return this.select(function(value) { 428 return value != undefined || value !=null;559 return value != null; 429 560 }); 430 561 }, … … 432 563 flatten: function() { 433 564 return this.inject([], function(array, value) { 434 return array.concat(value .constructor == Array ?565 return array.concat(value && value.constructor == Array ? 435 566 value.flatten() : [value]); 436 567 }); … … 445 576 446 577 indexOf: function(object) { 447 for (var i = 0 ; i < this.length; i++)578 for (var i = 0, length = this.length; i < length; i++) 448 579 if (this[i] == object) return i; 449 580 return -1; … … 454 585 }, 455 586 456 shift: function() { 457 var result = this[0]; 458 for (var i = 0; i < this.length - 1; i++) 459 this[i] = this[i + 1]; 460 this.length--; 461 return result; 587 reduce: function() { 588 return this.length > 1 ? this : this[0]; 589 }, 590 591 uniq: function() { 592 return this.inject([], function(array, value) { 593 return array.include(value) ? array : array.concat([value]); 594 }); 595 }, 596 597 clone: function() { 598 return [].concat(this); 599 }, 600 601 size: function() { 602 return this.length; 462 603 }, 463 604 … … 466 607 } 467 608 }); 468 var Hash = { 609 610 Array.prototype.toArray = Array.prototype.clone; 611 612 function $w(string){ 613 string = string.strip(); 614 return string ? string.split(/\s+/) : []; 615 } 616 617 if(window.opera){ 618 Array.prototype.concat = function(){ 619 var array = []; 620 for(var i = 0, length = this.length; i < length; i++) array.push(this[i]); 621 for(var i = 0, length = arguments.length; i < length; i++) { 622 if(arguments[i].constructor == Array) { 623 for(var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) 624 array.push(arguments[i][j]); 625 } else { 626 array.push(arguments[i]); 627 } 628 } 629 return array; 630 } 631 } 632 var Hash = function(obj) { 633 Object.extend(this, obj || {}); 634 }; 635 636 Object.extend(Hash, { 637 toQueryString: function(obj) { 638 var parts = []; 639 640 this.prototype._each.call(obj, function(pair) { 641 if (!pair.key) return; 642 643 if (pair.value && pair.value.constructor == Array) { 644 var values = pair.value.compact(); 645 if (values.length < 2) pair.value = values.reduce(); 646 else { 647 key = encodeURIComponent(pair.key); 648 values.each(function(value) { 649 value = value != undefined ? encodeURIComponent(value) : ''; 650 parts.push(key + '=' + encodeURIComponent(value)); 651 }); 652 return; 653 } 654 } 655 if (pair.value == undefined) pair[1] = ''; 656 parts.push(pair.map(encodeURIComponent).join('=')); 657 }); 658 659 return parts.join('&'); 660 } 661 }); 662 663 Object.extend(Hash.prototype, Enumerable); 664 Object.extend(Hash.prototype, { 469 665 _each: function(iterator) { 470 for ( key in this) {666 for (var key in this) { 471 667 var value = this[key]; 472 if ( typeof value == 'function') continue;668 if (value && value == Hash.prototype[key]) continue; 473 669 474 670 var pair = [key, value]; … … 488 684 489 685 merge: function(hash) { 490 return $H(hash).inject( $H(this), function(mergedHash, pair) {686 return $H(hash).inject(this, function(mergedHash, pair) { 491 687 mergedHash[pair.key] = pair.value; 492 688 return mergedHash; … … 494 690 }, 495 691 692 remove: function() { 693 var result; 694 for(var i = 0, length = arguments.length; i < length; i++) { 695 var value = this[arguments[i]]; 696 if (value !== undefined){ 697 if (result === undefined) result = value; 698 else { 699 if (result.constructor != Array) result = [result]; 700 result.push(value) 701 } 702 } 703 delete this[arguments[i]]; 704 } 705 return result; 706 }, 707 496 708 toQueryString: function() { 497 return this.map(function(pair) { 498 return pair.map(encodeURIComponent).join('='); 499 }).join('&'); 709 return Hash.toQueryString(this); 500 710 }, 501 711 … … 505 715 }).join(', ') + '}>'; 506 716 } 507 } 717 }); 508 718 509 719 function $H(object) { 510 var hash = Object.extend({}, object || {}); 511 Object.extend(hash, Enumerable); 512 Object.extend(hash, Hash); 513 return hash; 514 } 720 if (object && object.constructor == Hash) return object; 721 return new Hash(object); 722 }; 515 723 ObjectRange = Class.create(); 516 724 Object.extend(ObjectRange.prototype, Enumerable); … … 524 732 _each: function(iterator) { 525 733 var value = this.start; 526 do{734 while (this.include(value)) { 527 735 iterator(value); 528 736 value = value.succ(); 529 } while (this.include(value));737 } 530 738 }, 531 739 … … 546 754 getTransport: function() { 547 755 return Try.these( 756 function() {return new XMLHttpRequest()}, 548 757 function() {return new ActiveXObject('Msxml2.XMLHTTP')}, 549 function() {return new ActiveXObject('Microsoft.XMLHTTP')}, 550 function() {return new XMLHttpRequest()} 758 function() {return new ActiveXObject('Microsoft.XMLHTTP')} 551 759 ) || false; 552 760 }, … … 562 770 }, 563 771 564 register: function(responder ToAdd) {565 if (!this.include(responder ToAdd))566 this.responders.push(responder ToAdd);567 }, 568 569 unregister: function(responder ToRemove) {570 this.responders = this.responders.without(responder ToRemove);772 register: function(responder) { 773 if (!this.include(responder)) 774 this.responders.push(responder); 775 }, 776 777 unregister: function(responder) { 778 this.responders = this.responders.without(responder); 571 779 }, 572 780 573 781 dispatch: function(callback, request, transport, json) { 574 782 this.each(function(responder) { 575 if ( responder[callback] &&typeof responder[callback] == 'function') {783 if (typeof responder[callback] == 'function') { 576 784 try { 577 785 responder[callback].apply(responder, [request, transport, json]); … … 588 796 Ajax.activeRequestCount++; 589 797 }, 590 591 798 onComplete: function() { 592 799 Ajax.activeRequestCount--; … … 600 807 method: 'post', 601 808 asynchronous: true, 809 contentType: 'application/x-www-form-urlencoded', 810 encoding: 'UTF-8', 602 811 parameters: '' 603 812 } 604 813 Object.extend(this.options, options || {}); 605 }, 606 607 responseIsSuccess: function() { 608 return this.transport.status == undefined 609 || this.transport.status == 0 610 || (this.transport.status >= 200 && this.transport.status < 300); 611 }, 612 613 responseIsFailure: function() { 614 return !this.responseIsSuccess(); 814 815 this.options.method = this.options.method.toLowerCase(); 816 if (typeof this.options.parameters == 'string') 817 this.options.parameters = this.options.parameters.toQueryParams(); 615 818 } 616 819 } … … 621 824 622 825 Ajax.Request.prototype = Object.extend(new Ajax.Base(), { 826 _complete: false, 827 623 828 initialize: function(url, options) { 624 829 this.transport = Ajax.getTransport(); … … 628 833 629 834 request: function(url) { 630 var parameters = this.options.parameters || ''; 631 if (parameters.length > 0) parameters += '&_='; 835 this.url = url; 836 this.method = this.options.method; 837 var params = this.options.parameters; 838 839 if (!['get', 'post'].include(this.method)) { 840 // simulate other verbs over post 841 params['_method'] = this.method; 842 this.method = 'post'; 843 } 844 845 params = Hash.toQueryString(params); 846 if (params && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_=' 847 848 // when GET, append parameters to URL 849 if (this.method == 'get' && params) 850 this.url += (this.url.indexOf('?') > -1 ? '&' : '?') + params; 632 851 633 852 try { 634 this.url = url;635 if (this.options.method == 'get' && parameters.length > 0)636 this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;637 638 853 Ajax.Responders.dispatch('onCreate', this, this.transport); 639 854 640 this.transport.open(this. options.method, this.url,855 this.transport.open(this.method.toUpperCase(), this.url, 641 856 this.options.asynchronous); 642 857 643 if (this.options.asynchronous) { 644 this.transport.onreadystatechange = this.onStateChange.bind(this); 645 setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); 858 if (this.options.asynchronous) 859 setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10); 860 861 this.transport.onreadystatechange = this.onStateChange.bind(this); 862 this.setRequestHeaders(); 863 864 var body = this.method == 'post' ? (this.options.postBody || params) : null; 865 866 this.transport.send(body); 867 868 /* Force Firefox to handle ready state 4 for synchronous requests */ 869 if (!this.options.asynchronous && this.transport.overrideMimeType) 870 this.onStateChange(); 871 872 } 873 catch (e) { 874 this.dispatchException(e); 875 } 876 }, 877 878 onStateChange: function() { 879 var readyState = this.transport.readyState; 880 if (readyState > 1 && !((readyState == 4) && this._complete)) 881 this.respondToReadyState(this.transport.readyState); 882 }, 883 884 setRequestHeaders: function() { 885 var headers = { 886 'X-Requested-With': 'XMLHttpRequest', 887 'X-Prototype-Version': Prototype.Version, 888 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' 889 }; 890 891 if (this.method == 'post') { 892 headers['Content-type'] = this.options.contentType + 893 (this.options.encoding ? '; charset=' + this.options.encoding : ''); 894 895 /* Force "Connection: close" for older Mozilla browsers to work 896 * around a bug where XMLHttpRequest sends an incorrect 897 * Content-length header. See Mozilla Bugzilla #246651. 898 */ 899 if (this.transport.overrideMimeType && 900 (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) 901 headers['Connection'] = 'close'; 902 } 903 904 // user-defined headers 905 if (typeof this.options.requestHeaders == 'object') { 906 var extras = this.options.requestHeaders; 907 908 if (typeof extras.push == 'function') 909 for (var i = 0, length = extras.length; i < length; i += 2) 910 headers[extras[i]] = extras[i+1]; 911 else 912 $H(extras).each(function(pair) { headers[pair.key] = pair.value }); 913 } 914 915 for (var name in headers) 916 this.transport.setRequestHeader(name, headers[name]); 917 }, 918 919 success: function() { 920 return !this.transport.status 921 || (this.transport.status >= 200 && this.transport.status < 300); 922 }, 923 924 respondToReadyState: function(readyState) { 925 var state = Ajax.Request.Events[readyState]; 926 var transport = this.transport, json = this.evalJSON(); 927 928 if (state == 'Complete') { 929 try { 930 this._complete = true; 931 (this.options['on' + this.transport.status] 932 || this.options['on' + (this.success() ? 'Success' : 'Failure')] 933 || Prototype.emptyFunction)(transport, json); 934 } catch (e) { 935 this.dispatchException(e); 646 936 } 647 937 648 this.setRequestHeaders(); 649 650 var body = this.options.postBody ? this.options.postBody : parameters; 651 this.transport.send(this.options.method == 'post' ? body : null); 652 938 if ((this.getHeader('Content-type') || 'text/javascript').strip(). 939 match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i)) 940 this.evalResponse(); 941 } 942 943 try { 944 (this.options['on' + state] || Prototype.emptyFunction)(transport, json); 945 Ajax.Responders.dispatch('on' + state, this, transport, json); 653 946 } catch (e) { 654 947 this.dispatchException(e); 655 948 } 656 }, 657 658 setRequestHeaders: function() { 659 var requestHeaders = 660 ['X-Requested-With', 'XMLHttpRequest', 661 'X-Prototype-Version', Prototype.Version]; 662 663 if (this.options.method == 'post') { 664 requestHeaders.push('Content-type', 665 'application/x-www-form-urlencoded'); 666 667 /* Force "Connection: close" for Mozilla browsers to work around 668 * a bug where XMLHttpReqeuest sends an incorrect Content-length 669 * header. See Mozilla Bugzilla #246651. 670 */ 671 if (this.transport.overrideMimeType) 672 requestHeaders.push('Connection', 'close'); 673 } 674 675 if (this.options.requestHeaders) 676 requestHeaders.push.apply(requestHeaders, this.options.requestHeaders); 677 678 for (var i = 0; i < requestHeaders.length; i += 2) 679 this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]); 680 }, 681 682 onStateChange: function() { 683 var readyState = this.transport.readyState; 684 if (readyState != 1) 685 this.respondToReadyState(this.transport.readyState); 686 }, 687 688 header: function(name) { 949 950 if (state == 'Complete') { 951 // avoid memory leak in MSIE: clean up 952 this.transport.onreadystatechange = Prototype.emptyFunction; 953 } 954 }, 955 956 getHeader: function(name) { 689 957 try { 690 958 return this.transport.getResponseHeader(name); 691 } catch (e) { }959 } catch (e) { return null } 692 960 }, 693 961 694 962 evalJSON: function() { 695 963 try { 696 return eval(this.header('X-JSON')); 697 } catch (e) {} 964 var json = this.getHeader('X-JSON'); 965 return json ? eval('(' + json + ')') : null; 966 } catch (e) { return null } 698 967 }, 699 968 … … 706 975 }, 707 976 708 respondToReadyState: function(readyState) {709 var event = Ajax.Request.Events[readyState];710 var transport = this.transport, json = this.evalJSON();711 712 if (event == 'Complete') {713 try {714 (this.options['on' + this.transport.status]715 || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]716 || Prototype.emptyFunction)(transport, json);717 } catch (e) {718 this.dispatchException(e);719 }720 721 if ((this.header('Content-type') || '').match(/^text\/javascript/i))722 this.evalResponse();723 }724 725 try {726 (this.options['on' + event] || Prototype.emptyFunction)(transport, json);727 Ajax.Responders.dispatch('on' + event, this, transport, json);728 } catch (e) {729 this.dispatchException(e);730 }731 732 /* Avoid memory leak in MSIE: clean up the oncomplete event handler */733 if (event == 'Complete')734 this.transport.onreadystatechange = Prototype.emptyFunction;735 },736 737 977 dispatchException: function(exception) { 738 978 (this.options.onException || Prototype.emptyFunction)(this, exception); … … 745 985 Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { 746 986 initialize: function(container, url, options) { 747 this.containers = { 748 success: container.success ? $(container.success) : $(container), 749 failure: container.failure ? $(container.failure) : 750 (container.success ? null : $(container)) 987 this.container = { 988 success: (container.success || container), 989 failure: (container.failure || (container.success ? null : container)) 751 990 } 752 991 … … 755 994 756 995 var onComplete = this.options.onComplete || Prototype.emptyFunction; 757 this.options.onComplete = (function(transport, object) {996 this.options.onComplete = (function(transport, param) { 758 997 this.updateContent(); 759 onComplete(transport, object);998 onComplete(transport, param); 760 999 }).bind(this); 761 1000 … … 764 1003 765 1004 updateContent: function() { 766 var receiver = this.responseIsSuccess() ? 767 this.containers.success : this.containers.failure; 1005 var receiver = this.container[this.success() ? 'success' : 'failure']; 768 1006 var response = this.transport.responseText; 769 1007 770 if (!this.options.evalScripts) 771 response = response.stripScripts(); 772 773 if (receiver) { 774 if (this.options.insertion) { 1008 if (!this.options.evalScripts) response = response.stripScripts(); 1009 1010 if (receiver = $(receiver)) { 1011 if (this.options.insertion) 775 1012 new this.options.insertion(receiver, response); 776 } else { 777 Element.update(receiver, response); 778 } 779 } 780 781 if (this.responseIsSuccess()) { 1013 else 1014 receiver.update(response); 1015 } 1016 1017 if (this.success()) { 782 1018 if (this.onComplete) 783 1019 setTimeout(this.onComplete.bind(this), 10); … … 808 1044 809 1045 stop: function() { 810 this.updater.o nComplete = undefined;1046 this.updater.options.onComplete = undefined; 811 1047 clearTimeout(this.timer); 812 1048 (this.onComplete || Prototype.emptyFunction).apply(this, arguments); … … 828 1064 } 829 1065 }); 1066 function $(element) { 1067 if (arguments.length > 1) { 1068 for (var i = 0, elements = [], length = arguments.length; i < length; i++) 1069 elements.push($(arguments[i])); 1070 return elements; 1071 } 1072 if (typeof element == 'string') 1073 element = document.getElementById(element); 1074 return Element.extend(element); 1075 } 1076 1077 if (Prototype.BrowserFeatures.XPath) { 1078 document._getElementsByXPath = function(expression, parentElement) { 1079 var results = []; 1080 var query = document.evaluate(expression, $(parentElement) || document, 1081 null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); 1082 for (var i = 0, length = query.snapshotLength; i < length; i++) 1083 results.push(query.snapshotItem(i)); 1084 return results; 1085 }; 1086 } 1087 830 1088 document.getElementsByClassName = function(className, parentElement) { 831 var children = ($(parentElement) || document.body).getElementsByTagName('*'); 832 return $A(children).inject([], function(elements, child) { 833 if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) 834 elements.push(child); 1089 if (Prototype.BrowserFeatures.XPath) { 1090 var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]"; 1091 return document._getElementsByXPath(q, parentElement); 1092 } else { 1093 var children = ($(parentElement) || document.body).getElementsByTagName('*'); 1094 var elements = [], child; 1095 for (var i = 0, length = children.length; i < length; i++) { 1096 child = children[i]; 1097 if (Element.hasClassName(child, className)) 1098 elements.push(Element.extend(child)); 1099 } 835 1100 return elements; 836 } );837 } 1101 } 1102 }; 838 1103 839 1104 /*--------------------------------------------------------------------------*/ 840 1105 841 if (!window.Element) {1106 if (!window.Element) 842 1107 var Element = new Object(); 843 } 844 845 Object.extend(Element, { 1108 1109 Element.extend = function(element) { 1110 if (!element || _nativeExtensions || element.nodeType == 3) return element; 1111 1112 if (!element._extended && element.tagName && element != window) { 1113 var methods = Object.clone(Element.Methods), cache = Element.extend.cache; 1114 1115 if (element.tagName == 'FORM') 1116 Object.extend(methods, Form.Methods); 1117 if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName)) 1118 Object.extend(methods, Form.Element.Methods); 1119 1120 Object.extend(methods, Element.Methods.Simulated); 1121 1122 for (var property in methods) { 1123 var value = methods[property]; 1124 if (typeof value == 'function' && !(property in element)) 1125 element[property] = cache.findOrStore(value); 1126 } 1127 } 1128 1129 element._extended = true; 1130 return element; 1131 }; 1132 1133 Element.extend.cache = { 1134 findOrStore: function(value) { 1135 return this[value] = this[value] || function() { 1136 return value.apply(null, [this].concat($A(arguments))); 1137 } 1138 } 1139 }; 1140 1141 Element.Methods = { 846 1142 visible: function(element) { 847 1143 return $(element).style.display != 'none'; 848 1144 }, 849 1145 850 toggle: function() { 851 for (var i = 0; i < arguments.length; i++) { 852 var element = $(arguments[i]); 853 Element[Element.visible(element) ? 'hide' : 'show'](element); 854 } 855 }, 856 857 hide: function() { 858 for (var i = 0; i < arguments.length; i++) { 859 var element = $(arguments[i]); 860 element.style.display = 'none'; 861 } 862 }, 863 864 show: function() { 865 for (var i = 0; i < arguments.length; i++) { 866 var element = $(arguments[i]); 867 element.style.display = ''; 868 } 1146 toggle: function(element) { 1147 element = $(element); 1148 Element[Element.visible(element) ? 'hide' : 'show'](element); 1149 return element; 1150 }, 1151 1152 hide: function(element) { 1153 $(element).style.display = 'none'; 1154 return element; 1155 }, 1156 1157 show: function(element) { 1158 $(element).style.display = ''; 1159 return element; 869 1160 }, 870 1161 … … 872 1163 element = $(element); 873 1164 element.parentNode.removeChild(element); 1165 return element; 874 1166 }, 875 1167 876 1168 update: function(element, html) { 1169 html = typeof html == 'undefined' ? '' : html.toString(); 877 1170 $(element).innerHTML = html.stripScripts(); 878 1171 setTimeout(function() {html.evalScripts()}, 10); 1172 return element; 1173 }, 1174 1175 replace: function(element, html) { 1176 element = $(element); 1177 html = typeof html == 'undefined' ? '' : html.toString(); 1178 if (element.outerHTML) { 1179 element.outerHTML = html.stripScripts(); 1180 } else { 1181 var range = element.ownerDocument.createRange(); 1182 range.selectNodeContents(element); 1183 element.parentNode.replaceChild( 1184 range.createContextualFragment(html.stripScripts()), element); 1185 } 1186 setTimeout(function() {html.evalScripts()}, 10); 1187 return element; 1188 }, 1189 1190 inspect: function(element) { 1191 element = $(element); 1192 var result = '<' + element.tagName.toLowerCase(); 1193 $H({'id': 'id', 'className': 'class'}).each(function(pair) { 1194 var property = pair.first(), attribute = pair.last(); 1195 var value = (element[property] || '').toString(); 1196 if (value) result += ' ' + attribute + '=' + value.inspect(true); 1197 }); 1198 return result + '>'; 1199 }, 1200 1201 recursivelyCollect: function(element, property) { 1202 element = $(element); 1203 var elements = []; 1204 while (element = element[property]) 1205 if (element.nodeType == 1) 1206 elements.push(Element.extend(element)); 1207 return elements; 1208 }, 1209 1210 ancestors: function(element) { 1211 return $(element).recursivelyCollect('parentNode'); 1212 }, 1213 1214 descendants: function(element) { 1215 return $A($(element).getElementsByTagName('*')); 1216 }, 1217 1218 immediateDescendants: function(element) { 1219 if (!(element = $(element).firstChild)) return []; 1220 while (element && element.nodeType != 1) element = element.nextSibling; 1221 if (element) return [element].concat($(element).nextSiblings()); 1222 return []; 1223 }, 1224 1225 previousSiblings: function(element) { 1226 return $(element).recursivelyCollect('previousSibling'); 1227 }, 1228 1229 nextSiblings: function(element) { 1230 return $(element).recursivelyCollect('nextSibling'); 1231 }, 1232 1233 siblings: function(element) { 1234 element = $(element); 1235 return element.previousSiblings().reverse().concat(element.nextSiblings()); 1236 }, 1237 1238 match: function(element, selector) { 1239 if (typeof selector == 'string') 1240 selector = new Selector(selector); 1241 return selector.match($(element)); 1242 }, 1243 1244 up: function(element, expression, index) { 1245 return Selector.findElement($(element).ancestors(), expression, index); 1246 }, 1247 1248 down: function(element, expression, index) { 1249 return Selector.findElement($(element).descendants(), expression, index); 1250 }, 1251 1252 previous: function(element, expression, index) { 1253 return Selector.findElement($(element).previousSiblings(), expression, index); 1254 }, 1255 1256 next: function(element, expression, index) { 1257 return Selector.findElement($(element).nextSiblings(), expression, index); 1258 }, 1259 1260 getElementsBySelector: function() { 1261 var args = $A(arguments), element = $(args.shift()); 1262 return Selector.findChildElements(element, args); 1263 }, 1264 1265 getElementsByClassName: function(element, className) { 1266 return document.getElementsByClassName(className, element); 1267 }, 1268 1269 readAttribute: function(element, name) { 1270 element = $(element); 1271 if (document.all && !window.opera) { 1272 var t = Element._attributeTranslations; 1273 if (t.values[name]) return t.values[name](element, name); 1274 if (t.names[name]) name = t.names[name]; 1275 var attribute = element.attributes[name]; 1276 if(attribute) return attribute.nodeValue; 1277 } 1278 return element.getAttribute(name); 879 1279 }, 880 1280 881 1281 getHeight: function(element) { 882 element = $(element); 883 return element.offsetHeight; 1282 return $(element).getDimensions().height; 1283 }, 1284 1285 getWidth: function(element) { 1286 return $(element).getDimensions().width; 884 1287 }, 885 1288 … … 890 1293 hasClassName: function(element, className) { 891 1294 if (!(element = $(element))) return; 892 return Element.classNames(element).include(className); 1295 var elementClassName = element.className; 1296 if (elementClassName.length == 0) return false; 1297 if (elementClassName == className || 1298 elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) 1299 return true; 1300 return false; 893 1301 }, 894 1302 895 1303 addClassName: function(element, className) { 896 1304 if (!(element = $(element))) return; 897 return Element.classNames(element).add(className); 1305 Element.classNames(element).add(className); 1306 return element; 898 1307 }, 899 1308 900 1309 removeClassName: function(element, className) { 901 1310 if (!(element = $(element))) return; 902 return Element.classNames(element).remove(className); 1311 Element.classNames(element).remove(className); 1312 return element; 1313 }, 1314 1315 toggleClassName: function(element, className) { 1316 if (!(element = $(element))) return; 1317 Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className); 1318 return element; 1319 }, 1320 1321 observe: function() { 1322 Event.observe.apply(Event, arguments); 1323 return $A(arguments).first(); 1324 }, 1325 1326 stopObserving: function() { 1327 Event.stopObserving.apply(Event, arguments); 1328 return $A(arguments).first(); 903 1329 }, 904 1330 … … 906 1332 cleanWhitespace: function(element) { 907 1333 element = $(element); 908 for (var i = 0; i < element.childNodes.length; i++) { 909 var node = element.childNodes[i]; 1334 var node = element.firstChild; 1335 while (node) { 1336 var nextNode = node.nextSibling; 910 1337 if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) 911 Element.remove(node); 912 } 1338 element.removeChild(node); 1339 node = nextNode; 1340 } 1341 return element; 913 1342 }, 914 1343 … … 917 1346 }, 918 1347 1348 descendantOf: function(element, ancestor) { 1349 element = $(element), ancestor = $(ancestor); 1350 while (element = element.parentNode) 1351 if (element == ancestor) return true; 1352 return false; 1353 }, 1354 919 1355 scrollTo: function(element) { 920 1356 element = $(element); 921 var x = element.x ? element.x : element.offsetLeft,922 y = element.y ? element.y : element.offsetTop;923 window.scrollTo(x, y);1357 var pos = Position.cumulativeOffset(element); 1358 window.scrollTo(pos[0], pos[1]); 1359 return element; 924 1360 }, 925 1361 926 1362 getStyle: function(element, style) { 927 1363 element = $(element); 928 var value = element.style[style.camelize()]; 1364 if (['float','cssFloat'].include(style)) 1365 style = (typeof element.style.styleFloat != 'undefined' ? 'styleFloat' : 'cssFloat'); 1366 style = style.camelize(); 1367 var value = element.style[style]; 929 1368 if (!value) { 930 1369 if (document.defaultView && document.defaultView.getComputedStyle) { 931 1370 var css = document.defaultView.getComputedStyle(element, null); 932 value = css ? css .getPropertyValue(style): null;1371 value = css ? css[style] : null; 933 1372 } else if (element.currentStyle) { 934 value = element.currentStyle[style .camelize()];1373 value = element.currentStyle[style]; 935 1374 } 936 1375 } 1376 1377 if((value == 'auto') && ['width','height'].include(style) && (element.getStyle('display') != 'none')) 1378 value = element['offset'+style.capitalize()] + 'px'; 937 1379 938 1380 if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) 939 1381 if (Element.getStyle(element, 'position') == 'static') value = 'auto'; 940 1382 if(style == 'opacity') { 1383 if(value) return parseFloat(value); 1384 if(value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) 1385 if(value[1]) return parseFloat(value[1]) / 100; 1386 return 1.0; 1387 } 941 1388 return value == 'auto' ? null : value; 942 1389 }, … … 944 1391 setStyle: function(element, style) { 945 1392 element = $(element); 946 for (name in style) 947 element.style[name.camelize()] = style[name]; 1393 for (var name in style) { 1394 var value = style[name]; 1395 if(name == 'opacity') { 1396 if (value == 1) { 1397 value = (/Gecko/.test(navigator.userAgent) && 1398 !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : 1.0; 1399 if(/MSIE/.test(navigator.userAgent) && !window.opera) 1400 element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,''); 1401 } else if(value == '') { 1402 if(/MSIE/.test(navigator.userAgent) && !window.opera) 1403 element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,''); 1404 } else { 1405 if(value < 0.00001) value = 0; 1406 if(/MSIE/.test(navigator.userAgent) && !window.opera) 1407 element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') + 1408 'alpha(opacity='+value*100+')'; 1409 } 1410 } else if(['float','cssFloat'].include(name)) name = (typeof element.style.styleFloat != 'undefined') ? 'styleFloat' : 'cssFloat'; 1411 element.style[name.camelize()] = value; 1412 } 1413 return element; 948 1414 }, 949 1415 950 1416 getDimensions: function(element) { 951 1417 element = $(element); 952 if (Element.getStyle(element, 'display') != 'none') 1418 var display = $(element).getStyle('display'); 1419 if (display != 'none' && display != null) // Safari bug 953 1420 return {width: element.offsetWidth, height: element.offsetHeight}; 954 1421 … … 958 1425 var originalVisibility = els.visibility; 959 1426 var originalPosition = els.position; 1427 var originalDisplay = els.display; 960 1428 els.visibility = 'hidden'; 961 1429 els.position = 'absolute'; 962 els.display = ' ';1430 els.display = 'block'; 963 1431 var originalWidth = element.clientWidth; 964 1432 var originalHeight = element.clientHeight; 965 els.display = 'none';1433 els.display = originalDisplay; 966 1434 els.position = originalPosition; 967 1435 els.visibility = originalVisibility; … … 982 1450 } 983 1451 } 1452 return element; 984 1453 }, 985 1454 … … 994 1463 element.style.right = ''; 995 1464 } 1465 return element; 996 1466 }, 997 1467 998 1468 makeClipping: function(element) { 999 1469 element = $(element); 1000 if (element._overflow) return ;1001 element._overflow = element.style.overflow ;1470 if (element._overflow) return element; 1471 element._overflow = element.style.overflow || 'auto'; 1002 1472 if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') 1003 1473 element.style.overflow = 'hidden'; 1474 return element; 1004 1475 }, 1005 1476 1006 1477 undoClipping: function(element) { 1007 1478 element = $(element); 1008 if (element._overflow) return; 1009 element.style.overflow = element._overflow; 1010 element._overflow = undefined; 1011 } 1479 if (!element._overflow) return element; 1480 element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; 1481 element._overflow = null; 1482 return element; 1483 } 1484 }; 1485 1486 Object.extend(Element.Methods, {childOf: Element.Methods.descendantOf}); 1487 1488 Element._attributeTranslations = {}; 1489 1490 Element._attributeTranslations.names = { 1491 colspan: "colSpan", 1492 rowspan: "rowSpan", 1493 valign: "vAlign", 1494 datetime: "dateTime", 1495 accesskey: "accessKey", 1496 tabindex: "tabIndex", 1497 enctype: "encType", 1498 maxlength: "maxLength", 1499 readonly: "readOnly", 1500 longdesc: "longDesc" 1501 }; 1502 1503 Element._attributeTranslations.values = { 1504 _getAttr: function(element, attribute) { 1505 return element.getAttribute(attribute, 2); 1506 }, 1507 1508 _flag: function(element, attribute) { 1509 return $(element).hasAttribute(attribute) ? attribute : null; 1510 }, 1511 1512 style: function(element) { 1513 return element.style.cssText.toLowerCase(); 1514 }, 1515 1516 title: function(element) { 1517 var node = element.getAttributeNode('title'); 1518 return node.specified ? node.nodeValue : null; 1519 } 1520 }; 1521 1522 Object.extend(Element._attributeTranslations.values, { 1523 href: Element._attributeTranslations.values._getAttr, 1524 src: Element._attributeTranslations.values._getAttr, 1525 disabled: Element._attributeTranslations.values._flag, 1526 checked: Element._attributeTranslations.values._flag, 1527 readonly: Element._attributeTranslations.values._flag, 1528 multiple: Element._attributeTranslations.values._flag 1012 1529 }); 1530 1531 Element.Methods.Simulated = { 1532 hasAttribute: function(element, attribute) { 1533 var t = Element._attributeTranslations; 1534 attribute = t.names[attribute] || attribute; 1535 return $(element).getAttributeNode(attribute).specified; 1536 } 1537 }; 1538 1539 // IE is missing .innerHTML support for TABLE-related elements 1540 if (document.all && !window.opera){ 1541 Element.Methods.update = function(element, html) { 1542 element = $(element); 1543 html = typeof html == 'undefined' ? '' : html.toString(); 1544 var tagName = element.tagName.toUpperCase(); 1545 if (['THEAD','TBODY','TR','TD'].include(tagName)) { 1546 var div = document.createElement('div'); 1547 switch (tagName) { 1548 case 'THEAD': 1549 case 'TBODY': 1550 div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>'; 1551 depth = 2; 1552 break; 1553 case 'TR': 1554 div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>'; 1555 depth = 3; 1556 break; 1557 case 'TD': 1558 div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>'; 1559 depth = 4; 1560 } 1561 $A(element.childNodes).each(function(node){ 1562 element.removeChild(node) 1563 }); 1564 depth.times(function(){ div = div.firstChild }); 1565 1566 $A(div.childNodes).each( 1567 function(node){ element.appendChild(node) }); 1568 } else { 1569 element.innerHTML = html.stripScripts(); 1570 } 1571 setTimeout(function() {html.evalScripts()}, 10); 1572 return element; 1573 } 1574 }; 1575 1576 Object.extend(Element, Element.Methods); 1577 1578 var _nativeExtensions = false; 1579 1580 if(/Konqueror|Safari|KHTML/.test(navigator.userAgent)) 1581 ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) { 1582 var className = 'HTML' + tag + 'Element'; 1583 if(window[className]) return; 1584 var klass = window[className] = {}; 1585 klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__; 1586 }); 1587 1588 Element.addMethods = function(methods) { 1589 Object.extend(Element.Methods, methods || {}); 1590 1591 function copy(methods, destination, onlyIfAbsent) { 1592 onlyIfAbsent = onlyIfAbsent || false; 1593 var cache = Element.extend.cache; 1594 for (var property in methods) { 1595 var value = methods[property]; 1596 if (!onlyIfAbsent || !(property in destination)) 1597 destination[property] = cache.findOrStore(value); 1598 } 1599 } 1600 1601 if (typeof HTMLElement != 'undefined') { 1602 copy(Element.Methods, HTMLElement.prototype); 1603 copy(Element.Methods.Simulated, HTMLElement.prototype, true); 1604 copy(Form.Methods, HTMLFormElement.prototype); 1605 [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) { 1606 copy(Form.Element.Methods, klass.prototype); 1607 }); 1608 _nativeExtensions = true; 1609 } 1610 } 1013 1611 1014 1612 var Toggle = new Object(); … … 1030 1628 this.element.insertAdjacentHTML(this.adjacency, this.content); 1031 1629 } catch (e) { 1032 if (this.element.tagName.toLowerCase() == 'tbody') { 1630 var tagName = this.element.tagName.toUpperCase(); 1631 if (['TBODY', 'TR'].include(tagName)) { 1033 1632 this.insertContent(this.contentFromAnonymousTable()); 1034 1633 } else { … … 1129 1728 add: function(classNameToAdd) { 1130 1729 if (this.include(classNameToAdd)) return; 1131 this.set( this.toArray().concat(classNameToAdd).join(' '));1730 this.set($A(this).concat(classNameToAdd).join(' ')); 1132 1731 }, 1133 1732 1134 1733 remove: function(classNameToRemove) { 1135 1734 if (!this.include(classNameToRemove)) return; 1136 this.set(this.select(function(className) { 1137 return className != classNameToRemove; 1138 }).join(' ')); 1735 this.set($A(this).without(classNameToRemove).join(' ')); 1139 1736 }, 1140 1737 1141 1738 toString: function() { 1142 return this.toArray().join(' ');1143 } 1144 } 1739 return $A(this).join(' '); 1740 } 1741 }; 1145 1742 1146 1743 Object.extend(Element.ClassNames.prototype, Enumerable); 1147 var Field = { 1148 clear: function() { 1149 for (var i = 0; i < arguments.length; i++) 1150 $(arguments[i]).value = ''; 1151 }, 1152 1744 var Selector = Class.create(); 1745 Selector.prototype = { 1746 initialize: function(expression) { 1747 this.params = {classNames: []}; 1748 this.expression = expression.toString().strip(); 1749 this.parseExpression(); 1750 this.compileMatcher(); 1751 }, 1752 1753 parseExpression: function() { 1754 function abort(message) { throw 'Parse error in selector: ' + message; } 1755 1756 if (this.expression == '') abort('empty expression'); 1757 1758 var params = this.params, expr = this.expression, match, modifier, clause, rest; 1759 while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) { 1760 params.attributes = params.attributes || []; 1761 params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''}); 1762 expr = match[1]; 1763 } 1764 1765 if (expr == '*') return this.params.wildcard = true; 1766 1767 while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) { 1768 modifier = match[1], clause = match[2], rest = match[3]; 1769 switch (modifier) { 1770 case '#': params.id = clause; break; 1771 case '.': params.classNames.push(clause); break; 1772 case '': 1773 case undefined: params.tagName = clause.toUpperCase(); break; 1774 default: abort(expr.inspect()); 1775 } 1776 expr = rest; 1777 } 1778 1779 if (expr.length > 0) abort(expr.inspect()); 1780 }, 1781 1782 buildMatchExpression: function() { 1783 var params = this.params, conditions = [], clause; 1784 1785 if (params.wildcard) 1786 conditions.push('true'); 1787 if (clause = params.id) 1788 conditions.push('element.readAttribute("id") == ' + clause.inspect()); 1789 if (clause = params.tagName) 1790 conditions.push('element.tagName.toUpperCase() == ' + clause.inspect()); 1791 if ((clause = params.classNames).length > 0) 1792 for (var i = 0, length = clause.length; i < length; i++) 1793 conditions.push('element.hasClassName(' + clause[i].inspect() + ')'); 1794 if (clause = params.attributes) { 1795 clause.each(function(attribute) { 1796 var value = 'element.readAttribute(' + attribute.name.inspect() + ')'; 1797 var splitValueBy = function(delimiter) { 1798 return value + ' && ' + value + '.split(' + delimiter.inspect() + ')'; 1799 } 1800 1801 switch (attribute.operator) { 1802 case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break; 1803 case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break; 1804 case '|=': conditions.push( 1805 splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect() 1806 ); break; 1807 case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break; 1808 case '': 1809 case undefined: conditions.push('element.hasAttribute(' + attribute.name.inspect() + ')'); break; 1810 default: throw 'Unknown operator ' + attribute.operator + ' in selector'; 1811 } 1812 }); 1813 } 1814 1815 return conditions.join(' && '); 1816 }, 1817 1818 compileMatcher: function() { 1819 this.match = new Function('element', 'if (!element.tagName) return false; \ 1820 element = $(element); \ 1821 return ' + this.buildMatchExpression()); 1822 }, 1823 1824 findElements: function(scope) { 1825 var element; 1826 1827 if (element = $(this.params.id)) 1828 if (this.match(element)) 1829 if (!scope || Element.childOf(element, scope)) 1830 return [element]; 1831 1832 scope = (scope || document).getElementsByTagName(this.params.tagName || '*'); 1833 1834 var results = []; 1835 for (var i = 0, length = scope.length; i < length; i++) 1836 if (this.match(element = scope[i])) 1837 results.push(Element.extend(element)); 1838 1839 return results; 1840 }, 1841 1842 toString: function() { 1843 return this.expression; 1844 } 1845 } 1846 1847 Object.extend(Selector, { 1848 matchElements: function(elements, expression) { 1849 var selector = new Selector(expression); 1850 return elements.select(selector.match.bind(selector)).map(Element.extend); 1851 }, 1852 1853 findElement: function(elements, expression, index) { 1854 if (typeof expression == 'number') index = expression, expression = false; 1855 return Selector.matchElements(elements, expression || '*')[index || 0]; 1856 }, 1857 1858 findChildElements: function(element, expressions) { 1859 return expressions.map(function(expression) { 1860 return expression.match(/[^\s"]+(?:"[^"]*"[^\s"]+)*/g).inject([null], function(results, expr) { 1861 var selector = new Selector(expr); 1862 return results.inject([], function(elements, result) { 1863 return elements.concat(selector.findElements(result || element)); 1864 }); 1865 }); 1866 }).flatten(); 1867 } 1868 }); 1869 1870 function $$() { 1871 return Selector.findChildElements(document, $A(arguments)); 1872 } 1873 var Form = { 1874 reset: function(form) { 1875 $(form).reset(); 1876 return form; 1877 }, 1878 1879 serializeElements: function(elements, getHash) { 1880 var data = elements.inject({}, function(result, element) { 1881 if (!element.disabled && element.name) { 1882 var key = element.name, value = $(element).getValue(); 1883 if (value != undefined) { 1884 if (result[key]) { 1885 if (result[key].constructor != Array) result[key] = [result[key]]; 1886 result[key].push(value); 1887 } 1888 else result[key] = value; 1889 } 1890 } 1891 return result; 1892 }); 1893 1894 return getHash ? data : Hash.toQueryString(data); 1895 } 1896 }; 1897 1898 Form.Methods = { 1899 serialize: function(form, getHash) { 1900 return Form.serializeElements(Form.getElements(form), getHash); 1901 }, 1902 1903 getElements: function(form) { 1904 return $A($(form).getElementsByTagName('*')).inject([], 1905 function(elements, child) { 1906 if (Form.Element.Serializers[child.tagName.toLowerCase()]) 1907 elements.push(Element.extend(child)); 1908 return elements; 1909 } 1910 ); 1911 }, 1912 1913 getInputs: function(form, typeName, name) { 1914 form = $(form); 1915 var inputs = form.getElementsByTagName('input'); 1916 1917 if (!typeName && !name) return $A(inputs).map(Element.extend); 1918 1919 for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { 1920 var input = inputs[i]; 1921 if ((typeName && input.type != typeName) || (name && input.name != name)) 1922 continue; 1923 matchingInputs.push(Element.extend(input)); 1924 } 1925 1926 return matchingInputs; 1927 }, 1928 1929 disable: function(form) { 1930 form = $(form); 1931 form.getElements().each(function(element) { 1932 element.blur(); 1933 element.disabled = 'true'; 1934 }); 1935 return form; 1936 }, 1937 1938 enable: function(form) { 1939 form = $(form); 1940 form.getElements().each(function(element) { 1941 element.disabled = ''; 1942 }); 1943 return form; 1944 }, 1945 1946 findFirstElement: function(form) { 1947 return $(form).getElements().find(function(element) { 1948 return element.type != 'hidden' && !element.disabled && 1949 ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); 1950 }); 1951 }, 1952 1953 focusFirstElement: function(form) { 1954 form = $(form); 1955 form.findFirstElement().activate(); 1956 return form; 1957 } 1958 } 1959 1960 Object.extend(Form, Form.Methods); 1961 1962 /*--------------------------------------------------------------------------*/ 1963 1964 Form.Element = { 1153 1965 focus: function(element) { 1154 1966 $(element).focus(); 1155 }, 1156 1157 present: function() { 1158 for (var i = 0; i < arguments.length; i++) 1159 if ($(arguments[i]).value == '') return false; 1160 return true; 1967 return element; 1161 1968 }, 1162 1969 1163 1970 select: function(element) { 1164 1971 $(element).select(); 1972 return element; 1973 } 1974 } 1975 1976 Form.Element.Methods = { 1977 serialize: function(element) { 1978 element = $(element); 1979 if (!element.disabled && element.name) { 1980 var value = element.getValue(); 1981 if (value != undefined) { 1982 var pair = {}; 1983 pair[element.name] = value; 1984 return Hash.toQueryString(pair); 1985 } 1986 } 1987 return ''; 1988 }, 1989 1990 getValue: function(element) { 1991 element = $(element); 1992 var method = element.tagName.toLowerCase(); 1993 return Form.Element.Serializers[method](element); 1994 }, 1995 1996 clear: function(element) { 1997 $(element).value = ''; 1998 return element; 1999 }, 2000 2001 present: function(element) { 2002 return $(element).value != ''; 1165 2003 }, 1166 2004 … … 1168 2006 element = $(element); 1169 2007 element.focus(); 1170 if (element.select) 2008 if (element.select && ( element.tagName.toLowerCase() != 'input' || 2009 !['button', 'reset', 'submit'].include(element.type) ) ) 1171 2010 element.select(); 1172 } 1173 } 2011 return element; 2012 }, 2013 2014 disable: function(element) { 2015 element = $(element); 2016 element.disabled = true; 2017 return element; 2018 }, 2019 2020 enable: function(element) { 2021 element = $(element); 2022 element.blur(); 2023 element.disabled = false; 2024 return element; 2025 } 2026 } 2027 2028 Object.extend(Form.Element, Form.Element.Methods); 2029 var Field = Form.Element; 2030 var $F = Form.Element.getValue; 1174 2031 1175 2032 /*--------------------------------------------------------------------------*/ 1176 1177 var Form = {1178 serialize: function(form) {1179 var elements = Form.getElements($(form));1180 var queryComponents = new Array();1181 1182 for (var i = 0; i < elements.length; i++) {1183 var queryComponent = Form.Element.serialize(elements[i]);1184 if (queryComponent)1185 queryComponents.push(queryComponent);1186 }1187 1188 return queryComponents.join('&');1189 },1190 1191 getElements: function(form) {1192 form = $(form);1193 var elements = new Array();1194 1195 for (tagName in Form.Element.Serializers) {1196 var tagElements = form.getElementsByTagName(tagName);1197 for (var j = 0; j < tagElements.length; j++)1198 elements.push(tagElements[j]);1199 }1200 return elements;1201 },1202 1203 getInputs: function(form, typeName, name) {1204 form = $(form);1205 var inputs = form.getElementsByTagName('input');1206 1207 if (!typeName && !name)1208 return inputs;1209 1210 var matchingInputs = new Array();1211 for (var i = 0; i < inputs.length; i++) {1212 var input = inputs[i];1213 if ((typeName && input.type != typeName) ||1214 (name && input.name != name))1215 continue;1216 matchingInputs.push(input);1217 }1218 1219 return matchingInputs;1220 },1221 1222 disable: function(form) {1223 var elements = Form.getElements(form);1224 for (var i = 0; i < elements.length; i++) {1225 var element = elements[i];1226 element.blur();1227 element.disabled = 'true';1228 }1229 },1230 1231 enable: function(form) {1232 var elements = Form.getElements(form);1233 for (var i = 0; i < elements.length; i++) {1234 var element = elements[i];1235 element.disabled = '';1236 }1237 },1238 1239 findFirstElement: function(form) {1240 return Form.getElements(form).find(function(element) {1241 return element.type != 'hidden' && !element.disabled &&1242 ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());1243 });1244 },1245 1246 focusFirstElement: function(form) {1247 Field.activate(Form.findFirstElement(form));1248 },1249 1250 reset: function(form) {1251 $(form).reset();1252 }1253 }1254 1255 Form.Element = {1256 serialize: function(element) {1257 element = $(element);1258 var method = element.tagName.toLowerCase();1259 var parameter = Form.Element.Serializers[method](element);1260 1261 if (parameter) {1262 var key = encodeURIComponent(parameter[0]);1263 if (key.length == 0) return;1264 1265 if (parameter[1].constructor != Array)1266 parameter[1] = [parameter[1]];1267 1268 return parameter[1].map(function(value) {1269 return key + '=' + encodeURIComponent(value);1270 }).join('&');1271 }1272 },1273 1274 getValue: function(element) {1275 element = $(element);1276 var method = element.tagName.toLowerCase();1277 var parameter = Form.Element.Serializers[method](element);1278 1279 if (parameter)1280 return parameter[1];1281 }1282 }1283 2033 1284 2034 Form.Element.Serializers = { 1285 2035 input: function(element) { 1286 2036 switch (element.type.toLowerCase()) { 1287 case 'submit':1288 case 'hidden':1289 case 'password':1290 case 'text':1291 return Form.Element.Serializers.textarea(element);1292 2037 case 'checkbox': 1293 2038 case 'radio': 1294 2039 return Form.Element.Serializers.inputSelector(element); 1295 } 1296 return false; 2040 default: 2041 return Form.Element.Serializers.textarea(element); 2042 } 1297 2043 }, 1298 2044 1299 2045 inputSelector: function(element) { 1300 if (element.checked) 1301 return [element.name, element.value]; 2046 return element.checked ? element.value : null; 1302 2047 }, 1303 2048 1304 2049 textarea: function(element) { 1305 return [element.name, element.value];2050 return element.value; 1306 2051 }, 1307 2052 1308 2053 select: function(element) { 1309 return Form.Element.Serializers[element.type == 'select-one' ?2054 return this[element.type == 'select-one' ? 1310 2055 'selectOne' : 'selectMany'](element); 1311 2056 }, 1312 2057 1313 2058 selectOne: function(element) { 1314 var value = '', opt, index = element.selectedIndex; 1315 if (index >= 0) { 1316 opt = element.options[index]; 1317 value = opt.value; 1318 if (!value && !('value' in opt)) 1319 value = opt.text; 1320 } 1321 return [element.name, value]; 2059 var index = element.selectedIndex; 2060 return index >= 0 ? this.optionValue(element.options[index]) : null; 1322 2061 }, 1323 2062 1324 2063 selectMany: function(element) { 1325 var value = new Array(); 1326 for (var i = 0; i < element.length; i++) { 2064 var values, length = element.length; 2065 if (!length) return null; 2066 2067 for (var i = 0, values = []; i < length; i++) { 1327 2068 var opt = element.options[i]; 1328 if (opt.selected) { 1329 var optValue = opt.value; 1330 if (!optValue && !('value' in opt)) 1331 optValue = opt.text; 1332 value.push(optValue); 1333 } 1334 } 1335 return [element.name, value]; 1336 } 1337 } 1338 1339 /*--------------------------------------------------------------------------*/ 1340 1341 var $F = Form.Element.getValue; 2069 if (opt.selected) values.push(this.optionValue(opt)); 2070 } 2071 return values; 2072 }, 2073 2074 optionValue: function(opt) { 2075 // extend element because hasAttribute may not be native 2076 return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; 2077 } 2078 } 1342 2079 1343 2080 /*--------------------------------------------------------------------------*/ … … 1360 2097 onTimerEvent: function() { 1361 2098 var value = this.getValue(); 1362 if (this.lastValue != value) { 2099 var changed = ('string' == typeof this.lastValue && 'string' == typeof value 2100 ? this.lastValue != value : String(this.lastValue) != String(value)); 2101 if (changed) { 1363 2102 this.callback(this.element, value); 1364 2103 this.lastValue = value; … … 1405 2144 1406 2145 registerFormCallbacks: function() { 1407 var elements = Form.getElements(this.element); 1408 for (var i = 0; i < elements.length; i++) 1409 this.registerCallback(elements[i]); 2146 Form.getElements(this.element).each(this.registerCallback.bind(this)); 1410 2147 }, 1411 2148 … … 1417 2154 Event.observe(element, 'click', this.onElementEvent.bind(this)); 1418 2155 break; 1419 case 'password': 1420 case 'text': 1421 case 'textarea': 1422 case 'select-one': 1423 case 'select-multiple': 2156 default: 1424 2157 Event.observe(element, 'change', this.onElementEvent.bind(this)); 1425 2158 break; … … 1456 2189 KEY_DOWN: 40, 1457 2190 KEY_DELETE: 46, 2191 KEY_HOME: 36, 2192 KEY_END: 35, 2193 KEY_PAGEUP: 33, 2194 KEY_PAGEDOWN: 34, 1458 2195 1459 2196 element: function(event) { … … 1511 2248 unloadCache: function() { 1512 2249 if (!Event.observers) return; 1513 for (var i = 0 ; i < Event.observers.length; i++) {2250 for (var i = 0, length = Event.observers.length; i < length; i++) { 1514 2251 Event.stopObserving.apply(this, Event.observers[i]); 1515 2252 Event.observers[i][0] = null; … … 1519 2256 1520 2257 observe: function(element, name, observer, useCapture) { 1521 varelement = $(element);2258 element = $(element); 1522 2259 useCapture = useCapture || false; 1523 2260 … … 1527 2264 name = 'keydown'; 1528 2265 1529 this._observeAndCache(element, name, observer, useCapture);2266 Event._observeAndCache(element, name, observer, useCapture); 1530 2267 }, 1531 2268 1532 2269 stopObserving: function(element, name, observer, useCapture) { 1533 varelement = $(element);2270 element = $(element); 1534 2271 useCapture = useCapture || false; 1535 2272 … … 1542 2279 element.removeEventListener(name, observer, useCapture); 1543 2280 } else if (element.detachEvent) { 1544 element.detachEvent('on' + name, observer); 2281 try { 2282 element.detachEvent('on' + name, observer); 2283 } catch (e) {} 1545 2284 } 1546 2285 } … … 1548 2287 1549 2288 /* prevent memory leaks in IE */ 1550 Event.observe(window, 'unload', Event.unloadCache, false); 2289 if (navigator.appVersion.match(/\bMSIE\b/)) 2290 Event.observe(window, 'unload', Event.unloadCache, false); 1551 2291 var Position = { 1552 2292 // set to true if needed, warning: firefox performance problems … … 1595 2335 element = element.offsetParent; 1596 2336 if (element) { 1597 p = Element.getStyle(element, 'position'); 2337 if(element.tagName=='BODY') break; 2338 var p = Element.getStyle(element, 'position'); 1598 2339 if (p == 'relative' || p == 'absolute') break; 1599 2340 } … … 1651 2392 }, 1652 2393 1653 clone: function(source, target) {1654 source = $(source);1655 target = $(target);1656 target.style.position = 'absolute';1657 var offsets = this.cumulativeOffset(source);1658 target.style.top = offsets[1] + 'px';1659 target.style.left = offsets[0] + 'px';1660 target.style.width = source.offsetWidth + 'px';1661 target.style.height = source.offsetHeight + 'px';1662 },1663 1664 2394 page: function(forElement) { 1665 2395 var valueT = 0, valueL = 0; … … 1678 2408 element = forElement; 1679 2409 do { 1680 valueT -= element.scrollTop || 0; 1681 valueL -= element.scrollLeft || 0; 2410 if (!window.opera || element.tagName=='BODY') { 2411 valueT -= element.scrollTop || 0; 2412 valueL -= element.scrollLeft || 0; 2413 } 1682 2414 } while (element = element.parentNode); 1683 2415 … … 1740 2472 1741 2473 element.style.position = 'absolute'; 1742 element.style.top = top + 'px'; ;1743 element.style.left = left + 'px'; ;1744 element.style.width = width + 'px'; ;1745 element.style.height = height + 'px'; ;2474 element.style.top = top + 'px'; 2475 element.style.left = left + 'px'; 2476 element.style.width = width + 'px'; 2477 element.style.height = height + 'px'; 1746 2478 }, 1747 2479 … … 1780 2512 } 1781 2513 } 2514 2515 Element.addMethods(); -
trunk/tools/ws.htm
r1849 r1852 6 6 7 7 <script type="text/javascript"> 8 function setElementText(id, text)9 {10 if (!text) text="";11 var elt = document.getElementById(id);12 if (!elt) alert('setElementText '+id);13 elt.innerHTML = text;14 }15 8 16 9 function setVisibility(id, vis) 17 10 { 18 document.getElementById(id).style.visibility = vis; 19 } 20 21 function clearError() 22 { 23 setElementText("error", ""); 11 $(id).style.visibility = vis; 24 12 } 25 13 … … 38 26 } 39 27 } 40 setElementText("error",s);28 $("error").update(s); 41 29 } 42 30 43 31 var gServiceUrl; 44 var gC urrentMethodParams;32 var gCachedMethods; 45 33 46 34 Ajax.Responders.register({ … … 101 89 function pwgChangeUrl() 102 90 { 103 clearError();91 $("error").update(""); 104 92 setVisibility("methodListWrapper", "hidden"); 105 setElementText("methodList","");93 $("methodList").update(""); 106 94 setVisibility("methodWrapper", "hidden"); 95 setVisibility("methodDetailWrapper", "hidden"); 107 96 108 97 gServiceUrl = $F('ws_url'); 109 gC urrentMethodParams = null;98 gCachedMethods = new Hash(); 110 99 111 100 try { … … 131 120 ml += '<li><a href="#" onclick="return pwgSelectMethod(this.innerHTML)">'+ result.methods[i]+'</a></li>'; 132 121 } 133 setElementText("methodList",ml);122 $("methodList").update(ml); 134 123 setVisibility("methodListWrapper", "visible"); 135 124 } 136 125 137 function pwgSelectMethod(method )138 { 139 clearError();140 setElementText("methodName", method);126 function pwgSelectMethod(methodName) 127 { 128 $("error").update(""); 129 $("methodName").update(methodName); 141 130 setVisibility("methodDetailWrapper", "hidden"); 142 131 setVisibility("methodWrapper", "visible"); 143 gCurrentMethodParams = null; 144 145 try { 146 147 var ajaxReq = new Ajax.Request( 148 gServiceUrl, 149 {method:'get', parameters:'format=json&method=reflection.getMethodDetails&methodName='+method, 150 onSuccess: function (r) { onSuccess_getMethodDetails(r); } 151 } 152 ) 153 }catch (e) 132 133 if ( gCachedMethods[methodName] ) 134 fillNewMethod( gCachedMethods[methodName] ); 135 else 154 136 { 155 dumpError( e ); 137 try { 138 var ajaxReq = new Ajax.Request( 139 gServiceUrl, 140 {method:'get', parameters:'format=json&method=reflection.getMethodDetails&methodName='+methodName, 141 onSuccess: function (r) { onSuccess_getMethodDetails(r); } 142 } 143 ) 144 }catch (e) 145 { 146 dumpError( e ); 147 } 156 148 } 157 149 return false; … … 161 153 { 162 154 var result = pwgGetJsonResult(transport); 155 fillNewMethod( gCachedMethods[result.name] = $H(result) ); 156 } 157 158 function fillNewMethod(method) 159 { 163 160 var methodParamsElt = $("methodParams"); 164 161 while (methodParamsElt.tBodies[0].rows.length) 165 162 methodParamsElt.tBodies[0].deleteRow(methodParamsElt.tBodies[0].rows.length-1); 166 163 167 if (result.params) 168 { 169 gCurrentMethodParams = result.params; 170 if (result.params.length>0) 171 { 172 for (var i=0; i<result.params.length; i++) 164 if (method.params && method.params.length>0) 165 { 166 for (var i=0; i<method.params.length; i++) 173 167 { 174 168 var row = methodParamsElt.tBodies[0].insertRow(-1); 175 var isOptional = result.params[i].optional; 176 var defaultValue = result.params[i].defaultValue == null ? '' : result.params[i].defaultValue; 169 var isOptional = method.params[i].optional; 170 var acceptArray = method.params[i].acceptArray; 171 var defaultValue = method.params[i].defaultValue == null ? '' : method.params[i].defaultValue; 177 172 178 row.insertCell(0).innerHTML = result.params[i].name; 179 row.insertCell(1).innerHTML = (isOptional ? 'optional':'required'); 173 row.insertCell(0).innerHTML = method.params[i].name; 174 row.insertCell(1).innerHTML = '<span title="parameter is '+(isOptional ? 'optional':'required') +'">'+(isOptional ? '?':'*')+'</span>' 175 + (method.params[i].acceptArray ? ' <span title="parameter can be an array; use | (pipe) character to split values">[ ]</span>':''); 180 176 row.insertCell(2).innerHTML = '<input id="methodParameterSend_'+i+'" type="checkbox" '+(isOptional ? '':'checked="checked"')+'/>'; 181 177 row.insertCell(3).innerHTML = '<input id="methodParameterValue_'+i+'"" value="'+defaultValue+'" style="width:99%" onchange="$(\'methodParameterSend_'+i+'\').checked=true;"/>'; 182 178 } 183 } 184 } 185 setElementText("methodDescription", result.description); 179 } 180 $("methodDescription").update(method.description); 186 181 setVisibility("methodDetailWrapper", "visible"); 187 182 } … … 189 184 function pwgInvokeMethod( newWindow ) 190 185 { 191 var method = document.getElementById('methodName').innerHTML; 186 var methodName = $('methodName').innerHTML; 187 var method = gCachedMethods[methodName]; 192 188 193 189 var reqUrl = gServiceUrl; 194 190 reqUrl += "?format="+$F('responseFormat'); 195 191 196 if ( document.getElementById('requestFormat').value == 'get')192 if ($('requestFormat').value == 'get') 197 193 { 198 reqUrl += "&method="+method ;199 for ( var i=0; i< gCurrentMethodParams.length; i++)194 reqUrl += "&method="+methodName; 195 for ( var i=0; i<method.params.length; i++) 200 196 { 201 if (document.getElementById('methodParameterSend_'+i).checked) 202 reqUrl += '&'+gCurrentMethodParams[i].name+'='+$F('methodParameterValue_'+i); 197 if (! $('methodParameterSend_'+i).checked) 198 continue; 199 200 if ( method.params[i].acceptArray && $F('methodParameterValue_'+i).split('|').length > 1 ) 201 { 202 $F('methodParameterValue_'+i).split('|').each( 203 function(v) { 204 reqUrl += '&'+method.params[i].name+'[]='+v; 205 } 206 ); 207 } 208 else 209 reqUrl += '&'+method.params[i].name+'='+$F('methodParameterValue_'+i); 203 210 } 204 211 if ( !newWindow ) 205 document.getElementById("invokeFrame").src = reqUrl;212 $("invokeFrame").src = reqUrl; 206 213 else 207 214 window.open(reqUrl); … … 209 216 else 210 217 { 211 var form = document.getElementById("invokeForm");218 var form = $("invokeForm"); 212 219 form.action = reqUrl; 213 var t = '<input type="hidden" name="'+'method'+'" value="'+method +'"/>';214 for ( var i=0; i< gCurrentMethodParams.length; i++)220 var t = '<input type="hidden" name="'+'method'+'" value="'+methodName+'"/>'; 221 for ( var i=0; i<method.params.length; i++) 215 222 { 216 if (document.getElementById('methodParameterSend_'+i).checked) 217 t += '<input type="hidden" name="'+gCurrentMethodParams[i].name+'" value="'+$F('methodParameterValue_'+i)+'"/>'; 223 if (! $('methodParameterSend_'+i).checked) 224 continue; 225 226 if ( method.params[i].acceptArray && $F('methodParameterValue_'+i).split('|').length > 1 ) 227 { 228 $F('methodParameterValue_'+i).split('|').each( 229 function(v) { 230 t += '<input type="hidden" name="'+method.params[i].name+'[]" value="'+v+'"/>'; 231 } 232 ); 233 } 234 else 235 t += '<input type="hidden" name="'+method.params[i].name+'" value="'+$F('methodParameterValue_'+i)+'"/>'; 218 236 } 219 237 form.innerHTML = t; 220 if ( !newWindow ) 221 form.target = "invokeFrame"; 222 else 223 form.target = "_blank"; 238 form.target = newWindow ? "_blank" : "invokeFrame"; 224 239 form.submit(); 225 240 } … … 357 372 <tr> 358 373 <td style="width:150px">Parameter</td> 359 <td> Optional</td>374 <td>Extra</td> 360 375 <td>Send</td> 361 376 <td style="width:160px">Value</td>
Note: See TracChangeset
for help on using the changeset viewer.