PageRenderTime 41ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/jruby-1.1.6RC1/lib/ruby/gems/1.8/gems/rspec-1.1.11/story_server/prototype/javascripts/prototype.js

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