- Timestamp:
- Sep 28, 2007, 12:46:17 AM (17 years ago)
- Location:
- trunk
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/admin.php
r2065 r2107 75 75 $page['page_banner'] = '<h1>'.l10n('PhpWebGallery Administration').'</h1>'; 76 76 $page['body_id'] = 'theAdminPage'; 77 include(PHPWG_ROOT_PATH.'include/page_header.php');78 77 79 78 $template->set_filenames(array('admin' => 'admin.tpl')); … … 116 115 } 117 116 118 // required before plugin page inclusion117 //---------------------------------------------------------------- plugin menus 119 118 $plugin_menu_links = array( 120 119 array( … … 125 124 $plugin_menu_links = trigger_event('get_admin_plugin_menu_links', 126 125 $plugin_menu_links ); 127 126 foreach ($plugin_menu_links as $menu_item) 127 { 128 $template->assign_block_vars('plugin_menu.menu_item', $menu_item); 129 } 128 130 129 131 include(PHPWG_ROOT_PATH.'admin/'.$page['page'].'.php'); 130 132 131 133 //------------------------------------------------------------- content display 132 foreach ($plugin_menu_links as $menu_item)133 {134 $template->assign_block_vars('plugin_menu.menu_item', $menu_item);135 }136 134 137 135 // +-----------------------------------------------------------------------+ … … 155 153 } 156 154 155 include(PHPWG_ROOT_PATH.'include/page_header.php'); 157 156 $template->parse('admin'); 158 157 … … 172 171 'cat_perm', // ?only POST 173 172 'element_set', // ?only POST; associate/dissociate 173 'picture_modify', // ?only POST; associate/dissociate 174 174 'user_list', // ?only POST; group assoc 175 175 'user_perm', -
trunk/admin/site_update.php
r2038 r2107 232 232 // retrieve sub-directories fulldirs from the site reader 233 233 $fs_fulldirs = $site_reader->get_full_directories($basedir); 234 //print_r( $fs_fulldirs ); echo "<br>";235 234 236 235 // get_full_directories doesn't include the base directory, so if it's a … … 353 352 } 354 353 355 echo '<!-- scanning dirs : ';356 echo get_elapsed_time($start, get_moment());357 echo' -->'."\n";354 $template->output .= '<!-- scanning dirs : ' 355 . get_elapsed_time($start, get_moment()) 356 . ' -->'."\n"; 358 357 } 359 358 // +-----------------------------------------------------------------------+ … … 367 366 368 367 $fs = $site_reader->get_elements($basedir); 369 //print_r($fs); echo "<br>"; 370 echo '<!-- get_elements: '.get_elapsed_time($start, get_moment())." -->\n"; 368 $template->output .= '<!-- get_elements: ' 369 . get_elapsed_time($start, get_moment()) 370 . " -->\n"; 371 371 372 372 $cat_ids = array_diff(array_keys($db_categories), $to_delete); … … 572 572 } 573 573 574 echo '<!-- scanning files : ';575 echo get_elapsed_time($start_files, get_moment());576 echo' -->'."\n";574 $template->output .= '<!-- scanning files : ' 575 . get_elapsed_time($start_files, get_moment()) 576 . ' -->'."\n"; 577 577 578 578 // retrieving informations given by uploaders … … 644 644 $start = get_moment(); 645 645 update_category('all'); 646 echo '<!-- update_category(all) : ';647 echo get_elapsed_time($start,get_moment());648 echo' -->'."\n";646 $template->output .= '<!-- update_category(all) : ' 647 . get_elapsed_time($start,get_moment()) 648 . ' -->'."\n"; 649 649 $start = get_moment(); 650 650 ordering(); 651 651 update_global_rank(); 652 echo '<!-- ordering categories : ';653 echo get_elapsed_time($start, get_moment());654 echo' -->'."\n";652 $template->output .= '<!-- ordering categories : ' 653 . get_elapsed_time($start, get_moment()) 654 . ' -->'."\n"; 655 655 } 656 656 … … 671 671 $opts['recursive'], 672 672 false); 673 echo '<!-- get_filelist : ';674 echo get_elapsed_time($start, get_moment());675 echo' -->'."\n";673 $template->output .= '<!-- get_filelist : ' 674 . get_elapsed_time($start, get_moment()) 675 . ' -->'."\n"; 676 676 $start = get_moment(); 677 677 … … 717 717 ); 718 718 } 719 echo '<!-- update files : ';720 echo get_elapsed_time($start,get_moment());721 echo' -->'."\n";719 $template->output .= '<!-- update files : ' 720 . get_elapsed_time($start,get_moment()) 721 . ' -->'."\n"; 722 722 }// end if sync files 723 723 } … … 773 773 $opts['only_new']); 774 774 775 echo '<!-- get_filelist : ';776 echo get_elapsed_time($start, get_moment());777 echo' -->'."\n";775 $template->output .= '<!-- get_filelist : ' 776 . get_elapsed_time($start, get_moment()) 777 . ' -->'."\n"; 778 778 779 779 $start = get_moment(); … … 806 806 } 807 807 } 808 808 809 809 foreach ( $files as $id=>$file ) 810 810 { … … 813 813 in_array($id, $has_high_images) 814 814 ); 815 815 816 816 if ( is_array($data) ) 817 817 { … … 849 849 if (count($datas) > 0) 850 850 { 851 // echo '<pre>', print_r($datas); echo '</pre>';852 853 851 mass_updates( 854 852 IMAGES_TABLE, … … 872 870 } 873 871 874 echo '<!-- metadata update : ';875 echo get_elapsed_time($start, get_moment());876 echo' -->'."\n";872 $template->output .= '<!-- metadata update : ' 873 . get_elapsed_time($start, get_moment()) 874 . ' -->'."\n"; 877 875 878 876 $template->assign_block_vars( -
trunk/comments.php
r2030 r2107 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$ … … 176 175 $title= l10n('title_comments'); 177 176 $page['body_id'] = 'theCommentsPage'; 178 include(PHPWG_ROOT_PATH.'include/page_header.php');179 177 180 178 $template->set_filenames(array('comments'=>'comments.tpl')); … … 443 441 // | html code display | 444 442 // +-----------------------------------------------------------------------+ 445 $template->assign_block_vars('title',array());443 include(PHPWG_ROOT_PATH.'include/page_header.php'); 446 444 $template->parse('comments'); 447 445 include(PHPWG_ROOT_PATH.'include/page_tail.php'); -
trunk/tags.php
r1912 r2107 60 60 $title= l10n('Tags'); 61 61 $page['body_id'] = 'theTagsPage'; 62 include(PHPWG_ROOT_PATH.'include/page_header.php');63 62 64 63 $template->set_filenames(array('tags'=>'tags.tpl')); … … 106 105 } 107 106 108 // +-----------------------------------------------------------------------+ 109 // | html code display | 110 // +-----------------------------------------------------------------------+ 111 112 $template->assign_block_vars('title',array()); 107 include(PHPWG_ROOT_PATH.'include/page_header.php'); 113 108 $template->parse('tags'); 114 109 include(PHPWG_ROOT_PATH.'include/page_tail.php'); -
trunk/template/yoga/theme/dark/theme.css
r2101 r2107 118 118 119 119 .virtual_cat { background: #3f3f3f !important; } 120 #mbMenu #quicksearch > p { text-align: left; } -
trunk/tools/prototype.js
r1912 r2107 1 /* Prototype JavaScript framework, version 1.5. 01 /* Prototype JavaScript framework, version 1.5.1.1 2 2 * (c) 2005-2007 Sam Stephenson 3 3 * 4 4 * Prototype is freely distributable under the terms of an MIT-style license. 5 * For details, see the Prototype web site: http:// prototype.conio.net/5 * For details, see the Prototype web site: http://www.prototypejs.org/ 6 6 * 7 7 /*--------------------------------------------------------------------------*/ 8 8 9 9 var Prototype = { 10 Version: '1.5.0', 11 BrowserFeatures: { 12 XPath: !!document.evaluate 13 }, 14 15 ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)', 16 emptyFunction: function() {}, 17 K: function(x) { return x } 10 Version: '1.5.1.1', 11 12 Browser: { 13 IE: !!(window.attachEvent && !window.opera), 14 Opera: !!window.opera, 15 WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, 16 Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1 17 }, 18 19 BrowserFeatures: { 20 XPath: !!document.evaluate, 21 ElementExtensions: !!window.HTMLElement, 22 SpecificElementExtensions: 23 (document.createElement('div').__proto__ !== 24 document.createElement('form').__proto__) 25 }, 26 27 ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>', 28 JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, 29 30 emptyFunction: function() { }, 31 K: function(x) { return x } 18 32 } 19 33 20 34 var Class = { 21 22 23 24 25 35 create: function() { 36 return function() { 37 this.initialize.apply(this, arguments); 38 } 39 } 26 40 } 27 41 … … 29 43 30 44 Object.extend = function(destination, source) { 31 32 33 34 45 for (var property in source) { 46 destination[property] = source[property]; 47 } 48 return destination; 35 49 } 36 50 37 51 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 } 52 inspect: function(object) { 53 try { 54 if (object === undefined) return 'undefined'; 55 if (object === null) return 'null'; 56 return object.inspect ? object.inspect() : object.toString(); 57 } catch (e) { 58 if (e instanceof RangeError) return '...'; 59 throw e; 60 } 61 }, 62 63 toJSON: function(object) { 64 var type = typeof object; 65 switch(type) { 66 case 'undefined': 67 case 'function': 68 case 'unknown': return; 69 case 'boolean': return object.toString(); 70 } 71 if (object === null) return 'null'; 72 if (object.toJSON) return object.toJSON(); 73 if (object.ownerDocument === document) return; 74 var results = []; 75 for (var property in object) { 76 var value = Object.toJSON(object[property]); 77 if (value !== undefined) 78 results.push(property.toJSON() + ': ' + value); 79 } 80 return '{' + results.join(', ') + '}'; 81 }, 82 83 keys: function(object) { 84 var keys = []; 85 for (var property in object) 86 keys.push(property); 87 return keys; 88 }, 89 90 values: function(object) { 91 var values = []; 92 for (var property in object) 93 values.push(object[property]); 94 return values; 95 }, 96 97 clone: function(object) { 98 return Object.extend({}, object); 99 } 66 100 }); 67 101 68 102 Function.prototype.bind = function() { 69 70 71 72 103 var __method = this, args = $A(arguments), object = args.shift(); 104 return function() { 105 return __method.apply(object, args.concat($A(arguments))); 106 } 73 107 } 74 108 75 109 Function.prototype.bindAsEventListener = function(object) { 76 77 78 return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));79 110 var __method = this, args = $A(arguments), object = args.shift(); 111 return function(event) { 112 return __method.apply(object, [event || window.event].concat(args)); 113 } 80 114 } 81 115 82 116 Object.extend(Number.prototype, { 83 toColorPart: function() { 84 var digits = this.toString(16); 85 if (this < 16) return '0' + digits; 86 return digits; 87 }, 88 89 succ: function() { 90 return this + 1; 91 }, 92 93 times: function(iterator) { 94 $R(0, this, true).each(iterator); 95 return this; 96 } 117 toColorPart: function() { 118 return this.toPaddedString(2, 16); 119 }, 120 121 succ: function() { 122 return this + 1; 123 }, 124 125 times: function(iterator) { 126 $R(0, this, true).each(iterator); 127 return this; 128 }, 129 130 toPaddedString: function(length, radix) { 131 var string = this.toString(radix || 10); 132 return '0'.times(length - string.length) + string; 133 }, 134 135 toJSON: function() { 136 return isFinite(this) ? this.toString() : 'null'; 137 } 97 138 }); 98 139 140 Date.prototype.toJSON = function() { 141 return '"' + this.getFullYear() + '-' + 142 (this.getMonth() + 1).toPaddedString(2) + '-' + 143 this.getDate().toPaddedString(2) + 'T' + 144 this.getHours().toPaddedString(2) + ':' + 145 this.getMinutes().toPaddedString(2) + ':' + 146 this.getSeconds().toPaddedString(2) + '"'; 147 }; 148 99 149 var Try = { 100 101 102 103 104 105 106 107 108 109 110 111 112 150 these: function() { 151 var returnValue; 152 153 for (var i = 0, length = arguments.length; i < length; i++) { 154 var lambda = arguments[i]; 155 try { 156 returnValue = lambda(); 157 break; 158 } catch (e) {} 159 } 160 161 return returnValue; 162 } 113 163 } 114 164 … … 117 167 var PeriodicalExecuter = Class.create(); 118 168 PeriodicalExecuter.prototype = { 119 initialize: function(callback, frequency) { 120 this.callback = callback; 121 this.frequency = frequency; 122 this.currentlyExecuting = false; 123 124 this.registerCallback(); 125 }, 126 127 registerCallback: function() { 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; 135 }, 136 137 onTimerEvent: function() { 138 if (!this.currentlyExecuting) { 139 try { 140 this.currentlyExecuting = true; 141 this.callback(this); 142 } finally { 143 this.currentlyExecuting = false; 144 } 145 } 146 } 147 } 148 String.interpret = function(value){ 149 return value == null ? '' : String(value); 150 } 169 initialize: function(callback, frequency) { 170 this.callback = callback; 171 this.frequency = frequency; 172 this.currentlyExecuting = false; 173 174 this.registerCallback(); 175 }, 176 177 registerCallback: function() { 178 this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); 179 }, 180 181 stop: function() { 182 if (!this.timer) return; 183 clearInterval(this.timer); 184 this.timer = null; 185 }, 186 187 onTimerEvent: function() { 188 if (!this.currentlyExecuting) { 189 try { 190 this.currentlyExecuting = true; 191 this.callback(this); 192 } finally { 193 this.currentlyExecuting = false; 194 } 195 } 196 } 197 } 198 Object.extend(String, { 199 interpret: function(value) { 200 return value == null ? '' : String(value); 201 }, 202 specialChar: { 203 '\b': '\\b', 204 '\t': '\\t', 205 '\n': '\\n', 206 '\f': '\\f', 207 '\r': '\\r', 208 '\\': '\\\\' 209 } 210 }); 151 211 152 212 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 195 stripTags: function() { 196 return this.replace(/<\/?[^>]+>/gi, ''); 197 }, 198 199 stripScripts: function() { 200 return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); 201 }, 202 203 extractScripts: function() { 204 var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); 205 var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); 206 return (this.match(matchAll) || []).map(function(scriptTag) { 207 return (scriptTag.match(matchOne) || ['', ''])[1]; 208 }); 209 }, 210 211 evalScripts: function() { 212 return this.extractScripts().map(function(script) { return eval(script) }); 213 }, 214 215 escapeHTML: function() { 216 var div = document.createElement('div'); 217 var text = document.createTextNode(this); 218 div.appendChild(text); 219 return div.innerHTML; 220 }, 221 222 unescapeHTML: function() { 223 var div = document.createElement('div'); 224 div.innerHTML = this.stripTags(); 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; 247 }); 248 }, 249 250 toArray: function() { 251 return this.split(''); 252 }, 253 254 succ: function() { 255 return this.slice(0, this.length - 1) + 256 String.fromCharCode(this.charCodeAt(this.length - 1) + 1); 257 }, 258 259 camelize: function() { 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, '\\\'') + "'"; 291 } 213 gsub: function(pattern, replacement) { 214 var result = '', source = this, match; 215 replacement = arguments.callee.prepareReplacement(replacement); 216 217 while (source.length > 0) { 218 if (match = source.match(pattern)) { 219 result += source.slice(0, match.index); 220 result += String.interpret(replacement(match)); 221 source = source.slice(match.index + match[0].length); 222 } else { 223 result += source, source = ''; 224 } 225 } 226 return result; 227 }, 228 229 sub: function(pattern, replacement, count) { 230 replacement = this.gsub.prepareReplacement(replacement); 231 count = count === undefined ? 1 : count; 232 233 return this.gsub(pattern, function(match) { 234 if (--count < 0) return match[0]; 235 return replacement(match); 236 }); 237 }, 238 239 scan: function(pattern, iterator) { 240 this.gsub(pattern, iterator); 241 return this; 242 }, 243 244 truncate: function(length, truncation) { 245 length = length || 30; 246 truncation = truncation === undefined ? '...' : truncation; 247 return this.length > length ? 248 this.slice(0, length - truncation.length) + truncation : this; 249 }, 250 251 strip: function() { 252 return this.replace(/^\s+/, '').replace(/\s+$/, ''); 253 }, 254 255 stripTags: function() { 256 return this.replace(/<\/?[^>]+>/gi, ''); 257 }, 258 259 stripScripts: function() { 260 return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); 261 }, 262 263 extractScripts: function() { 264 var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); 265 var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); 266 return (this.match(matchAll) || []).map(function(scriptTag) { 267 return (scriptTag.match(matchOne) || ['', ''])[1]; 268 }); 269 }, 270 271 evalScripts: function() { 272 return this.extractScripts().map(function(script) { return eval(script) }); 273 }, 274 275 escapeHTML: function() { 276 var self = arguments.callee; 277 self.text.data = this; 278 return self.div.innerHTML; 279 }, 280 281 unescapeHTML: function() { 282 var div = document.createElement('div'); 283 div.innerHTML = this.stripTags(); 284 return div.childNodes[0] ? (div.childNodes.length > 1 ? 285 $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : 286 div.childNodes[0].nodeValue) : ''; 287 }, 288 289 toQueryParams: function(separator) { 290 var match = this.strip().match(/([^?#]*)(#.*)?$/); 291 if (!match) return {}; 292 293 return match[1].split(separator || '&').inject({}, function(hash, pair) { 294 if ((pair = pair.split('='))[0]) { 295 var key = decodeURIComponent(pair.shift()); 296 var value = pair.length > 1 ? pair.join('=') : pair[0]; 297 if (value != undefined) value = decodeURIComponent(value); 298 299 if (key in hash) { 300 if (hash[key].constructor != Array) hash[key] = [hash[key]]; 301 hash[key].push(value); 302 } 303 else hash[key] = value; 304 } 305 return hash; 306 }); 307 }, 308 309 toArray: function() { 310 return this.split(''); 311 }, 312 313 succ: function() { 314 return this.slice(0, this.length - 1) + 315 String.fromCharCode(this.charCodeAt(this.length - 1) + 1); 316 }, 317 318 times: function(count) { 319 var result = ''; 320 for (var i = 0; i < count; i++) result += this; 321 return result; 322 }, 323 324 camelize: function() { 325 var parts = this.split('-'), len = parts.length; 326 if (len == 1) return parts[0]; 327 328 var camelized = this.charAt(0) == '-' 329 ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) 330 : parts[0]; 331 332 for (var i = 1; i < len; i++) 333 camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); 334 335 return camelized; 336 }, 337 338 capitalize: function() { 339 return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); 340 }, 341 342 underscore: function() { 343 return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); 344 }, 345 346 dasherize: function() { 347 return this.gsub(/_/,'-'); 348 }, 349 350 inspect: function(useDoubleQuotes) { 351 var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { 352 var character = String.specialChar[match[0]]; 353 return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16); 354 }); 355 if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; 356 return "'" + escapedString.replace(/'/g, '\\\'') + "'"; 357 }, 358 359 toJSON: function() { 360 return this.inspect(true); 361 }, 362 363 unfilterJSON: function(filter) { 364 return this.sub(filter || Prototype.JSONFilter, '#{1}'); 365 }, 366 367 isJSON: function() { 368 var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); 369 return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); 370 }, 371 372 evalJSON: function(sanitize) { 373 var json = this.unfilterJSON(); 374 try { 375 if (!sanitize || json.isJSON()) return eval('(' + json + ')'); 376 } catch (e) { } 377 throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); 378 }, 379 380 include: function(pattern) { 381 return this.indexOf(pattern) > -1; 382 }, 383 384 startsWith: function(pattern) { 385 return this.indexOf(pattern) === 0; 386 }, 387 388 endsWith: function(pattern) { 389 var d = this.length - pattern.length; 390 return d >= 0 && this.lastIndexOf(pattern) === d; 391 }, 392 393 empty: function() { 394 return this == ''; 395 }, 396 397 blank: function() { 398 return /^\s*$/.test(this); 399 } 292 400 }); 293 401 402 if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { 403 escapeHTML: function() { 404 return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); 405 }, 406 unescapeHTML: function() { 407 return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); 408 } 409 }); 410 294 411 String.prototype.gsub.prepareReplacement = function(replacement) { 295 296 297 412 if (typeof replacement == 'function') return replacement; 413 var template = new Template(replacement); 414 return function(match) { return template.evaluate(match) }; 298 415 } 299 416 300 417 String.prototype.parseQuery = String.prototype.toQueryParams; 418 419 Object.extend(String.prototype.escapeHTML, { 420 div: document.createElement('div'), 421 text: document.createTextNode('') 422 }); 423 424 with (String.prototype.escapeHTML) div.appendChild(text); 301 425 302 426 var Template = Class.create(); 303 427 Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; 304 428 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 } 318 319 var $break = new Object(); 320 var $continue = new Object(); 429 initialize: function(template, pattern) { 430 this.template = template.toString(); 431 this.pattern = pattern || Template.Pattern; 432 }, 433 434 evaluate: function(object) { 435 return this.template.gsub(this.pattern, function(match) { 436 var before = match[1]; 437 if (before == '\\') return match[2]; 438 return before + String.interpret(object[match[3]]); 439 }); 440 } 441 } 442 443 var $break = {}, $continue = new Error('"throw $continue" is deprecated, use "return" instead'); 321 444 322 445 var Enumerable = { 323 each: function(iterator) { 324 var index = 0; 325 try { 326 this._each(function(value) { 327 try { 328 iterator(value, index++); 329 } catch (e) { 330 if (e != $continue) throw e; 331 } 332 }); 333 } catch (e) { 334 if (e != $break) throw e; 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); 344 }, 345 346 all: function(iterator) { 347 var result = true; 348 this.each(function(value, index) { 349 result = result && !!(iterator || Prototype.K)(value, index); 350 if (!result) throw $break; 351 }); 352 return result; 353 }, 354 355 any: function(iterator) { 356 var result = false; 357 this.each(function(value, index) { 358 if (result = !!(iterator || Prototype.K)(value, index)) 359 throw $break; 360 }); 361 return result; 362 }, 363 364 collect: function(iterator) { 365 var results = []; 366 this.each(function(value, index) { 367 results.push((iterator || Prototype.K)(value, index)); 368 }); 369 return results; 370 }, 371 372 detect: function(iterator) { 373 var result; 374 this.each(function(value, index) { 375 if (iterator(value, index)) { 376 result = value; 377 throw $break; 378 } 379 }); 380 return result; 381 }, 382 383 findAll: function(iterator) { 384 var results = []; 385 this.each(function(value, index) { 386 if (iterator(value, index)) 387 results.push(value); 388 }); 389 return results; 390 }, 391 392 grep: function(pattern, iterator) { 393 var results = []; 394 this.each(function(value, index) { 395 var stringValue = value.toString(); 396 if (stringValue.match(pattern)) 397 results.push((iterator || Prototype.K)(value, index)); 398 }) 399 return results; 400 }, 401 402 include: function(object) { 403 var found = false; 404 this.each(function(value) { 405 if (value == object) { 406 found = true; 407 throw $break; 408 } 409 }); 410 return found; 411 }, 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 421 inject: function(memo, iterator) { 422 this.each(function(value, index) { 423 memo = iterator(memo, value, index); 424 }); 425 return memo; 426 }, 427 428 invoke: function(method) { 429 var args = $A(arguments).slice(1); 430 return this.map(function(value) { 431 return value[method].apply(value, args); 432 }); 433 }, 434 435 max: function(iterator) { 436 var result; 437 this.each(function(value, index) { 438 value = (iterator || Prototype.K)(value, index); 439 if (result == undefined || value >= result) 440 result = value; 441 }); 442 return result; 443 }, 444 445 min: function(iterator) { 446 var result; 447 this.each(function(value, index) { 448 value = (iterator || Prototype.K)(value, index); 449 if (result == undefined || value < result) 450 result = value; 451 }); 452 return result; 453 }, 454 455 partition: function(iterator) { 456 var trues = [], falses = []; 457 this.each(function(value, index) { 458 ((iterator || Prototype.K)(value, index) ? 459 trues : falses).push(value); 460 }); 461 return [trues, falses]; 462 }, 463 464 pluck: function(property) { 465 var results = []; 466 this.each(function(value, index) { 467 results.push(value[property]); 468 }); 469 return results; 470 }, 471 472 reject: function(iterator) { 473 var results = []; 474 this.each(function(value, index) { 475 if (!iterator(value, index)) 476 results.push(value); 477 }); 478 return results; 479 }, 480 481 sortBy: function(iterator) { 482 return this.map(function(value, index) { 483 return {value: value, criteria: iterator(value, index)}; 484 }).sort(function(left, right) { 485 var a = left.criteria, b = right.criteria; 486 return a < b ? -1 : a > b ? 1 : 0; 487 }).pluck('value'); 488 }, 489 490 toArray: function() { 491 return this.map(); 492 }, 493 494 zip: function() { 495 var iterator = Prototype.K, args = $A(arguments); 496 if (typeof args.last() == 'function') 497 iterator = args.pop(); 498 499 var collections = [this].concat(args).map($A); 500 return this.map(function(value, index) { 501 return iterator(collections.pluck(index)); 502 }); 503 }, 504 505 size: function() { 506 return this.toArray().length; 507 }, 508 509 inspect: function() { 510 return '#<Enumerable:' + this.toArray().inspect() + '>'; 511 } 446 each: function(iterator) { 447 var index = 0; 448 try { 449 this._each(function(value) { 450 iterator(value, index++); 451 }); 452 } catch (e) { 453 if (e != $break) throw e; 454 } 455 return this; 456 }, 457 458 eachSlice: function(number, iterator) { 459 var index = -number, slices = [], array = this.toArray(); 460 while ((index += number) < array.length) 461 slices.push(array.slice(index, index+number)); 462 return slices.map(iterator); 463 }, 464 465 all: function(iterator) { 466 var result = true; 467 this.each(function(value, index) { 468 result = result && !!(iterator || Prototype.K)(value, index); 469 if (!result) throw $break; 470 }); 471 return result; 472 }, 473 474 any: function(iterator) { 475 var result = false; 476 this.each(function(value, index) { 477 if (result = !!(iterator || Prototype.K)(value, index)) 478 throw $break; 479 }); 480 return result; 481 }, 482 483 collect: function(iterator) { 484 var results = []; 485 this.each(function(value, index) { 486 results.push((iterator || Prototype.K)(value, index)); 487 }); 488 return results; 489 }, 490 491 detect: function(iterator) { 492 var result; 493 this.each(function(value, index) { 494 if (iterator(value, index)) { 495 result = value; 496 throw $break; 497 } 498 }); 499 return result; 500 }, 501 502 findAll: function(iterator) { 503 var results = []; 504 this.each(function(value, index) { 505 if (iterator(value, index)) 506 results.push(value); 507 }); 508 return results; 509 }, 510 511 grep: function(pattern, iterator) { 512 var results = []; 513 this.each(function(value, index) { 514 var stringValue = value.toString(); 515 if (stringValue.match(pattern)) 516 results.push((iterator || Prototype.K)(value, index)); 517 }) 518 return results; 519 }, 520 521 include: function(object) { 522 var found = false; 523 this.each(function(value) { 524 if (value == object) { 525 found = true; 526 throw $break; 527 } 528 }); 529 return found; 530 }, 531 532 inGroupsOf: function(number, fillWith) { 533 fillWith = fillWith === undefined ? null : fillWith; 534 return this.eachSlice(number, function(slice) { 535 while(slice.length < number) slice.push(fillWith); 536 return slice; 537 }); 538 }, 539 540 inject: function(memo, iterator) { 541 this.each(function(value, index) { 542 memo = iterator(memo, value, index); 543 }); 544 return memo; 545 }, 546 547 invoke: function(method) { 548 var args = $A(arguments).slice(1); 549 return this.map(function(value) { 550 return value[method].apply(value, args); 551 }); 552 }, 553 554 max: function(iterator) { 555 var result; 556 this.each(function(value, index) { 557 value = (iterator || Prototype.K)(value, index); 558 if (result == undefined || value >= result) 559 result = value; 560 }); 561 return result; 562 }, 563 564 min: function(iterator) { 565 var result; 566 this.each(function(value, index) { 567 value = (iterator || Prototype.K)(value, index); 568 if (result == undefined || value < result) 569 result = value; 570 }); 571 return result; 572 }, 573 574 partition: function(iterator) { 575 var trues = [], falses = []; 576 this.each(function(value, index) { 577 ((iterator || Prototype.K)(value, index) ? 578 trues : falses).push(value); 579 }); 580 return [trues, falses]; 581 }, 582 583 pluck: function(property) { 584 var results = []; 585 this.each(function(value, index) { 586 results.push(value[property]); 587 }); 588 return results; 589 }, 590 591 reject: function(iterator) { 592 var results = []; 593 this.each(function(value, index) { 594 if (!iterator(value, index)) 595 results.push(value); 596 }); 597 return results; 598 }, 599 600 sortBy: function(iterator) { 601 return this.map(function(value, index) { 602 return {value: value, criteria: iterator(value, index)}; 603 }).sort(function(left, right) { 604 var a = left.criteria, b = right.criteria; 605 return a < b ? -1 : a > b ? 1 : 0; 606 }).pluck('value'); 607 }, 608 609 toArray: function() { 610 return this.map(); 611 }, 612 613 zip: function() { 614 var iterator = Prototype.K, args = $A(arguments); 615 if (typeof args.last() == 'function') 616 iterator = args.pop(); 617 618 var collections = [this].concat(args).map($A); 619 return this.map(function(value, index) { 620 return iterator(collections.pluck(index)); 621 }); 622 }, 623 624 size: function() { 625 return this.toArray().length; 626 }, 627 628 inspect: function() { 629 return '#<Enumerable:' + this.toArray().inspect() + '>'; 630 } 512 631 } 513 632 514 633 Object.extend(Enumerable, { 515 516 517 518 519 634 map: Enumerable.collect, 635 find: Enumerable.detect, 636 select: Enumerable.findAll, 637 member: Enumerable.include, 638 entries: Enumerable.toArray 520 639 }); 521 640 var $A = Array.from = function(iterable) { 522 if (!iterable) return []; 523 if (iterable.toArray) { 524 return iterable.toArray(); 525 } else { 526 var results = []; 527 for (var i = 0, length = iterable.length; i < length; i++) 528 results.push(iterable[i]); 529 return results; 530 } 641 if (!iterable) return []; 642 if (iterable.toArray) { 643 return iterable.toArray(); 644 } else { 645 var results = []; 646 for (var i = 0, length = iterable.length; i < length; i++) 647 results.push(iterable[i]); 648 return results; 649 } 650 } 651 652 if (Prototype.Browser.WebKit) { 653 $A = Array.from = function(iterable) { 654 if (!iterable) return []; 655 if (!(typeof iterable == 'function' && iterable == '[object NodeList]') && 656 iterable.toArray) { 657 return iterable.toArray(); 658 } else { 659 var results = []; 660 for (var i = 0, length = iterable.length; i < length; i++) 661 results.push(iterable[i]); 662 return results; 663 } 664 } 531 665 } 532 666 … … 534 668 535 669 if (!Array.prototype._reverse) 536 670 Array.prototype._reverse = Array.prototype.reverse; 537 671 538 672 Object.extend(Array.prototype, { 539 _each: function(iterator) { 540 for (var i = 0, length = this.length; i < length; i++) 541 iterator(this[i]); 542 }, 543 544 clear: function() { 545 this.length = 0; 546 return this; 547 }, 548 549 first: function() { 550 return this[0]; 551 }, 552 553 last: function() { 554 return this[this.length - 1]; 555 }, 556 557 compact: function() { 558 return this.select(function(value) { 559 return value != null; 560 }); 561 }, 562 563 flatten: function() { 564 return this.inject([], function(array, value) { 565 return array.concat(value && value.constructor == Array ? 566 value.flatten() : [value]); 567 }); 568 }, 569 570 without: function() { 571 var values = $A(arguments); 572 return this.select(function(value) { 573 return !values.include(value); 574 }); 575 }, 576 577 indexOf: function(object) { 578 for (var i = 0, length = this.length; i < length; i++) 579 if (this[i] == object) return i; 580 return -1; 581 }, 582 583 reverse: function(inline) { 584 return (inline !== false ? this : this.toArray())._reverse(); 585 }, 586 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; 603 }, 604 605 inspect: function() { 606 return '[' + this.map(Object.inspect).join(', ') + ']'; 607 } 673 _each: function(iterator) { 674 for (var i = 0, length = this.length; i < length; i++) 675 iterator(this[i]); 676 }, 677 678 clear: function() { 679 this.length = 0; 680 return this; 681 }, 682 683 first: function() { 684 return this[0]; 685 }, 686 687 last: function() { 688 return this[this.length - 1]; 689 }, 690 691 compact: function() { 692 return this.select(function(value) { 693 return value != null; 694 }); 695 }, 696 697 flatten: function() { 698 return this.inject([], function(array, value) { 699 return array.concat(value && value.constructor == Array ? 700 value.flatten() : [value]); 701 }); 702 }, 703 704 without: function() { 705 var values = $A(arguments); 706 return this.select(function(value) { 707 return !values.include(value); 708 }); 709 }, 710 711 indexOf: function(object) { 712 for (var i = 0, length = this.length; i < length; i++) 713 if (this[i] == object) return i; 714 return -1; 715 }, 716 717 reverse: function(inline) { 718 return (inline !== false ? this : this.toArray())._reverse(); 719 }, 720 721 reduce: function() { 722 return this.length > 1 ? this : this[0]; 723 }, 724 725 uniq: function(sorted) { 726 return this.inject([], function(array, value, index) { 727 if (0 == index || (sorted ? array.last() != value : !array.include(value))) 728 array.push(value); 729 return array; 730 }); 731 }, 732 733 clone: function() { 734 return [].concat(this); 735 }, 736 737 size: function() { 738 return this.length; 739 }, 740 741 inspect: function() { 742 return '[' + this.map(Object.inspect).join(', ') + ']'; 743 }, 744 745 toJSON: function() { 746 var results = []; 747 this.each(function(object) { 748 var value = Object.toJSON(object); 749 if (value !== undefined) results.push(value); 750 }); 751 return '[' + results.join(', ') + ']'; 752 } 608 753 }); 609 754 610 755 Array.prototype.toArray = Array.prototype.clone; 611 756 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 || {}); 757 function $w(string) { 758 string = string.strip(); 759 return string ? string.split(/\s+/) : []; 760 } 761 762 if (Prototype.Browser.Opera){ 763 Array.prototype.concat = function() { 764 var array = []; 765 for (var i = 0, length = this.length; i < length; i++) array.push(this[i]); 766 for (var i = 0, length = arguments.length; i < length; i++) { 767 if (arguments[i].constructor == Array) { 768 for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) 769 array.push(arguments[i][j]); 770 } else { 771 array.push(arguments[i]); 772 } 773 } 774 return array; 775 } 776 } 777 var Hash = function(object) { 778 if (object instanceof Hash) this.merge(object); 779 else Object.extend(this, object || {}); 634 780 }; 635 781 636 782 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 } 783 toQueryString: function(obj) { 784 var parts = []; 785 parts.add = arguments.callee.addPair; 786 787 this.prototype._each.call(obj, function(pair) { 788 if (!pair.key) return; 789 var value = pair.value; 790 791 if (value && typeof value == 'object') { 792 if (value.constructor == Array) value.each(function(value) { 793 parts.add(pair.key, value); 794 }); 795 return; 796 } 797 parts.add(pair.key, value); 798 }); 799 800 return parts.join('&'); 801 }, 802 803 toJSON: function(object) { 804 var results = []; 805 this.prototype._each.call(object, function(pair) { 806 var value = Object.toJSON(pair.value); 807 if (value !== undefined) results.push(pair.key.toJSON() + ': ' + value); 808 }); 809 return '{' + results.join(', ') + '}'; 810 } 661 811 }); 812 813 Hash.toQueryString.addPair = function(key, value, prefix) { 814 key = encodeURIComponent(key); 815 if (value === undefined) this.push(key); 816 else this.push(key + '=' + (value == null ? '' : encodeURIComponent(value))); 817 } 662 818 663 819 Object.extend(Hash.prototype, Enumerable); 664 820 Object.extend(Hash.prototype, { 665 _each: function(iterator) { 666 for (var key in this) { 667 var value = this[key]; 668 if (value && value == Hash.prototype[key]) continue; 669 670 var pair = [key, value]; 671 pair.key = key; 672 pair.value = value; 673 iterator(pair); 674 } 675 }, 676 677 keys: function() { 678 return this.pluck('key'); 679 }, 680 681 values: function() { 682 return this.pluck('value'); 683 }, 684 685 merge: function(hash) { 686 return $H(hash).inject(this, function(mergedHash, pair) { 687 mergedHash[pair.key] = pair.value; 688 return mergedHash; 689 }); 690 }, 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 708 toQueryString: function() { 709 return Hash.toQueryString(this); 710 }, 711 712 inspect: function() { 713 return '#<Hash:{' + this.map(function(pair) { 714 return pair.map(Object.inspect).join(': '); 715 }).join(', ') + '}>'; 716 } 821 _each: function(iterator) { 822 for (var key in this) { 823 var value = this[key]; 824 if (value && value == Hash.prototype[key]) continue; 825 826 var pair = [key, value]; 827 pair.key = key; 828 pair.value = value; 829 iterator(pair); 830 } 831 }, 832 833 keys: function() { 834 return this.pluck('key'); 835 }, 836 837 values: function() { 838 return this.pluck('value'); 839 }, 840 841 merge: function(hash) { 842 return $H(hash).inject(this, function(mergedHash, pair) { 843 mergedHash[pair.key] = pair.value; 844 return mergedHash; 845 }); 846 }, 847 848 remove: function() { 849 var result; 850 for(var i = 0, length = arguments.length; i < length; i++) { 851 var value = this[arguments[i]]; 852 if (value !== undefined){ 853 if (result === undefined) result = value; 854 else { 855 if (result.constructor != Array) result = [result]; 856 result.push(value) 857 } 858 } 859 delete this[arguments[i]]; 860 } 861 return result; 862 }, 863 864 toQueryString: function() { 865 return Hash.toQueryString(this); 866 }, 867 868 inspect: function() { 869 return '#<Hash:{' + this.map(function(pair) { 870 return pair.map(Object.inspect).join(': '); 871 }).join(', ') + '}>'; 872 }, 873 874 toJSON: function() { 875 return Hash.toJSON(this); 876 } 717 877 }); 718 878 719 879 function $H(object) { 720 if (object && object.constructor == Hash) return object; 721 return new Hash(object); 880 if (object instanceof Hash) return object; 881 return new Hash(object); 882 }; 883 884 // Safari iterates over shadowed properties 885 if (function() { 886 var i = 0, Test = function(value) { this.key = value }; 887 Test.prototype.key = 'foo'; 888 for (var property in new Test('bar')) i++; 889 return i > 1; 890 }()) Hash.prototype._each = function(iterator) { 891 var cache = []; 892 for (var key in this) { 893 var value = this[key]; 894 if ((value && value == Hash.prototype[key]) || cache.include(key)) continue; 895 cache.push(key); 896 var pair = [key, value]; 897 pair.key = key; 898 pair.value = value; 899 iterator(pair); 900 } 722 901 }; 723 902 ObjectRange = Class.create(); 724 903 Object.extend(ObjectRange.prototype, Enumerable); 725 904 Object.extend(ObjectRange.prototype, { 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 905 initialize: function(start, end, exclusive) { 906 this.start = start; 907 this.end = end; 908 this.exclusive = exclusive; 909 }, 910 911 _each: function(iterator) { 912 var value = this.start; 913 while (this.include(value)) { 914 iterator(value); 915 value = value.succ(); 916 } 917 }, 918 919 include: function(value) { 920 if (value < this.start) 921 return false; 922 if (this.exclusive) 923 return value < this.end; 924 return value <= this.end; 925 } 747 926 }); 748 927 749 928 var $R = function(start, end, exclusive) { 750 929 return new ObjectRange(start, end, exclusive); 751 930 } 752 931 753 932 var Ajax = { 754 755 756 757 758 759 760 761 762 933 getTransport: function() { 934 return Try.these( 935 function() {return new XMLHttpRequest()}, 936 function() {return new ActiveXObject('Msxml2.XMLHTTP')}, 937 function() {return new ActiveXObject('Microsoft.XMLHTTP')} 938 ) || false; 939 }, 940 941 activeRequestCount: 0 763 942 } 764 943 765 944 Ajax.Responders = { 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 945 responders: [], 946 947 _each: function(iterator) { 948 this.responders._each(iterator); 949 }, 950 951 register: function(responder) { 952 if (!this.include(responder)) 953 this.responders.push(responder); 954 }, 955 956 unregister: function(responder) { 957 this.responders = this.responders.without(responder); 958 }, 959 960 dispatch: function(callback, request, transport, json) { 961 this.each(function(responder) { 962 if (typeof responder[callback] == 'function') { 963 try { 964 responder[callback].apply(responder, [request, transport, json]); 965 } catch (e) {} 966 } 967 }); 968 } 790 969 }; 791 970 … … 793 972 794 973 Ajax.Responders.register({ 795 796 797 798 799 800 974 onCreate: function() { 975 Ajax.activeRequestCount++; 976 }, 977 onComplete: function() { 978 Ajax.activeRequestCount--; 979 } 801 980 }); 802 981 803 982 Ajax.Base = function() {}; 804 983 Ajax.Base.prototype = { 805 806 807 808 809 810 811 812 813 814 815 816 817 818 984 setOptions: function(options) { 985 this.options = { 986 method: 'post', 987 asynchronous: true, 988 contentType: 'application/x-www-form-urlencoded', 989 encoding: 'UTF-8', 990 parameters: '' 991 } 992 Object.extend(this.options, options || {}); 993 994 this.options.method = this.options.method.toLowerCase(); 995 if (typeof this.options.parameters == 'string') 996 this.options.parameters = this.options.parameters.toQueryParams(); 997 } 819 998 } 820 999 821 1000 Ajax.Request = Class.create(); 822 1001 Ajax.Request.Events = 823 1002 ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; 824 1003 825 1004 Ajax.Request.prototype = Object.extend(new Ajax.Base(), { 826 _complete: false, 827 828 initialize: function(url, options) { 829 this.transport = Ajax.getTransport(); 830 this.setOptions(options); 831 this.request(url); 832 }, 833 834 request: function(url) { 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; 851 852 try { 853 Ajax.Responders.dispatch('onCreate', this, this.transport); 854 855 this.transport.open(this.method.toUpperCase(), this.url, 856 this.options.asynchronous); 857 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); 936 } 937 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); 946 } catch (e) { 947 this.dispatchException(e); 948 } 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) { 957 try { 958 return this.transport.getResponseHeader(name); 959 } catch (e) { return null } 960 }, 961 962 evalJSON: function() { 963 try { 964 var json = this.getHeader('X-JSON'); 965 return json ? eval('(' + json + ')') : null; 966 } catch (e) { return null } 967 }, 968 969 evalResponse: function() { 970 try { 971 return eval(this.transport.responseText); 972 } catch (e) { 973 this.dispatchException(e); 974 } 975 }, 976 977 dispatchException: function(exception) { 978 (this.options.onException || Prototype.emptyFunction)(this, exception); 979 Ajax.Responders.dispatch('onException', this, exception); 980 } 1005 _complete: false, 1006 1007 initialize: function(url, options) { 1008 this.transport = Ajax.getTransport(); 1009 this.setOptions(options); 1010 this.request(url); 1011 }, 1012 1013 request: function(url) { 1014 this.url = url; 1015 this.method = this.options.method; 1016 var params = Object.clone(this.options.parameters); 1017 1018 if (!['get', 'post'].include(this.method)) { 1019 // simulate other verbs over post 1020 params['_method'] = this.method; 1021 this.method = 'post'; 1022 } 1023 1024 this.parameters = params; 1025 1026 if (params = Hash.toQueryString(params)) { 1027 // when GET, append parameters to URL 1028 if (this.method == 'get') 1029 this.url += (this.url.include('?') ? '&' : '?') + params; 1030 else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) 1031 params += '&_='; 1032 } 1033 1034 try { 1035 if (this.options.onCreate) this.options.onCreate(this.transport); 1036 Ajax.Responders.dispatch('onCreate', this, this.transport); 1037 1038 this.transport.open(this.method.toUpperCase(), this.url, 1039 this.options.asynchronous); 1040 1041 if (this.options.asynchronous) 1042 setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10); 1043 1044 this.transport.onreadystatechange = this.onStateChange.bind(this); 1045 this.setRequestHeaders(); 1046 1047 this.body = this.method == 'post' ? (this.options.postBody || params) : null; 1048 this.transport.send(this.body); 1049 1050 /* Force Firefox to handle ready state 4 for synchronous requests */ 1051 if (!this.options.asynchronous && this.transport.overrideMimeType) 1052 this.onStateChange(); 1053 1054 } 1055 catch (e) { 1056 this.dispatchException(e); 1057 } 1058 }, 1059 1060 onStateChange: function() { 1061 var readyState = this.transport.readyState; 1062 if (readyState > 1 && !((readyState == 4) && this._complete)) 1063 this.respondToReadyState(this.transport.readyState); 1064 }, 1065 1066 setRequestHeaders: function() { 1067 var headers = { 1068 'X-Requested-With': 'XMLHttpRequest', 1069 'X-Prototype-Version': Prototype.Version, 1070 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' 1071 }; 1072 1073 if (this.method == 'post') { 1074 headers['Content-type'] = this.options.contentType + 1075 (this.options.encoding ? '; charset=' + this.options.encoding : ''); 1076 1077 /* Force "Connection: close" for older Mozilla browsers to work 1078 * around a bug where XMLHttpRequest sends an incorrect 1079 * Content-length header. See Mozilla Bugzilla #246651. 1080 */ 1081 if (this.transport.overrideMimeType && 1082 (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) 1083 headers['Connection'] = 'close'; 1084 } 1085 1086 // user-defined headers 1087 if (typeof this.options.requestHeaders == 'object') { 1088 var extras = this.options.requestHeaders; 1089 1090 if (typeof extras.push == 'function') 1091 for (var i = 0, length = extras.length; i < length; i += 2) 1092 headers[extras[i]] = extras[i+1]; 1093 else 1094 $H(extras).each(function(pair) { headers[pair.key] = pair.value }); 1095 } 1096 1097 for (var name in headers) 1098 this.transport.setRequestHeader(name, headers[name]); 1099 }, 1100 1101 success: function() { 1102 return !this.transport.status 1103 || (this.transport.status >= 200 && this.transport.status < 300); 1104 }, 1105 1106 respondToReadyState: function(readyState) { 1107 var state = Ajax.Request.Events[readyState]; 1108 var transport = this.transport, json = this.evalJSON(); 1109 1110 if (state == 'Complete') { 1111 try { 1112 this._complete = true; 1113 (this.options['on' + this.transport.status] 1114 || this.options['on' + (this.success() ? 'Success' : 'Failure')] 1115 || Prototype.emptyFunction)(transport, json); 1116 } catch (e) { 1117 this.dispatchException(e); 1118 } 1119 1120 var contentType = this.getHeader('Content-type'); 1121 if (contentType && contentType.strip(). 1122 match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i)) 1123 this.evalResponse(); 1124 } 1125 1126 try { 1127 (this.options['on' + state] || Prototype.emptyFunction)(transport, json); 1128 Ajax.Responders.dispatch('on' + state, this, transport, json); 1129 } catch (e) { 1130 this.dispatchException(e); 1131 } 1132 1133 if (state == 'Complete') { 1134 // avoid memory leak in MSIE: clean up 1135 this.transport.onreadystatechange = Prototype.emptyFunction; 1136 } 1137 }, 1138 1139 getHeader: function(name) { 1140 try { 1141 return this.transport.getResponseHeader(name); 1142 } catch (e) { return null } 1143 }, 1144 1145 evalJSON: function() { 1146 try { 1147 var json = this.getHeader('X-JSON'); 1148 return json ? json.evalJSON() : null; 1149 } catch (e) { return null } 1150 }, 1151 1152 evalResponse: function() { 1153 try { 1154 return eval((this.transport.responseText || '').unfilterJSON()); 1155 } catch (e) { 1156 this.dispatchException(e); 1157 } 1158 }, 1159 1160 dispatchException: function(exception) { 1161 (this.options.onException || Prototype.emptyFunction)(this, exception); 1162 Ajax.Responders.dispatch('onException', this, exception); 1163 } 981 1164 }); 982 1165 … … 984 1167 985 1168 Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1169 initialize: function(container, url, options) { 1170 this.container = { 1171 success: (container.success || container), 1172 failure: (container.failure || (container.success ? null : container)) 1173 } 1174 1175 this.transport = Ajax.getTransport(); 1176 this.setOptions(options); 1177 1178 var onComplete = this.options.onComplete || Prototype.emptyFunction; 1179 this.options.onComplete = (function(transport, param) { 1180 this.updateContent(); 1181 onComplete(transport, param); 1182 }).bind(this); 1183 1184 this.request(url); 1185 }, 1186 1187 updateContent: function() { 1188 var receiver = this.container[this.success() ? 'success' : 'failure']; 1189 var response = this.transport.responseText; 1190 1191 if (!this.options.evalScripts) response = response.stripScripts(); 1192 1193 if (receiver = $(receiver)) { 1194 if (this.options.insertion) 1195 new this.options.insertion(receiver, response); 1196 else 1197 receiver.update(response); 1198 } 1199 1200 if (this.success()) { 1201 if (this.onComplete) 1202 setTimeout(this.onComplete.bind(this), 10); 1203 } 1204 } 1022 1205 }); 1023 1206 1024 1207 Ajax.PeriodicalUpdater = Class.create(); 1025 1208 Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1209 initialize: function(container, url, options) { 1210 this.setOptions(options); 1211 this.onComplete = this.options.onComplete; 1212 1213 this.frequency = (this.options.frequency || 2); 1214 this.decay = (this.options.decay || 1); 1215 1216 this.updater = {}; 1217 this.container = container; 1218 this.url = url; 1219 1220 this.start(); 1221 }, 1222 1223 start: function() { 1224 this.options.onComplete = this.updateComplete.bind(this); 1225 this.onTimerEvent(); 1226 }, 1227 1228 stop: function() { 1229 this.updater.options.onComplete = undefined; 1230 clearTimeout(this.timer); 1231 (this.onComplete || Prototype.emptyFunction).apply(this, arguments); 1232 }, 1233 1234 updateComplete: function(request) { 1235 if (this.options.decay) { 1236 this.decay = (request.responseText == this.lastText ? 1237 this.decay * this.options.decay : 1); 1238 1239 this.lastText = request.responseText; 1240 } 1241 this.timer = setTimeout(this.onTimerEvent.bind(this), 1242 this.decay * this.frequency * 1000); 1243 }, 1244 1245 onTimerEvent: function() { 1246 this.updater = new Ajax.Updater(this.container, this.url, this.options); 1247 } 1065 1248 }); 1066 1249 function $(element) { 1067 1068 1069 1070 1071 1072 1073 1074 1250 if (arguments.length > 1) { 1251 for (var i = 0, elements = [], length = arguments.length; i < length; i++) 1252 elements.push($(arguments[i])); 1253 return elements; 1254 } 1255 if (typeof element == 'string') 1256 element = document.getElementById(element); 1257 return Element.extend(element); 1075 1258 } 1076 1259 1077 1260 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 1088 document.getElementsByClassName = function(className, parentElement) { 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 } 1100 return elements; 1101 } 1261 document._getElementsByXPath = function(expression, parentElement) { 1262 var results = []; 1263 var query = document.evaluate(expression, $(parentElement) || document, 1264 null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); 1265 for (var i = 0, length = query.snapshotLength; i < length; i++) 1266 results.push(query.snapshotItem(i)); 1267 return results; 1268 }; 1269 1270 document.getElementsByClassName = function(className, parentElement) { 1271 var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]"; 1272 return document._getElementsByXPath(q, parentElement); 1273 } 1274 1275 } else document.getElementsByClassName = function(className, parentElement) { 1276 var children = ($(parentElement) || document.body).getElementsByTagName('*'); 1277 var elements = [], child, pattern = new RegExp("(^|\\s)" + className + "(\\s|$)"); 1278 for (var i = 0, length = children.length; i < length; i++) { 1279 child = children[i]; 1280 var elementClassName = child.className; 1281 if (elementClassName.length == 0) continue; 1282 if (elementClassName == className || elementClassName.match(pattern)) 1283 elements.push(Element.extend(child)); 1284 } 1285 return elements; 1102 1286 }; 1103 1287 1104 1288 /*--------------------------------------------------------------------------*/ 1105 1289 1106 if (!window.Element) 1107 var Element = new Object(); 1290 if (!window.Element) var Element = {}; 1108 1291 1109 1292 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; 1293 var F = Prototype.BrowserFeatures; 1294 if (!element || !element.tagName || element.nodeType == 3 || 1295 element._extended || F.SpecificElementExtensions || element == window) 1296 return element; 1297 1298 var methods = {}, tagName = element.tagName, cache = Element.extend.cache, 1299 T = Element.Methods.ByTag; 1300 1301 // extend methods for all tags (Safari doesn't need this) 1302 if (!F.ElementExtensions) { 1303 Object.extend(methods, Element.Methods), 1304 Object.extend(methods, Element.Methods.Simulated); 1305 } 1306 1307 // extend methods for specific tags 1308 if (T[tagName]) Object.extend(methods, T[tagName]); 1309 1310 for (var property in methods) { 1311 var value = methods[property]; 1312 if (typeof value == 'function' && !(property in element)) 1313 element[property] = cache.findOrStore(value); 1314 } 1315 1316 element._extended = Prototype.emptyFunction; 1317 return element; 1131 1318 }; 1132 1319 1133 1320 Element.extend.cache = { 1134 1135 1136 1137 1138 1321 findOrStore: function(value) { 1322 return this[value] = this[value] || function() { 1323 return value.apply(null, [this].concat($A(arguments))); 1324 } 1325 } 1139 1326 }; 1140 1327 1141 1328 Element.Methods = { 1142 visible: function(element) { 1143 return $(element).style.display != 'none'; 1144 }, 1145 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; 1160 }, 1161 1162 remove: function(element) { 1163 element = $(element); 1164 element.parentNode.removeChild(element); 1165 return element; 1166 }, 1167 1168 update: function(element, html) { 1169 html = typeof html == 'undefined' ? '' : html.toString(); 1170 $(element).innerHTML = html.stripScripts(); 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); 1279 }, 1280 1281 getHeight: function(element) { 1282 return $(element).getDimensions().height; 1283 }, 1284 1285 getWidth: function(element) { 1286 return $(element).getDimensions().width; 1287 }, 1288 1289 classNames: function(element) { 1290 return new Element.ClassNames(element); 1291 }, 1292 1293 hasClassName: function(element, className) { 1294 if (!(element = $(element))) return; 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; 1301 }, 1302 1303 addClassName: function(element, className) { 1304 if (!(element = $(element))) return; 1305 Element.classNames(element).add(className); 1306 return element; 1307 }, 1308 1309 removeClassName: function(element, className) { 1310 if (!(element = $(element))) return; 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(); 1329 }, 1330 1331 // removes whitespace-only text node children 1332 cleanWhitespace: function(element) { 1333 element = $(element); 1334 var node = element.firstChild; 1335 while (node) { 1336 var nextNode = node.nextSibling; 1337 if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) 1338 element.removeChild(node); 1339 node = nextNode; 1340 } 1341 return element; 1342 }, 1343 1344 empty: function(element) { 1345 return $(element).innerHTML.match(/^\s*$/); 1346 }, 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 1355 scrollTo: function(element) { 1356 element = $(element); 1357 var pos = Position.cumulativeOffset(element); 1358 window.scrollTo(pos[0], pos[1]); 1359 return element; 1360 }, 1361 1362 getStyle: function(element, style) { 1363 element = $(element); 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]; 1368 if (!value) { 1369 if (document.defaultView && document.defaultView.getComputedStyle) { 1370 var css = document.defaultView.getComputedStyle(element, null); 1371 value = css ? css[style] : null; 1372 } else if (element.currentStyle) { 1373 value = element.currentStyle[style]; 1374 } 1375 } 1376 1377 if((value == 'auto') && ['width','height'].include(style) && (element.getStyle('display') != 'none')) 1378 value = element['offset'+style.capitalize()] + 'px'; 1379 1380 if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) 1381 if (Element.getStyle(element, 'position') == 'static') value = 'auto'; 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 } 1388 return value == 'auto' ? null : value; 1389 }, 1390 1391 setStyle: function(element, style) { 1392 element = $(element); 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; 1414 }, 1415 1416 getDimensions: function(element) { 1417 element = $(element); 1418 var display = $(element).getStyle('display'); 1419 if (display != 'none' && display != null) // Safari bug 1420 return {width: element.offsetWidth, height: element.offsetHeight}; 1421 1422 // All *Width and *Height properties give 0 on elements with display none, 1423 // so enable the element temporarily 1424 var els = element.style; 1425 var originalVisibility = els.visibility; 1426 var originalPosition = els.position; 1427 var originalDisplay = els.display; 1428 els.visibility = 'hidden'; 1429 els.position = 'absolute'; 1430 els.display = 'block'; 1431 var originalWidth = element.clientWidth; 1432 var originalHeight = element.clientHeight; 1433 els.display = originalDisplay; 1434 els.position = originalPosition; 1435 els.visibility = originalVisibility; 1436 return {width: originalWidth, height: originalHeight}; 1437 }, 1438 1439 makePositioned: function(element) { 1440 element = $(element); 1441 var pos = Element.getStyle(element, 'position'); 1442 if (pos == 'static' || !pos) { 1443 element._madePositioned = true; 1444 element.style.position = 'relative'; 1445 // Opera returns the offset relative to the positioning context, when an 1446 // element is position relative but top and left have not been defined 1447 if (window.opera) { 1448 element.style.top = 0; 1449 element.style.left = 0; 1450 } 1451 } 1452 return element; 1453 }, 1454 1455 undoPositioned: function(element) { 1456 element = $(element); 1457 if (element._madePositioned) { 1458 element._madePositioned = undefined; 1459 element.style.position = 1460 element.style.top = 1461 element.style.left = 1462 element.style.bottom = 1463 element.style.right = ''; 1464 } 1465 return element; 1466 }, 1467 1468 makeClipping: function(element) { 1469 element = $(element); 1470 if (element._overflow) return element; 1471 element._overflow = element.style.overflow || 'auto'; 1472 if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') 1473 element.style.overflow = 'hidden'; 1474 return element; 1475 }, 1476 1477 undoClipping: function(element) { 1478 element = $(element); 1479 if (!element._overflow) return element; 1480 element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; 1481 element._overflow = null; 1482 return element; 1483 } 1329 visible: function(element) { 1330 return $(element).style.display != 'none'; 1331 }, 1332 1333 toggle: function(element) { 1334 element = $(element); 1335 Element[Element.visible(element) ? 'hide' : 'show'](element); 1336 return element; 1337 }, 1338 1339 hide: function(element) { 1340 $(element).style.display = 'none'; 1341 return element; 1342 }, 1343 1344 show: function(element) { 1345 $(element).style.display = ''; 1346 return element; 1347 }, 1348 1349 remove: function(element) { 1350 element = $(element); 1351 element.parentNode.removeChild(element); 1352 return element; 1353 }, 1354 1355 update: function(element, html) { 1356 html = typeof html == 'undefined' ? '' : html.toString(); 1357 $(element).innerHTML = html.stripScripts(); 1358 setTimeout(function() {html.evalScripts()}, 10); 1359 return element; 1360 }, 1361 1362 replace: function(element, html) { 1363 element = $(element); 1364 html = typeof html == 'undefined' ? '' : html.toString(); 1365 if (element.outerHTML) { 1366 element.outerHTML = html.stripScripts(); 1367 } else { 1368 var range = element.ownerDocument.createRange(); 1369 range.selectNodeContents(element); 1370 element.parentNode.replaceChild( 1371 range.createContextualFragment(html.stripScripts()), element); 1372 } 1373 setTimeout(function() {html.evalScripts()}, 10); 1374 return element; 1375 }, 1376 1377 inspect: function(element) { 1378 element = $(element); 1379 var result = '<' + element.tagName.toLowerCase(); 1380 $H({'id': 'id', 'className': 'class'}).each(function(pair) { 1381 var property = pair.first(), attribute = pair.last(); 1382 var value = (element[property] || '').toString(); 1383 if (value) result += ' ' + attribute + '=' + value.inspect(true); 1384 }); 1385 return result + '>'; 1386 }, 1387 1388 recursivelyCollect: function(element, property) { 1389 element = $(element); 1390 var elements = []; 1391 while (element = element[property]) 1392 if (element.nodeType == 1) 1393 elements.push(Element.extend(element)); 1394 return elements; 1395 }, 1396 1397 ancestors: function(element) { 1398 return $(element).recursivelyCollect('parentNode'); 1399 }, 1400 1401 descendants: function(element) { 1402 return $A($(element).getElementsByTagName('*')).each(Element.extend); 1403 }, 1404 1405 firstDescendant: function(element) { 1406 element = $(element).firstChild; 1407 while (element && element.nodeType != 1) element = element.nextSibling; 1408 return $(element); 1409 }, 1410 1411 immediateDescendants: function(element) { 1412 if (!(element = $(element).firstChild)) return []; 1413 while (element && element.nodeType != 1) element = element.nextSibling; 1414 if (element) return [element].concat($(element).nextSiblings()); 1415 return []; 1416 }, 1417 1418 previousSiblings: function(element) { 1419 return $(element).recursivelyCollect('previousSibling'); 1420 }, 1421 1422 nextSiblings: function(element) { 1423 return $(element).recursivelyCollect('nextSibling'); 1424 }, 1425 1426 siblings: function(element) { 1427 element = $(element); 1428 return element.previousSiblings().reverse().concat(element.nextSiblings()); 1429 }, 1430 1431 match: function(element, selector) { 1432 if (typeof selector == 'string') 1433 selector = new Selector(selector); 1434 return selector.match($(element)); 1435 }, 1436 1437 up: function(element, expression, index) { 1438 element = $(element); 1439 if (arguments.length == 1) return $(element.parentNode); 1440 var ancestors = element.ancestors(); 1441 return expression ? Selector.findElement(ancestors, expression, index) : 1442 ancestors[index || 0]; 1443 }, 1444 1445 down: function(element, expression, index) { 1446 element = $(element); 1447 if (arguments.length == 1) return element.firstDescendant(); 1448 var descendants = element.descendants(); 1449 return expression ? Selector.findElement(descendants, expression, index) : 1450 descendants[index || 0]; 1451 }, 1452 1453 previous: function(element, expression, index) { 1454 element = $(element); 1455 if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); 1456 var previousSiblings = element.previousSiblings(); 1457 return expression ? Selector.findElement(previousSiblings, expression, index) : 1458 previousSiblings[index || 0]; 1459 }, 1460 1461 next: function(element, expression, index) { 1462 element = $(element); 1463 if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); 1464 var nextSiblings = element.nextSiblings(); 1465 return expression ? Selector.findElement(nextSiblings, expression, index) : 1466 nextSiblings[index || 0]; 1467 }, 1468 1469 getElementsBySelector: function() { 1470 var args = $A(arguments), element = $(args.shift()); 1471 return Selector.findChildElements(element, args); 1472 }, 1473 1474 getElementsByClassName: function(element, className) { 1475 return document.getElementsByClassName(className, element); 1476 }, 1477 1478 readAttribute: function(element, name) { 1479 element = $(element); 1480 if (Prototype.Browser.IE) { 1481 if (!element.attributes) return null; 1482 var t = Element._attributeTranslations; 1483 if (t.values[name]) return t.values[name](element, name); 1484 if (t.names[name]) name = t.names[name]; 1485 var attribute = element.attributes[name]; 1486 return attribute ? attribute.nodeValue : null; 1487 } 1488 return element.getAttribute(name); 1489 }, 1490 1491 getHeight: function(element) { 1492 return $(element).getDimensions().height; 1493 }, 1494 1495 getWidth: function(element) { 1496 return $(element).getDimensions().width; 1497 }, 1498 1499 classNames: function(element) { 1500 return new Element.ClassNames(element); 1501 }, 1502 1503 hasClassName: function(element, className) { 1504 if (!(element = $(element))) return; 1505 var elementClassName = element.className; 1506 if (elementClassName.length == 0) return false; 1507 if (elementClassName == className || 1508 elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) 1509 return true; 1510 return false; 1511 }, 1512 1513 addClassName: function(element, className) { 1514 if (!(element = $(element))) return; 1515 Element.classNames(element).add(className); 1516 return element; 1517 }, 1518 1519 removeClassName: function(element, className) { 1520 if (!(element = $(element))) return; 1521 Element.classNames(element).remove(className); 1522 return element; 1523 }, 1524 1525 toggleClassName: function(element, className) { 1526 if (!(element = $(element))) return; 1527 Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className); 1528 return element; 1529 }, 1530 1531 observe: function() { 1532 Event.observe.apply(Event, arguments); 1533 return $A(arguments).first(); 1534 }, 1535 1536 stopObserving: function() { 1537 Event.stopObserving.apply(Event, arguments); 1538 return $A(arguments).first(); 1539 }, 1540 1541 // removes whitespace-only text node children 1542 cleanWhitespace: function(element) { 1543 element = $(element); 1544 var node = element.firstChild; 1545 while (node) { 1546 var nextNode = node.nextSibling; 1547 if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) 1548 element.removeChild(node); 1549 node = nextNode; 1550 } 1551 return element; 1552 }, 1553 1554 empty: function(element) { 1555 return $(element).innerHTML.blank(); 1556 }, 1557 1558 descendantOf: function(element, ancestor) { 1559 element = $(element), ancestor = $(ancestor); 1560 while (element = element.parentNode) 1561 if (element == ancestor) return true; 1562 return false; 1563 }, 1564 1565 scrollTo: function(element) { 1566 element = $(element); 1567 var pos = Position.cumulativeOffset(element); 1568 window.scrollTo(pos[0], pos[1]); 1569 return element; 1570 }, 1571 1572 getStyle: function(element, style) { 1573 element = $(element); 1574 style = style == 'float' ? 'cssFloat' : style.camelize(); 1575 var value = element.style[style]; 1576 if (!value) { 1577 var css = document.defaultView.getComputedStyle(element, null); 1578 value = css ? css[style] : null; 1579 } 1580 if (style == 'opacity') return value ? parseFloat(value) : 1.0; 1581 return value == 'auto' ? null : value; 1582 }, 1583 1584 getOpacity: function(element) { 1585 return $(element).getStyle('opacity'); 1586 }, 1587 1588 setStyle: function(element, styles, camelized) { 1589 element = $(element); 1590 var elementStyle = element.style; 1591 1592 for (var property in styles) 1593 if (property == 'opacity') element.setOpacity(styles[property]) 1594 else 1595 elementStyle[(property == 'float' || property == 'cssFloat') ? 1596 (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') : 1597 (camelized ? property : property.camelize())] = styles[property]; 1598 1599 return element; 1600 }, 1601 1602 setOpacity: function(element, value) { 1603 element = $(element); 1604 element.style.opacity = (value == 1 || value === '') ? '' : 1605 (value < 0.00001) ? 0 : value; 1606 return element; 1607 }, 1608 1609 getDimensions: function(element) { 1610 element = $(element); 1611 var display = $(element).getStyle('display'); 1612 if (display != 'none' && display != null) // Safari bug 1613 return {width: element.offsetWidth, height: element.offsetHeight}; 1614 1615 // All *Width and *Height properties give 0 on elements with display none, 1616 // so enable the element temporarily 1617 var els = element.style; 1618 var originalVisibility = els.visibility; 1619 var originalPosition = els.position; 1620 var originalDisplay = els.display; 1621 els.visibility = 'hidden'; 1622 els.position = 'absolute'; 1623 els.display = 'block'; 1624 var originalWidth = element.clientWidth; 1625 var originalHeight = element.clientHeight; 1626 els.display = originalDisplay; 1627 els.position = originalPosition; 1628 els.visibility = originalVisibility; 1629 return {width: originalWidth, height: originalHeight}; 1630 }, 1631 1632 makePositioned: function(element) { 1633 element = $(element); 1634 var pos = Element.getStyle(element, 'position'); 1635 if (pos == 'static' || !pos) { 1636 element._madePositioned = true; 1637 element.style.position = 'relative'; 1638 // Opera returns the offset relative to the positioning context, when an 1639 // element is position relative but top and left have not been defined 1640 if (window.opera) { 1641 element.style.top = 0; 1642 element.style.left = 0; 1643 } 1644 } 1645 return element; 1646 }, 1647 1648 undoPositioned: function(element) { 1649 element = $(element); 1650 if (element._madePositioned) { 1651 element._madePositioned = undefined; 1652 element.style.position = 1653 element.style.top = 1654 element.style.left = 1655 element.style.bottom = 1656 element.style.right = ''; 1657 } 1658 return element; 1659 }, 1660 1661 makeClipping: function(element) { 1662 element = $(element); 1663 if (element._overflow) return element; 1664 element._overflow = element.style.overflow || 'auto'; 1665 if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') 1666 element.style.overflow = 'hidden'; 1667 return element; 1668 }, 1669 1670 undoClipping: function(element) { 1671 element = $(element); 1672 if (!element._overflow) return element; 1673 element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; 1674 element._overflow = null; 1675 return element; 1676 } 1484 1677 }; 1485 1678 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" 1679 Object.extend(Element.Methods, { 1680 childOf: Element.Methods.descendantOf, 1681 childElements: Element.Methods.immediateDescendants 1682 }); 1683 1684 if (Prototype.Browser.Opera) { 1685 Element.Methods._getStyle = Element.Methods.getStyle; 1686 Element.Methods.getStyle = function(element, style) { 1687 switch(style) { 1688 case 'left': 1689 case 'top': 1690 case 'right': 1691 case 'bottom': 1692 if (Element._getStyle(element, 'position') == 'static') return null; 1693 default: return Element._getStyle(element, style); 1694 } 1695 }; 1696 } 1697 else if (Prototype.Browser.IE) { 1698 Element.Methods.getStyle = function(element, style) { 1699 element = $(element); 1700 style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); 1701 var value = element.style[style]; 1702 if (!value && element.currentStyle) value = element.currentStyle[style]; 1703 1704 if (style == 'opacity') { 1705 if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) 1706 if (value[1]) return parseFloat(value[1]) / 100; 1707 return 1.0; 1708 } 1709 1710 if (value == 'auto') { 1711 if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) 1712 return element['offset'+style.capitalize()] + 'px'; 1713 return null; 1714 } 1715 return value; 1716 }; 1717 1718 Element.Methods.setOpacity = function(element, value) { 1719 element = $(element); 1720 var filter = element.getStyle('filter'), style = element.style; 1721 if (value == 1 || value === '') { 1722 style.filter = filter.replace(/alpha\([^\)]*\)/gi,''); 1723 return element; 1724 } else if (value < 0.00001) value = 0; 1725 style.filter = filter.replace(/alpha\([^\)]*\)/gi, '') + 1726 'alpha(opacity=' + (value * 100) + ')'; 1727 return element; 1728 }; 1729 1730 // IE is missing .innerHTML support for TABLE-related elements 1731 Element.Methods.update = function(element, html) { 1732 element = $(element); 1733 html = typeof html == 'undefined' ? '' : html.toString(); 1734 var tagName = element.tagName.toUpperCase(); 1735 if (['THEAD','TBODY','TR','TD'].include(tagName)) { 1736 var div = document.createElement('div'); 1737 switch (tagName) { 1738 case 'THEAD': 1739 case 'TBODY': 1740 div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>'; 1741 depth = 2; 1742 break; 1743 case 'TR': 1744 div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>'; 1745 depth = 3; 1746 break; 1747 case 'TD': 1748 div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>'; 1749 depth = 4; 1750 } 1751 $A(element.childNodes).each(function(node) { element.removeChild(node) }); 1752 depth.times(function() { div = div.firstChild }); 1753 $A(div.childNodes).each(function(node) { element.appendChild(node) }); 1754 } else { 1755 element.innerHTML = html.stripScripts(); 1756 } 1757 setTimeout(function() { html.evalScripts() }, 10); 1758 return element; 1759 } 1760 } 1761 else if (Prototype.Browser.Gecko) { 1762 Element.Methods.setOpacity = function(element, value) { 1763 element = $(element); 1764 element.style.opacity = (value == 1) ? 0.999999 : 1765 (value === '') ? '' : (value < 0.00001) ? 0 : value; 1766 return element; 1767 }; 1768 } 1769 1770 Element._attributeTranslations = { 1771 names: { 1772 colspan: "colSpan", 1773 rowspan: "rowSpan", 1774 valign: "vAlign", 1775 datetime: "dateTime", 1776 accesskey: "accessKey", 1777 tabindex: "tabIndex", 1778 enctype: "encType", 1779 maxlength: "maxLength", 1780 readonly: "readOnly", 1781 longdesc: "longDesc" 1782 }, 1783 values: { 1784 _getAttr: function(element, attribute) { 1785 return element.getAttribute(attribute, 2); 1786 }, 1787 _flag: function(element, attribute) { 1788 return $(element).hasAttribute(attribute) ? attribute : null; 1789 }, 1790 style: function(element) { 1791 return element.style.cssText.toLowerCase(); 1792 }, 1793 title: function(element) { 1794 var node = element.getAttributeNode('title'); 1795 return node.specified ? node.nodeValue : null; 1796 } 1797 } 1501 1798 }; 1502 1799 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 } 1800 (function() { 1801 Object.extend(this, { 1802 href: this._getAttr, 1803 src: this._getAttr, 1804 type: this._getAttr, 1805 disabled: this._flag, 1806 checked: this._flag, 1807 readonly: this._flag, 1808 multiple: this._flag 1809 }); 1810 }).call(Element._attributeTranslations.values); 1811 1812 Element.Methods.Simulated = { 1813 hasAttribute: function(element, attribute) { 1814 var t = Element._attributeTranslations, node; 1815 attribute = t.names[attribute] || attribute; 1816 node = $(element).getAttributeNode(attribute); 1817 return node && node.specified; 1818 } 1520 1819 }; 1521 1820 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 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 } 1821 Element.Methods.ByTag = {}; 1822 1823 Object.extend(Element, Element.Methods); 1824 1825 if (!Prototype.BrowserFeatures.ElementExtensions && 1826 document.createElement('div').__proto__) { 1827 window.HTMLElement = {}; 1828 window.HTMLElement.prototype = document.createElement('div').__proto__; 1829 Prototype.BrowserFeatures.ElementExtensions = true; 1830 } 1831 1832 Element.hasAttribute = function(element, attribute) { 1833 if (element.hasAttribute) return element.hasAttribute(attribute); 1834 return Element.Methods.Simulated.hasAttribute(element, attribute); 1537 1835 }; 1538 1836 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 } 1837 Element.addMethods = function(methods) { 1838 var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; 1839 1840 if (!methods) { 1841 Object.extend(Form, Form.Methods); 1842 Object.extend(Form.Element, Form.Element.Methods); 1843 Object.extend(Element.Methods.ByTag, { 1844 "FORM": Object.clone(Form.Methods), 1845 "INPUT": Object.clone(Form.Element.Methods), 1846 "SELECT": Object.clone(Form.Element.Methods), 1847 "TEXTAREA": Object.clone(Form.Element.Methods) 1848 }); 1849 } 1850 1851 if (arguments.length == 2) { 1852 var tagName = methods; 1853 methods = arguments[1]; 1854 } 1855 1856 if (!tagName) Object.extend(Element.Methods, methods || {}); 1857 else { 1858 if (tagName.constructor == Array) tagName.each(extend); 1859 else extend(tagName); 1860 } 1861 1862 function extend(tagName) { 1863 tagName = tagName.toUpperCase(); 1864 if (!Element.Methods.ByTag[tagName]) 1865 Element.Methods.ByTag[tagName] = {}; 1866 Object.extend(Element.Methods.ByTag[tagName], methods); 1867 } 1868 1869 function copy(methods, destination, onlyIfAbsent) { 1870 onlyIfAbsent = onlyIfAbsent || false; 1871 var cache = Element.extend.cache; 1872 for (var property in methods) { 1873 var value = methods[property]; 1874 if (!onlyIfAbsent || !(property in destination)) 1875 destination[property] = cache.findOrStore(value); 1876 } 1877 } 1878 1879 function findDOMClass(tagName) { 1880 var klass; 1881 var trans = { 1882 "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", 1883 "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", 1884 "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", 1885 "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", 1886 "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": 1887 "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": 1888 "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": 1889 "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": 1890 "FrameSet", "IFRAME": "IFrame" 1891 }; 1892 if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; 1893 if (window[klass]) return window[klass]; 1894 klass = 'HTML' + tagName + 'Element'; 1895 if (window[klass]) return window[klass]; 1896 klass = 'HTML' + tagName.capitalize() + 'Element'; 1897 if (window[klass]) return window[klass]; 1898 1899 window[klass] = {}; 1900 window[klass].prototype = document.createElement(tagName).__proto__; 1901 return window[klass]; 1902 } 1903 1904 if (F.ElementExtensions) { 1905 copy(Element.Methods, HTMLElement.prototype); 1906 copy(Element.Methods.Simulated, HTMLElement.prototype, true); 1907 } 1908 1909 if (F.SpecificElementExtensions) { 1910 for (var tag in Element.Methods.ByTag) { 1911 var klass = findDOMClass(tag); 1912 if (typeof klass == "undefined") continue; 1913 copy(T[tag], klass.prototype); 1914 } 1915 } 1916 1917 Object.extend(Element, Element.Methods); 1918 delete Element.ByTag; 1574 1919 }; 1575 1920 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 } 1611 1612 var Toggle = new Object(); 1613 Toggle.display = Element.toggle; 1921 var Toggle = { display: Element.toggle }; 1614 1922 1615 1923 /*--------------------------------------------------------------------------*/ 1616 1924 1617 1925 Abstract.Insertion = function(adjacency) { 1618 1926 this.adjacency = adjacency; 1619 1927 } 1620 1928 1621 1929 Abstract.Insertion.prototype = { 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1930 initialize: function(element, content) { 1931 this.element = $(element); 1932 this.content = content.stripScripts(); 1933 1934 if (this.adjacency && this.element.insertAdjacentHTML) { 1935 try { 1936 this.element.insertAdjacentHTML(this.adjacency, this.content); 1937 } catch (e) { 1938 var tagName = this.element.tagName.toUpperCase(); 1939 if (['TBODY', 'TR'].include(tagName)) { 1940 this.insertContent(this.contentFromAnonymousTable()); 1941 } else { 1942 throw e; 1943 } 1944 } 1945 } else { 1946 this.range = this.element.ownerDocument.createRange(); 1947 if (this.initializeRange) this.initializeRange(); 1948 this.insertContent([this.range.createContextualFragment(this.content)]); 1949 } 1950 1951 setTimeout(function() {content.evalScripts()}, 10); 1952 }, 1953 1954 contentFromAnonymousTable: function() { 1955 var div = document.createElement('div'); 1956 div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>'; 1957 return $A(div.childNodes[0].childNodes[0].childNodes); 1958 } 1651 1959 } 1652 1960 … … 1655 1963 Insertion.Before = Class.create(); 1656 1964 Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { 1657 1658 1659 1660 1661 1662 1663 1664 1665 1965 initializeRange: function() { 1966 this.range.setStartBefore(this.element); 1967 }, 1968 1969 insertContent: function(fragments) { 1970 fragments.each((function(fragment) { 1971 this.element.parentNode.insertBefore(fragment, this.element); 1972 }).bind(this)); 1973 } 1666 1974 }); 1667 1975 1668 1976 Insertion.Top = Class.create(); 1669 1977 Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1978 initializeRange: function() { 1979 this.range.selectNodeContents(this.element); 1980 this.range.collapse(true); 1981 }, 1982 1983 insertContent: function(fragments) { 1984 fragments.reverse(false).each((function(fragment) { 1985 this.element.insertBefore(fragment, this.element.firstChild); 1986 }).bind(this)); 1987 } 1680 1988 }); 1681 1989 1682 1990 Insertion.Bottom = Class.create(); 1683 1991 Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1992 initializeRange: function() { 1993 this.range.selectNodeContents(this.element); 1994 this.range.collapse(this.element); 1995 }, 1996 1997 insertContent: function(fragments) { 1998 fragments.each((function(fragment) { 1999 this.element.appendChild(fragment); 2000 }).bind(this)); 2001 } 1694 2002 }); 1695 2003 1696 2004 Insertion.After = Class.create(); 1697 2005 Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 2006 initializeRange: function() { 2007 this.range.setStartAfter(this.element); 2008 }, 2009 2010 insertContent: function(fragments) { 2011 fragments.each((function(fragment) { 2012 this.element.parentNode.insertBefore(fragment, 2013 this.element.nextSibling); 2014 }).bind(this)); 2015 } 1708 2016 }); 1709 2017 … … 1712 2020 Element.ClassNames = Class.create(); 1713 2021 Element.ClassNames.prototype = { 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 2022 initialize: function(element) { 2023 this.element = $(element); 2024 }, 2025 2026 _each: function(iterator) { 2027 this.element.className.split(/\s+/).select(function(name) { 2028 return name.length > 0; 2029 })._each(iterator); 2030 }, 2031 2032 set: function(className) { 2033 this.element.className = className; 2034 }, 2035 2036 add: function(classNameToAdd) { 2037 if (this.include(classNameToAdd)) return; 2038 this.set($A(this).concat(classNameToAdd).join(' ')); 2039 }, 2040 2041 remove: function(classNameToRemove) { 2042 if (!this.include(classNameToRemove)) return; 2043 this.set($A(this).without(classNameToRemove).join(' ')); 2044 }, 2045 2046 toString: function() { 2047 return $A(this).join(' '); 2048 } 1741 2049 }; 1742 2050 1743 2051 Object.extend(Element.ClassNames.prototype, Enumerable); 2052 /* Portions of the Selector class are derived from Jack Slocum’s DomQuery, 2053 * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style 2054 * license. Please see http://www.yui-ext.com/ for more information. */ 2055 1744 2056 var Selector = Class.create(); 2057 1745 2058 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 } 2059 initialize: function(expression) { 2060 this.expression = expression.strip(); 2061 this.compileMatcher(); 2062 }, 2063 2064 compileMatcher: function() { 2065 // Selectors with namespaced attributes can't use the XPath version 2066 if (Prototype.BrowserFeatures.XPath && !(/\[[\w-]*?:/).test(this.expression)) 2067 return this.compileXPathMatcher(); 2068 2069 var e = this.expression, ps = Selector.patterns, h = Selector.handlers, 2070 c = Selector.criteria, le, p, m; 2071 2072 if (Selector._cache[e]) { 2073 this.matcher = Selector._cache[e]; return; 2074 } 2075 this.matcher = ["this.matcher = function(root) {", 2076 "var r = root, h = Selector.handlers, c = false, n;"]; 2077 2078 while (e && le != e && (/\S/).test(e)) { 2079 le = e; 2080 for (var i in ps) { 2081 p = ps[i]; 2082 if (m = e.match(p)) { 2083 this.matcher.push(typeof c[i] == 'function' ? c[i](m) : 2084 new Template(c[i]).evaluate(m)); 2085 e = e.replace(m[0], ''); 2086 break; 2087 } 2088 } 2089 } 2090 2091 this.matcher.push("return h.unique(n);\n}"); 2092 eval(this.matcher.join('\n')); 2093 Selector._cache[this.expression] = this.matcher; 2094 }, 2095 2096 compileXPathMatcher: function() { 2097 var e = this.expression, ps = Selector.patterns, 2098 x = Selector.xpath, le, m; 2099 2100 if (Selector._cache[e]) { 2101 this.xpath = Selector._cache[e]; return; 2102 } 2103 2104 this.matcher = ['.//*']; 2105 while (e && le != e && (/\S/).test(e)) { 2106 le = e; 2107 for (var i in ps) { 2108 if (m = e.match(ps[i])) { 2109 this.matcher.push(typeof x[i] == 'function' ? x[i](m) : 2110 new Template(x[i]).evaluate(m)); 2111 e = e.replace(m[0], ''); 2112 break; 2113 } 2114 } 2115 } 2116 2117 this.xpath = this.matcher.join(''); 2118 Selector._cache[this.expression] = this.xpath; 2119 }, 2120 2121 findElements: function(root) { 2122 root = root || document; 2123 if (this.xpath) return document._getElementsByXPath(this.xpath, root); 2124 return this.matcher(root); 2125 }, 2126 2127 match: function(element) { 2128 return this.findElements(document).include(element); 2129 }, 2130 2131 toString: function() { 2132 return this.expression; 2133 }, 2134 2135 inspect: function() { 2136 return "#<Selector:" + this.expression.inspect() + ">"; 2137 } 2138 }; 1846 2139 1847 2140 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 } 2141 _cache: {}, 2142 2143 xpath: { 2144 descendant: "//*", 2145 child: "/*", 2146 adjacent: "/following-sibling::*[1]", 2147 laterSibling: '/following-sibling::*', 2148 tagName: function(m) { 2149 if (m[1] == '*') return ''; 2150 return "[local-name()='" + m[1].toLowerCase() + 2151 "' or local-name()='" + m[1].toUpperCase() + "']"; 2152 }, 2153 className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", 2154 id: "[@id='#{1}']", 2155 attrPresence: "[@#{1}]", 2156 attr: function(m) { 2157 m[3] = m[5] || m[6]; 2158 return new Template(Selector.xpath.operators[m[2]]).evaluate(m); 2159 }, 2160 pseudo: function(m) { 2161 var h = Selector.xpath.pseudos[m[1]]; 2162 if (!h) return ''; 2163 if (typeof h === 'function') return h(m); 2164 return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); 2165 }, 2166 operators: { 2167 '=': "[@#{1}='#{3}']", 2168 '!=': "[@#{1}!='#{3}']", 2169 '^=': "[starts-with(@#{1}, '#{3}')]", 2170 '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", 2171 '*=': "[contains(@#{1}, '#{3}')]", 2172 '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", 2173 '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" 2174 }, 2175 pseudos: { 2176 'first-child': '[not(preceding-sibling::*)]', 2177 'last-child': '[not(following-sibling::*)]', 2178 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', 2179 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]", 2180 'checked': "[@checked]", 2181 'disabled': "[@disabled]", 2182 'enabled': "[not(@disabled)]", 2183 'not': function(m) { 2184 var e = m[6], p = Selector.patterns, 2185 x = Selector.xpath, le, m, v; 2186 2187 var exclusion = []; 2188 while (e && le != e && (/\S/).test(e)) { 2189 le = e; 2190 for (var i in p) { 2191 if (m = e.match(p[i])) { 2192 v = typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m); 2193 exclusion.push("(" + v.substring(1, v.length - 1) + ")"); 2194 e = e.replace(m[0], ''); 2195 break; 2196 } 2197 } 2198 } 2199 return "[not(" + exclusion.join(" and ") + ")]"; 2200 }, 2201 'nth-child': function(m) { 2202 return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); 2203 }, 2204 'nth-last-child': function(m) { 2205 return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m); 2206 }, 2207 'nth-of-type': function(m) { 2208 return Selector.xpath.pseudos.nth("position() ", m); 2209 }, 2210 'nth-last-of-type': function(m) { 2211 return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m); 2212 }, 2213 'first-of-type': function(m) { 2214 m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); 2215 }, 2216 'last-of-type': function(m) { 2217 m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); 2218 }, 2219 'only-of-type': function(m) { 2220 var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m); 2221 }, 2222 nth: function(fragment, m) { 2223 var mm, formula = m[6], predicate; 2224 if (formula == 'even') formula = '2n+0'; 2225 if (formula == 'odd') formula = '2n+1'; 2226 if (mm = formula.match(/^(\d+)$/)) // digit only 2227 return '[' + fragment + "= " + mm[1] + ']'; 2228 if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b 2229 if (mm[1] == "-") mm[1] = -1; 2230 var a = mm[1] ? Number(mm[1]) : 1; 2231 var b = mm[2] ? Number(mm[2]) : 0; 2232 predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " + 2233 "((#{fragment} - #{b}) div #{a} >= 0)]"; 2234 return new Template(predicate).evaluate({ 2235 fragment: fragment, a: a, b: b }); 2236 } 2237 } 2238 } 2239 }, 2240 2241 criteria: { 2242 tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', 2243 className: 'n = h.className(n, r, "#{1}", c); c = false;', 2244 id: 'n = h.id(n, r, "#{1}", c); c = false;', 2245 attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;', 2246 attr: function(m) { 2247 m[3] = (m[5] || m[6]); 2248 return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m); 2249 }, 2250 pseudo: function(m) { 2251 if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); 2252 return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); 2253 }, 2254 descendant: 'c = "descendant";', 2255 child: 'c = "child";', 2256 adjacent: 'c = "adjacent";', 2257 laterSibling: 'c = "laterSibling";' 2258 }, 2259 2260 patterns: { 2261 // combinators must be listed first 2262 // (and descendant needs to be last combinator) 2263 laterSibling: /^\s*~\s*/, 2264 child: /^\s*>\s*/, 2265 adjacent: /^\s*\+\s*/, 2266 descendant: /^\s/, 2267 2268 // selectors follow 2269 tagName: /^\s*(\*|[\w\-]+)(\b|$)?/, 2270 id: /^#([\w\-\*]+)(\b|$)/, 2271 className: /^\.([\w\-\*]+)(\b|$)/, 2272 pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s|(?=:))/, 2273 attrPresence: /^\[([\w]+)\]/, 2274 attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/ 2275 }, 2276 2277 handlers: { 2278 // UTILITY FUNCTIONS 2279 // joins two collections 2280 concat: function(a, b) { 2281 for (var i = 0, node; node = b[i]; i++) 2282 a.push(node); 2283 return a; 2284 }, 2285 2286 // marks an array of nodes for counting 2287 mark: function(nodes) { 2288 for (var i = 0, node; node = nodes[i]; i++) 2289 node._counted = true; 2290 return nodes; 2291 }, 2292 2293 unmark: function(nodes) { 2294 for (var i = 0, node; node = nodes[i]; i++) 2295 node._counted = undefined; 2296 return nodes; 2297 }, 2298 2299 // mark each child node with its position (for nth calls) 2300 // "ofType" flag indicates whether we're indexing for nth-of-type 2301 // rather than nth-child 2302 index: function(parentNode, reverse, ofType) { 2303 parentNode._counted = true; 2304 if (reverse) { 2305 for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { 2306 node = nodes[i]; 2307 if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++; 2308 } 2309 } else { 2310 for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) 2311 if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++; 2312 } 2313 }, 2314 2315 // filters out duplicates and extends all nodes 2316 unique: function(nodes) { 2317 if (nodes.length == 0) return nodes; 2318 var results = [], n; 2319 for (var i = 0, l = nodes.length; i < l; i++) 2320 if (!(n = nodes[i])._counted) { 2321 n._counted = true; 2322 results.push(Element.extend(n)); 2323 } 2324 return Selector.handlers.unmark(results); 2325 }, 2326 2327 // COMBINATOR FUNCTIONS 2328 descendant: function(nodes) { 2329 var h = Selector.handlers; 2330 for (var i = 0, results = [], node; node = nodes[i]; i++) 2331 h.concat(results, node.getElementsByTagName('*')); 2332 return results; 2333 }, 2334 2335 child: function(nodes) { 2336 var h = Selector.handlers; 2337 for (var i = 0, results = [], node; node = nodes[i]; i++) { 2338 for (var j = 0, children = [], child; child = node.childNodes[j]; j++) 2339 if (child.nodeType == 1 && child.tagName != '!') results.push(child); 2340 } 2341 return results; 2342 }, 2343 2344 adjacent: function(nodes) { 2345 for (var i = 0, results = [], node; node = nodes[i]; i++) { 2346 var next = this.nextElementSibling(node); 2347 if (next) results.push(next); 2348 } 2349 return results; 2350 }, 2351 2352 laterSibling: function(nodes) { 2353 var h = Selector.handlers; 2354 for (var i = 0, results = [], node; node = nodes[i]; i++) 2355 h.concat(results, Element.nextSiblings(node)); 2356 return results; 2357 }, 2358 2359 nextElementSibling: function(node) { 2360 while (node = node.nextSibling) 2361 if (node.nodeType == 1) return node; 2362 return null; 2363 }, 2364 2365 previousElementSibling: function(node) { 2366 while (node = node.previousSibling) 2367 if (node.nodeType == 1) return node; 2368 return null; 2369 }, 2370 2371 // TOKEN FUNCTIONS 2372 tagName: function(nodes, root, tagName, combinator) { 2373 tagName = tagName.toUpperCase(); 2374 var results = [], h = Selector.handlers; 2375 if (nodes) { 2376 if (combinator) { 2377 // fastlane for ordinary descendant combinators 2378 if (combinator == "descendant") { 2379 for (var i = 0, node; node = nodes[i]; i++) 2380 h.concat(results, node.getElementsByTagName(tagName)); 2381 return results; 2382 } else nodes = this[combinator](nodes); 2383 if (tagName == "*") return nodes; 2384 } 2385 for (var i = 0, node; node = nodes[i]; i++) 2386 if (node.tagName.toUpperCase() == tagName) results.push(node); 2387 return results; 2388 } else return root.getElementsByTagName(tagName); 2389 }, 2390 2391 id: function(nodes, root, id, combinator) { 2392 var targetNode = $(id), h = Selector.handlers; 2393 if (!nodes && root == document) return targetNode ? [targetNode] : []; 2394 if (nodes) { 2395 if (combinator) { 2396 if (combinator == 'child') { 2397 for (var i = 0, node; node = nodes[i]; i++) 2398 if (targetNode.parentNode == node) return [targetNode]; 2399 } else if (combinator == 'descendant') { 2400 for (var i = 0, node; node = nodes[i]; i++) 2401 if (Element.descendantOf(targetNode, node)) return [targetNode]; 2402 } else if (combinator == 'adjacent') { 2403 for (var i = 0, node; node = nodes[i]; i++) 2404 if (Selector.handlers.previousElementSibling(targetNode) == node) 2405 return [targetNode]; 2406 } else nodes = h[combinator](nodes); 2407 } 2408 for (var i = 0, node; node = nodes[i]; i++) 2409 if (node == targetNode) return [targetNode]; 2410 return []; 2411 } 2412 return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; 2413 }, 2414 2415 className: function(nodes, root, className, combinator) { 2416 if (nodes && combinator) nodes = this[combinator](nodes); 2417 return Selector.handlers.byClassName(nodes, root, className); 2418 }, 2419 2420 byClassName: function(nodes, root, className) { 2421 if (!nodes) nodes = Selector.handlers.descendant([root]); 2422 var needle = ' ' + className + ' '; 2423 for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { 2424 nodeClassName = node.className; 2425 if (nodeClassName.length == 0) continue; 2426 if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) 2427 results.push(node); 2428 } 2429 return results; 2430 }, 2431 2432 attrPresence: function(nodes, root, attr) { 2433 var results = []; 2434 for (var i = 0, node; node = nodes[i]; i++) 2435 if (Element.hasAttribute(node, attr)) results.push(node); 2436 return results; 2437 }, 2438 2439 attr: function(nodes, root, attr, value, operator) { 2440 if (!nodes) nodes = root.getElementsByTagName("*"); 2441 var handler = Selector.operators[operator], results = []; 2442 for (var i = 0, node; node = nodes[i]; i++) { 2443 var nodeValue = Element.readAttribute(node, attr); 2444 if (nodeValue === null) continue; 2445 if (handler(nodeValue, value)) results.push(node); 2446 } 2447 return results; 2448 }, 2449 2450 pseudo: function(nodes, name, value, root, combinator) { 2451 if (nodes && combinator) nodes = this[combinator](nodes); 2452 if (!nodes) nodes = root.getElementsByTagName("*"); 2453 return Selector.pseudos[name](nodes, value, root); 2454 } 2455 }, 2456 2457 pseudos: { 2458 'first-child': function(nodes, value, root) { 2459 for (var i = 0, results = [], node; node = nodes[i]; i++) { 2460 if (Selector.handlers.previousElementSibling(node)) continue; 2461 results.push(node); 2462 } 2463 return results; 2464 }, 2465 'last-child': function(nodes, value, root) { 2466 for (var i = 0, results = [], node; node = nodes[i]; i++) { 2467 if (Selector.handlers.nextElementSibling(node)) continue; 2468 results.push(node); 2469 } 2470 return results; 2471 }, 2472 'only-child': function(nodes, value, root) { 2473 var h = Selector.handlers; 2474 for (var i = 0, results = [], node; node = nodes[i]; i++) 2475 if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) 2476 results.push(node); 2477 return results; 2478 }, 2479 'nth-child': function(nodes, formula, root) { 2480 return Selector.pseudos.nth(nodes, formula, root); 2481 }, 2482 'nth-last-child': function(nodes, formula, root) { 2483 return Selector.pseudos.nth(nodes, formula, root, true); 2484 }, 2485 'nth-of-type': function(nodes, formula, root) { 2486 return Selector.pseudos.nth(nodes, formula, root, false, true); 2487 }, 2488 'nth-last-of-type': function(nodes, formula, root) { 2489 return Selector.pseudos.nth(nodes, formula, root, true, true); 2490 }, 2491 'first-of-type': function(nodes, formula, root) { 2492 return Selector.pseudos.nth(nodes, "1", root, false, true); 2493 }, 2494 'last-of-type': function(nodes, formula, root) { 2495 return Selector.pseudos.nth(nodes, "1", root, true, true); 2496 }, 2497 'only-of-type': function(nodes, formula, root) { 2498 var p = Selector.pseudos; 2499 return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); 2500 }, 2501 2502 // handles the an+b logic 2503 getIndices: function(a, b, total) { 2504 if (a == 0) return b > 0 ? [b] : []; 2505 return $R(1, total).inject([], function(memo, i) { 2506 if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); 2507 return memo; 2508 }); 2509 }, 2510 2511 // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type 2512 nth: function(nodes, formula, root, reverse, ofType) { 2513 if (nodes.length == 0) return []; 2514 if (formula == 'even') formula = '2n+0'; 2515 if (formula == 'odd') formula = '2n+1'; 2516 var h = Selector.handlers, results = [], indexed = [], m; 2517 h.mark(nodes); 2518 for (var i = 0, node; node = nodes[i]; i++) { 2519 if (!node.parentNode._counted) { 2520 h.index(node.parentNode, reverse, ofType); 2521 indexed.push(node.parentNode); 2522 } 2523 } 2524 if (formula.match(/^\d+$/)) { // just a number 2525 formula = Number(formula); 2526 for (var i = 0, node; node = nodes[i]; i++) 2527 if (node.nodeIndex == formula) results.push(node); 2528 } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b 2529 if (m[1] == "-") m[1] = -1; 2530 var a = m[1] ? Number(m[1]) : 1; 2531 var b = m[2] ? Number(m[2]) : 0; 2532 var indices = Selector.pseudos.getIndices(a, b, nodes.length); 2533 for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { 2534 for (var j = 0; j < l; j++) 2535 if (node.nodeIndex == indices[j]) results.push(node); 2536 } 2537 } 2538 h.unmark(nodes); 2539 h.unmark(indexed); 2540 return results; 2541 }, 2542 2543 'empty': function(nodes, value, root) { 2544 for (var i = 0, results = [], node; node = nodes[i]; i++) { 2545 // IE treats comments as element nodes 2546 if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue; 2547 results.push(node); 2548 } 2549 return results; 2550 }, 2551 2552 'not': function(nodes, selector, root) { 2553 var h = Selector.handlers, selectorType, m; 2554 var exclusions = new Selector(selector).findElements(root); 2555 h.mark(exclusions); 2556 for (var i = 0, results = [], node; node = nodes[i]; i++) 2557 if (!node._counted) results.push(node); 2558 h.unmark(exclusions); 2559 return results; 2560 }, 2561 2562 'enabled': function(nodes, value, root) { 2563 for (var i = 0, results = [], node; node = nodes[i]; i++) 2564 if (!node.disabled) results.push(node); 2565 return results; 2566 }, 2567 2568 'disabled': function(nodes, value, root) { 2569 for (var i = 0, results = [], node; node = nodes[i]; i++) 2570 if (node.disabled) results.push(node); 2571 return results; 2572 }, 2573 2574 'checked': function(nodes, value, root) { 2575 for (var i = 0, results = [], node; node = nodes[i]; i++) 2576 if (node.checked) results.push(node); 2577 return results; 2578 } 2579 }, 2580 2581 operators: { 2582 '=': function(nv, v) { return nv == v; }, 2583 '!=': function(nv, v) { return nv != v; }, 2584 '^=': function(nv, v) { return nv.startsWith(v); }, 2585 '$=': function(nv, v) { return nv.endsWith(v); }, 2586 '*=': function(nv, v) { return nv.include(v); }, 2587 '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, 2588 '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); } 2589 }, 2590 2591 matchElements: function(elements, expression) { 2592 var matches = new Selector(expression).findElements(), h = Selector.handlers; 2593 h.mark(matches); 2594 for (var i = 0, results = [], element; element = elements[i]; i++) 2595 if (element._counted) results.push(element); 2596 h.unmark(matches); 2597 return results; 2598 }, 2599 2600 findElement: function(elements, expression, index) { 2601 if (typeof expression == 'number') { 2602 index = expression; expression = false; 2603 } 2604 return Selector.matchElements(elements, expression || '*')[index || 0]; 2605 }, 2606 2607 findChildElements: function(element, expressions) { 2608 var exprs = expressions.join(','), expressions = []; 2609 exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { 2610 expressions.push(m[1].strip()); 2611 }); 2612 var results = [], h = Selector.handlers; 2613 for (var i = 0, l = expressions.length, selector; i < l; i++) { 2614 selector = new Selector(expressions[i].strip()); 2615 h.concat(results, selector.findElements(element)); 2616 } 2617 return (l > 1) ? h.unique(results) : results; 2618 } 1868 2619 }); 1869 2620 1870 2621 function $$() { 1871 2622 return Selector.findChildElements(document, $A(arguments)); 1872 2623 } 1873 2624 var Form = { 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 if (value != undefined) {1884 if (result[key]) {1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 2625 reset: function(form) { 2626 $(form).reset(); 2627 return form; 2628 }, 2629 2630 serializeElements: function(elements, getHash) { 2631 var data = elements.inject({}, function(result, element) { 2632 if (!element.disabled && element.name) { 2633 var key = element.name, value = $(element).getValue(); 2634 if (value != null) { 2635 if (key in result) { 2636 if (result[key].constructor != Array) result[key] = [result[key]]; 2637 result[key].push(value); 2638 } 2639 else result[key] = value; 2640 } 2641 } 2642 return result; 2643 }); 2644 2645 return getHash ? data : Hash.toQueryString(data); 2646 } 1896 2647 }; 1897 2648 1898 2649 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); 2650 serialize: function(form, getHash) { 2651 return Form.serializeElements(Form.getElements(form), getHash); 2652 }, 2653 2654 getElements: function(form) { 2655 return $A($(form).getElementsByTagName('*')).inject([], 2656 function(elements, child) { 2657 if (Form.Element.Serializers[child.tagName.toLowerCase()]) 2658 elements.push(Element.extend(child)); 2659 return elements; 2660 } 2661 ); 2662 }, 2663 2664 getInputs: function(form, typeName, name) { 2665 form = $(form); 2666 var inputs = form.getElementsByTagName('input'); 2667 2668 if (!typeName && !name) return $A(inputs).map(Element.extend); 2669 2670 for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { 2671 var input = inputs[i]; 2672 if ((typeName && input.type != typeName) || (name && input.name != name)) 2673 continue; 2674 matchingInputs.push(Element.extend(input)); 2675 } 2676 2677 return matchingInputs; 2678 }, 2679 2680 disable: function(form) { 2681 form = $(form); 2682 Form.getElements(form).invoke('disable'); 2683 return form; 2684 }, 2685 2686 enable: function(form) { 2687 form = $(form); 2688 Form.getElements(form).invoke('enable'); 2689 return form; 2690 }, 2691 2692 findFirstElement: function(form) { 2693 return $(form).getElements().find(function(element) { 2694 return element.type != 'hidden' && !element.disabled && 2695 ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); 2696 }); 2697 }, 2698 2699 focusFirstElement: function(form) { 2700 form = $(form); 2701 form.findFirstElement().activate(); 2702 return form; 2703 }, 2704 2705 request: function(form, options) { 2706 form = $(form), options = Object.clone(options || {}); 2707 2708 var params = options.parameters; 2709 options.parameters = form.serialize(true); 2710 2711 if (params) { 2712 if (typeof params == 'string') params = params.toQueryParams(); 2713 Object.extend(options.parameters, params); 2714 } 2715 2716 if (form.hasAttribute('method') && !options.method) 2717 options.method = form.method; 2718 2719 return new Ajax.Request(form.readAttribute('action'), options); 2720 } 2721 } 1961 2722 1962 2723 /*--------------------------------------------------------------------------*/ 1963 2724 1964 2725 Form.Element = { 1965 1966 1967 1968 1969 1970 1971 1972 1973 2726 focus: function(element) { 2727 $(element).focus(); 2728 return element; 2729 }, 2730 2731 select: function(element) { 2732 $(element).select(); 2733 return element; 2734 } 1974 2735 } 1975 2736 1976 2737 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 != ''; 2003 }, 2004 2005 activate: function(element) { 2006 element = $(element); 2007 element.focus(); 2008 if (element.select && ( element.tagName.toLowerCase() != 'input' || 2009 !['button', 'reset', 'submit'].include(element.type) ) ) 2010 element.select(); 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); 2738 serialize: function(element) { 2739 element = $(element); 2740 if (!element.disabled && element.name) { 2741 var value = element.getValue(); 2742 if (value != undefined) { 2743 var pair = {}; 2744 pair[element.name] = value; 2745 return Hash.toQueryString(pair); 2746 } 2747 } 2748 return ''; 2749 }, 2750 2751 getValue: function(element) { 2752 element = $(element); 2753 var method = element.tagName.toLowerCase(); 2754 return Form.Element.Serializers[method](element); 2755 }, 2756 2757 clear: function(element) { 2758 $(element).value = ''; 2759 return element; 2760 }, 2761 2762 present: function(element) { 2763 return $(element).value != ''; 2764 }, 2765 2766 activate: function(element) { 2767 element = $(element); 2768 try { 2769 element.focus(); 2770 if (element.select && (element.tagName.toLowerCase() != 'input' || 2771 !['button', 'reset', 'submit'].include(element.type))) 2772 element.select(); 2773 } catch (e) {} 2774 return element; 2775 }, 2776 2777 disable: function(element) { 2778 element = $(element); 2779 element.blur(); 2780 element.disabled = true; 2781 return element; 2782 }, 2783 2784 enable: function(element) { 2785 element = $(element); 2786 element.disabled = false; 2787 return element; 2788 } 2789 } 2790 2791 /*--------------------------------------------------------------------------*/ 2792 2029 2793 var Field = Form.Element; 2030 var $F = Form.Element. getValue;2794 var $F = Form.Element.Methods.getValue; 2031 2795 2032 2796 /*--------------------------------------------------------------------------*/ 2033 2797 2034 2798 Form.Element.Serializers = { 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2799 input: function(element) { 2800 switch (element.type.toLowerCase()) { 2801 case 'checkbox': 2802 case 'radio': 2803 return Form.Element.Serializers.inputSelector(element); 2804 default: 2805 return Form.Element.Serializers.textarea(element); 2806 } 2807 }, 2808 2809 inputSelector: function(element) { 2810 return element.checked ? element.value : null; 2811 }, 2812 2813 textarea: function(element) { 2814 return element.value; 2815 }, 2816 2817 select: function(element) { 2818 return this[element.type == 'select-one' ? 2819 'selectOne' : 'selectMany'](element); 2820 }, 2821 2822 selectOne: function(element) { 2823 var index = element.selectedIndex; 2824 return index >= 0 ? this.optionValue(element.options[index]) : null; 2825 }, 2826 2827 selectMany: function(element) { 2828 var values, length = element.length; 2829 if (!length) return null; 2830 2831 for (var i = 0, values = []; i < length; i++) { 2832 var opt = element.options[i]; 2833 if (opt.selected) values.push(this.optionValue(opt)); 2834 } 2835 return values; 2836 }, 2837 2838 optionValue: function(opt) { 2839 // extend element because hasAttribute may not be native 2840 return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; 2841 } 2078 2842 } 2079 2843 … … 2082 2846 Abstract.TimedObserver = function() {} 2083 2847 Abstract.TimedObserver.prototype = { 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2848 initialize: function(element, frequency, callback) { 2849 this.frequency = frequency; 2850 this.element = $(element); 2851 this.callback = callback; 2852 2853 this.lastValue = this.getValue(); 2854 this.registerCallback(); 2855 }, 2856 2857 registerCallback: function() { 2858 setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); 2859 }, 2860 2861 onTimerEvent: function() { 2862 var value = this.getValue(); 2863 var changed = ('string' == typeof this.lastValue && 'string' == typeof value 2864 ? this.lastValue != value : String(this.lastValue) != String(value)); 2865 if (changed) { 2866 this.callback(this.element, value); 2867 this.lastValue = value; 2868 } 2869 } 2106 2870 } 2107 2871 2108 2872 Form.Element.Observer = Class.create(); 2109 2873 Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { 2110 2111 2112 2874 getValue: function() { 2875 return Form.Element.getValue(this.element); 2876 } 2113 2877 }); 2114 2878 2115 2879 Form.Observer = Class.create(); 2116 2880 Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { 2117 2118 2119 2881 getValue: function() { 2882 return Form.serialize(this.element); 2883 } 2120 2884 }); 2121 2885 … … 2124 2888 Abstract.EventObserver = function() {} 2125 2889 Abstract.EventObserver.prototype = { 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2890 initialize: function(element, callback) { 2891 this.element = $(element); 2892 this.callback = callback; 2893 2894 this.lastValue = this.getValue(); 2895 if (this.element.tagName.toLowerCase() == 'form') 2896 this.registerFormCallbacks(); 2897 else 2898 this.registerCallback(this.element); 2899 }, 2900 2901 onElementEvent: function() { 2902 var value = this.getValue(); 2903 if (this.lastValue != value) { 2904 this.callback(this.element, value); 2905 this.lastValue = value; 2906 } 2907 }, 2908 2909 registerFormCallbacks: function() { 2910 Form.getElements(this.element).each(this.registerCallback.bind(this)); 2911 }, 2912 2913 registerCallback: function(element) { 2914 if (element.type) { 2915 switch (element.type.toLowerCase()) { 2916 case 'checkbox': 2917 case 'radio': 2918 Event.observe(element, 'click', this.onElementEvent.bind(this)); 2919 break; 2920 default: 2921 Event.observe(element, 'change', this.onElementEvent.bind(this)); 2922 break; 2923 } 2924 } 2925 } 2162 2926 } 2163 2927 2164 2928 Form.Element.EventObserver = Class.create(); 2165 2929 Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { 2166 2167 2168 2930 getValue: function() { 2931 return Form.Element.getValue(this.element); 2932 } 2169 2933 }); 2170 2934 2171 2935 Form.EventObserver = Class.create(); 2172 2936 Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { 2173 2174 2175 2937 getValue: function() { 2938 return Form.serialize(this.element); 2939 } 2176 2940 }); 2177 2941 if (!window.Event) { 2178 2942 var Event = new Object(); 2179 2943 } 2180 2944 2181 2945 Object.extend(Event, { 2182 KEY_BACKSPACE: 8, 2183 KEY_TAB: 9, 2184 KEY_RETURN: 13, 2185 KEY_ESC: 27, 2186 KEY_LEFT: 37, 2187 KEY_UP: 38, 2188 KEY_RIGHT: 39, 2189 KEY_DOWN: 40, 2190 KEY_DELETE: 46, 2191 KEY_HOME: 36, 2192 KEY_END: 35, 2193 KEY_PAGEUP: 33, 2194 KEY_PAGEDOWN: 34, 2195 2196 element: function(event) { 2197 return event.target || event.srcElement; 2198 }, 2199 2200 isLeftClick: function(event) { 2201 return (((event.which) && (event.which == 1)) || 2202 ((event.button) && (event.button == 1))); 2203 }, 2204 2205 pointerX: function(event) { 2206 return event.pageX || (event.clientX + 2207 (document.documentElement.scrollLeft || document.body.scrollLeft)); 2208 }, 2209 2210 pointerY: function(event) { 2211 return event.pageY || (event.clientY + 2212 (document.documentElement.scrollTop || document.body.scrollTop)); 2213 }, 2214 2215 stop: function(event) { 2216 if (event.preventDefault) { 2217 event.preventDefault(); 2218 event.stopPropagation(); 2219 } else { 2220 event.returnValue = false; 2221 event.cancelBubble = true; 2222 } 2223 }, 2224 2225 // find the first node with the given tagName, starting from the 2226 // node the event was triggered on; traverses the DOM upwards 2227 findElement: function(event, tagName) { 2228 var element = Event.element(event); 2229 while (element.parentNode && (!element.tagName || 2230 (element.tagName.toUpperCase() != tagName.toUpperCase()))) 2231 element = element.parentNode; 2232 return element; 2233 }, 2234 2235 observers: false, 2236 2237 _observeAndCache: function(element, name, observer, useCapture) { 2238 if (!this.observers) this.observers = []; 2239 if (element.addEventListener) { 2240 this.observers.push([element, name, observer, useCapture]); 2241 element.addEventListener(name, observer, useCapture); 2242 } else if (element.attachEvent) { 2243 this.observers.push([element, name, observer, useCapture]); 2244 element.attachEvent('on' + name, observer); 2245 } 2246 }, 2247 2248 unloadCache: function() { 2249 if (!Event.observers) return; 2250 for (var i = 0, length = Event.observers.length; i < length; i++) { 2251 Event.stopObserving.apply(this, Event.observers[i]); 2252 Event.observers[i][0] = null; 2253 } 2254 Event.observers = false; 2255 }, 2256 2257 observe: function(element, name, observer, useCapture) { 2258 element = $(element); 2259 useCapture = useCapture || false; 2260 2261 if (name == 'keypress' && 2262 (navigator.appVersion.match(/Konqueror|Safari|KHTML/) 2263 || element.attachEvent)) 2264 name = 'keydown'; 2265 2266 Event._observeAndCache(element, name, observer, useCapture); 2267 }, 2268 2269 stopObserving: function(element, name, observer, useCapture) { 2270 element = $(element); 2271 useCapture = useCapture || false; 2272 2273 if (name == 'keypress' && 2274 (navigator.appVersion.match(/Konqueror|Safari|KHTML/) 2275 || element.detachEvent)) 2276 name = 'keydown'; 2277 2278 if (element.removeEventListener) { 2279 element.removeEventListener(name, observer, useCapture); 2280 } else if (element.detachEvent) { 2281 try { 2282 element.detachEvent('on' + name, observer); 2283 } catch (e) {} 2284 } 2285 } 2946 KEY_BACKSPACE: 8, 2947 KEY_TAB: 9, 2948 KEY_RETURN: 13, 2949 KEY_ESC: 27, 2950 KEY_LEFT: 37, 2951 KEY_UP: 38, 2952 KEY_RIGHT: 39, 2953 KEY_DOWN: 40, 2954 KEY_DELETE: 46, 2955 KEY_HOME: 36, 2956 KEY_END: 35, 2957 KEY_PAGEUP: 33, 2958 KEY_PAGEDOWN: 34, 2959 2960 element: function(event) { 2961 return $(event.target || event.srcElement); 2962 }, 2963 2964 isLeftClick: function(event) { 2965 return (((event.which) && (event.which == 1)) || 2966 ((event.button) && (event.button == 1))); 2967 }, 2968 2969 pointerX: function(event) { 2970 return event.pageX || (event.clientX + 2971 (document.documentElement.scrollLeft || document.body.scrollLeft)); 2972 }, 2973 2974 pointerY: function(event) { 2975 return event.pageY || (event.clientY + 2976 (document.documentElement.scrollTop || document.body.scrollTop)); 2977 }, 2978 2979 stop: function(event) { 2980 if (event.preventDefault) { 2981 event.preventDefault(); 2982 event.stopPropagation(); 2983 } else { 2984 event.returnValue = false; 2985 event.cancelBubble = true; 2986 } 2987 }, 2988 2989 // find the first node with the given tagName, starting from the 2990 // node the event was triggered on; traverses the DOM upwards 2991 findElement: function(event, tagName) { 2992 var element = Event.element(event); 2993 while (element.parentNode && (!element.tagName || 2994 (element.tagName.toUpperCase() != tagName.toUpperCase()))) 2995 element = element.parentNode; 2996 return element; 2997 }, 2998 2999 observers: false, 3000 3001 _observeAndCache: function(element, name, observer, useCapture) { 3002 if (!this.observers) this.observers = []; 3003 if (element.addEventListener) { 3004 this.observers.push([element, name, observer, useCapture]); 3005 element.addEventListener(name, observer, useCapture); 3006 } else if (element.attachEvent) { 3007 this.observers.push([element, name, observer, useCapture]); 3008 element.attachEvent('on' + name, observer); 3009 } 3010 }, 3011 3012 unloadCache: function() { 3013 if (!Event.observers) return; 3014 for (var i = 0, length = Event.observers.length; i < length; i++) { 3015 Event.stopObserving.apply(this, Event.observers[i]); 3016 Event.observers[i][0] = null; 3017 } 3018 Event.observers = false; 3019 }, 3020 3021 observe: function(element, name, observer, useCapture) { 3022 element = $(element); 3023 useCapture = useCapture || false; 3024 3025 if (name == 'keypress' && 3026 (Prototype.Browser.WebKit || element.attachEvent)) 3027 name = 'keydown'; 3028 3029 Event._observeAndCache(element, name, observer, useCapture); 3030 }, 3031 3032 stopObserving: function(element, name, observer, useCapture) { 3033 element = $(element); 3034 useCapture = useCapture || false; 3035 3036 if (name == 'keypress' && 3037 (Prototype.Browser.WebKit || element.attachEvent)) 3038 name = 'keydown'; 3039 3040 if (element.removeEventListener) { 3041 element.removeEventListener(name, observer, useCapture); 3042 } else if (element.detachEvent) { 3043 try { 3044 element.detachEvent('on' + name, observer); 3045 } catch (e) {} 3046 } 3047 } 2286 3048 }); 2287 3049 2288 3050 /* prevent memory leaks in IE */ 2289 if ( navigator.appVersion.match(/\bMSIE\b/))2290 3051 if (Prototype.Browser.IE) 3052 Event.observe(window, 'unload', Event.unloadCache, false); 2291 3053 var Position = { 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 if (element.offsetParent==document.body)2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 3054 // set to true if needed, warning: firefox performance problems 3055 // NOT neeeded for page scrolling, only if draggable contained in 3056 // scrollable elements 3057 includeScrollOffsets: false, 3058 3059 // must be called before calling withinIncludingScrolloffset, every time the 3060 // page is scrolled 3061 prepare: function() { 3062 this.deltaX = window.pageXOffset 3063 || document.documentElement.scrollLeft 3064 || document.body.scrollLeft 3065 || 0; 3066 this.deltaY = window.pageYOffset 3067 || document.documentElement.scrollTop 3068 || document.body.scrollTop 3069 || 0; 3070 }, 3071 3072 realOffset: function(element) { 3073 var valueT = 0, valueL = 0; 3074 do { 3075 valueT += element.scrollTop || 0; 3076 valueL += element.scrollLeft || 0; 3077 element = element.parentNode; 3078 } while (element); 3079 return [valueL, valueT]; 3080 }, 3081 3082 cumulativeOffset: function(element) { 3083 var valueT = 0, valueL = 0; 3084 do { 3085 valueT += element.offsetTop || 0; 3086 valueL += element.offsetLeft || 0; 3087 element = element.offsetParent; 3088 } while (element); 3089 return [valueL, valueT]; 3090 }, 3091 3092 positionedOffset: function(element) { 3093 var valueT = 0, valueL = 0; 3094 do { 3095 valueT += element.offsetTop || 0; 3096 valueL += element.offsetLeft || 0; 3097 element = element.offsetParent; 3098 if (element) { 3099 if(element.tagName=='BODY') break; 3100 var p = Element.getStyle(element, 'position'); 3101 if (p == 'relative' || p == 'absolute') break; 3102 } 3103 } while (element); 3104 return [valueL, valueT]; 3105 }, 3106 3107 offsetParent: function(element) { 3108 if (element.offsetParent) return element.offsetParent; 3109 if (element == document.body) return element; 3110 3111 while ((element = element.parentNode) && element != document.body) 3112 if (Element.getStyle(element, 'position') != 'static') 3113 return element; 3114 3115 return document.body; 3116 }, 3117 3118 // caches x/y coordinate pair to use with overlap 3119 within: function(element, x, y) { 3120 if (this.includeScrollOffsets) 3121 return this.withinIncludingScrolloffsets(element, x, y); 3122 this.xcomp = x; 3123 this.ycomp = y; 3124 this.offset = this.cumulativeOffset(element); 3125 3126 return (y >= this.offset[1] && 3127 y < this.offset[1] + element.offsetHeight && 3128 x >= this.offset[0] && 3129 x < this.offset[0] + element.offsetWidth); 3130 }, 3131 3132 withinIncludingScrolloffsets: function(element, x, y) { 3133 var offsetcache = this.realOffset(element); 3134 3135 this.xcomp = x + offsetcache[0] - this.deltaX; 3136 this.ycomp = y + offsetcache[1] - this.deltaY; 3137 this.offset = this.cumulativeOffset(element); 3138 3139 return (this.ycomp >= this.offset[1] && 3140 this.ycomp < this.offset[1] + element.offsetHeight && 3141 this.xcomp >= this.offset[0] && 3142 this.xcomp < this.offset[0] + element.offsetWidth); 3143 }, 3144 3145 // within must be called directly before 3146 overlap: function(mode, element) { 3147 if (!mode) return 0; 3148 if (mode == 'vertical') 3149 return ((this.offset[1] + element.offsetHeight) - this.ycomp) / 3150 element.offsetHeight; 3151 if (mode == 'horizontal') 3152 return ((this.offset[0] + element.offsetWidth) - this.xcomp) / 3153 element.offsetWidth; 3154 }, 3155 3156 page: function(forElement) { 3157 var valueT = 0, valueL = 0; 3158 3159 var element = forElement; 3160 do { 3161 valueT += element.offsetTop || 0; 3162 valueL += element.offsetLeft || 0; 3163 3164 // Safari fix 3165 if (element.offsetParent == document.body) 3166 if (Element.getStyle(element,'position')=='absolute') break; 3167 3168 } while (element = element.offsetParent); 3169 3170 element = forElement; 3171 do { 3172 if (!window.opera || element.tagName=='BODY') { 3173 valueT -= element.scrollTop || 0; 3174 valueL -= element.scrollLeft || 0; 3175 } 3176 } while (element = element.parentNode); 3177 3178 return [valueL, valueT]; 3179 }, 3180 3181 clone: function(source, target) { 3182 var options = Object.extend({ 3183 setLeft: true, 3184 setTop: true, 3185 setWidth: true, 3186 setHeight: true, 3187 offsetTop: 0, 3188 offsetLeft: 0 3189 }, arguments[2] || {}) 3190 3191 // find page position of source 3192 source = $(source); 3193 var p = Position.page(source); 3194 3195 // find coordinate system to use 3196 target = $(target); 3197 var delta = [0, 0]; 3198 var parent = null; 3199 // delta [0,0] will do fine with position: fixed elements, 3200 // position:absolute needs offsetParent deltas 3201 if (Element.getStyle(target,'position') == 'absolute') { 3202 parent = Position.offsetParent(target); 3203 delta = Position.page(parent); 3204 } 3205 3206 // correct by body offsets (fixes Safari) 3207 if (parent == document.body) { 3208 delta[0] -= document.body.offsetLeft; 3209 delta[1] -= document.body.offsetTop; 3210 } 3211 3212 // set position 3213 if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; 3214 if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; 3215 if(options.setWidth) target.style.width = source.offsetWidth + 'px'; 3216 if(options.setHeight) target.style.height = source.offsetHeight + 'px'; 3217 }, 3218 3219 absolutize: function(element) { 3220 element = $(element); 3221 if (element.style.position == 'absolute') return; 3222 Position.prepare(); 3223 3224 var offsets = Position.positionedOffset(element); 3225 var top = offsets[1]; 3226 var left = offsets[0]; 3227 var width = element.clientWidth; 3228 var height = element.clientHeight; 3229 3230 element._originalLeft = left - parseFloat(element.style.left || 0); 3231 element._originalTop = top - parseFloat(element.style.top || 0); 3232 element._originalWidth = element.style.width; 3233 element._originalHeight = element.style.height; 3234 3235 element.style.position = 'absolute'; 3236 element.style.top = top + 'px'; 3237 element.style.left = left + 'px'; 3238 element.style.width = width + 'px'; 3239 element.style.height = height + 'px'; 3240 }, 3241 3242 relativize: function(element) { 3243 element = $(element); 3244 if (element.style.position == 'relative') return; 3245 Position.prepare(); 3246 3247 element.style.position = 'relative'; 3248 var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); 3249 var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); 3250 3251 element.style.top = top + 'px'; 3252 element.style.left = left + 'px'; 3253 element.style.height = element._originalHeight; 3254 element.style.width = element._originalWidth; 3255 } 2494 3256 } 2495 3257 … … 2497 3259 // positioned. For performance reasons, redefine Position.cumulativeOffset for 2498 3260 // KHTML/WebKit only. 2499 if ( /Konqueror|Safari|KHTML/.test(navigator.userAgent)) {2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 3261 if (Prototype.Browser.WebKit) { 3262 Position.cumulativeOffset = function(element) { 3263 var valueT = 0, valueL = 0; 3264 do { 3265 valueT += element.offsetTop || 0; 3266 valueL += element.offsetLeft || 0; 3267 if (element.offsetParent == document.body) 3268 if (Element.getStyle(element, 'position') == 'absolute') break; 3269 3270 element = element.offsetParent; 3271 } while (element); 3272 3273 return [valueL, valueT]; 3274 } 2513 3275 } 2514 3276
Note: See TracChangeset
for help on using the changeset viewer.