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

/dozer/media/javascript/prototype.js

https://bitbucket.org/bbangert/dozer/
JavaScript | 2337 lines | 2088 code | 219 blank | 30 comment | 269 complexity | ed2d6608b0832c5e990e10729157b485 MD5 | raw file
  1. /* Prototype JavaScript framework, version 1.5.0
  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://prototype.conio.net/
  6. *
  7. /*--------------------------------------------------------------------------*/
  8. var Prototype = {
  9. Version: '1.5.0',
  10. BrowserFeatures: {
  11. XPath: !!document.evaluate
  12. },
  13. ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
  14. emptyFunction: function() {},
  15. K: function(x) { return x }
  16. }
  17. var Class = {
  18. create: function() {
  19. return function() {
  20. this.initialize.apply(this, arguments);
  21. }
  22. }
  23. }
  24. var Abstract = new Object();
  25. Object.extend = function(destination, source) {
  26. for (var property in source) {
  27. destination[property] = source[property];
  28. }
  29. return destination;
  30. }
  31. Object.extend(Object, {
  32. inspect: function(object) {
  33. try {
  34. if (object === undefined) return 'undefined';
  35. if (object === null) return 'null';
  36. return object.inspect ? object.inspect() : object.toString();
  37. } catch (e) {
  38. if (e instanceof RangeError) return '...';
  39. throw e;
  40. }
  41. },
  42. keys: function(object) {
  43. var keys = [];
  44. for (var property in object)
  45. keys.push(property);
  46. return keys;
  47. },
  48. values: function(object) {
  49. var values = [];
  50. for (var property in object)
  51. values.push(object[property]);
  52. return values;
  53. },
  54. clone: function(object) {
  55. return Object.extend({}, object);
  56. }
  57. });
  58. Function.prototype.bind = function() {
  59. var __method = this, args = $A(arguments), object = args.shift();
  60. return function() {
  61. return __method.apply(object, args.concat($A(arguments)));
  62. }
  63. }
  64. Function.prototype.bindAsEventListener = function(object) {
  65. var __method = this, args = $A(arguments), object = args.shift();
  66. return function(event) {
  67. return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));
  68. }
  69. }
  70. Object.extend(Number.prototype, {
  71. toColorPart: function() {
  72. var digits = this.toString(16);
  73. if (this < 16) return '0' + digits;
  74. return digits;
  75. },
  76. succ: function() {
  77. return this + 1;
  78. },
  79. times: function(iterator) {
  80. $R(0, this, true).each(iterator);
  81. return this;
  82. }
  83. });
  84. var Try = {
  85. these: function() {
  86. var returnValue;
  87. for (var i = 0, length = arguments.length; i < length; i++) {
  88. var lambda = arguments[i];
  89. try {
  90. returnValue = lambda();
  91. break;
  92. } catch (e) {}
  93. }
  94. return returnValue;
  95. }
  96. }
  97. /*--------------------------------------------------------------------------*/
  98. var PeriodicalExecuter = Class.create();
  99. PeriodicalExecuter.prototype = {
  100. initialize: function(callback, frequency) {
  101. this.callback = callback;
  102. this.frequency = frequency;
  103. this.currentlyExecuting = false;
  104. this.registerCallback();
  105. },
  106. registerCallback: function() {
  107. this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  108. },
  109. stop: function() {
  110. if (!this.timer) return;
  111. clearInterval(this.timer);
  112. this.timer = null;
  113. },
  114. onTimerEvent: function() {
  115. if (!this.currentlyExecuting) {
  116. try {
  117. this.currentlyExecuting = true;
  118. this.callback(this);
  119. } finally {
  120. this.currentlyExecuting = false;
  121. }
  122. }
  123. }
  124. }
  125. String.interpret = function(value){
  126. return value == null ? '' : String(value);
  127. }
  128. Object.extend(String.prototype, {
  129. gsub: function(pattern, replacement) {
  130. var result = '', source = this, match;
  131. replacement = arguments.callee.prepareReplacement(replacement);
  132. while (source.length > 0) {
  133. if (match = source.match(pattern)) {
  134. result += source.slice(0, match.index);
  135. result += String.interpret(replacement(match));
  136. source = source.slice(match.index + match[0].length);
  137. } else {
  138. result += source, source = '';
  139. }
  140. }
  141. return result;
  142. },
  143. sub: function(pattern, replacement, count) {
  144. replacement = this.gsub.prepareReplacement(replacement);
  145. count = count === undefined ? 1 : count;
  146. return this.gsub(pattern, function(match) {
  147. if (--count < 0) return match[0];
  148. return replacement(match);
  149. });
  150. },
  151. scan: function(pattern, iterator) {
  152. this.gsub(pattern, iterator);
  153. return this;
  154. },
  155. truncate: function(length, truncation) {
  156. length = length || 30;
  157. truncation = truncation === undefined ? '...' : truncation;
  158. return this.length > length ?
  159. this.slice(0, length - truncation.length) + truncation : this;
  160. },
  161. strip: function() {
  162. return this.replace(/^\s+/, '').replace(/\s+$/, '');
  163. },
  164. stripTags: function() {
  165. return this.replace(/<\/?[^>]+>/gi, '');
  166. },
  167. stripScripts: function() {
  168. return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
  169. },
  170. extractScripts: function() {
  171. var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
  172. var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
  173. return (this.match(matchAll) || []).map(function(scriptTag) {
  174. return (scriptTag.match(matchOne) || ['', ''])[1];
  175. });
  176. },
  177. evalScripts: function() {
  178. return this.extractScripts().map(function(script) { return eval(script) });
  179. },
  180. escapeHTML: function() {
  181. var div = document.createElement('div');
  182. var text = document.createTextNode(this);
  183. div.appendChild(text);
  184. return div.innerHTML;
  185. },
  186. unescapeHTML: function() {
  187. var div = document.createElement('div');
  188. div.innerHTML = this.stripTags();
  189. return div.childNodes[0] ? (div.childNodes.length > 1 ?
  190. $A(div.childNodes).inject('',function(memo,node){ return memo+node.nodeValue }) :
  191. div.childNodes[0].nodeValue) : '';
  192. },
  193. toQueryParams: function(separator) {
  194. var match = this.strip().match(/([^?#]*)(#.*)?$/);
  195. if (!match) return {};
  196. return match[1].split(separator || '&').inject({}, function(hash, pair) {
  197. if ((pair = pair.split('='))[0]) {
  198. var name = decodeURIComponent(pair[0]);
  199. var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
  200. if (hash[name] !== undefined) {
  201. if (hash[name].constructor != Array)
  202. hash[name] = [hash[name]];
  203. if (value) hash[name].push(value);
  204. }
  205. else hash[name] = value;
  206. }
  207. return hash;
  208. });
  209. },
  210. toArray: function() {
  211. return this.split('');
  212. },
  213. succ: function() {
  214. return this.slice(0, this.length - 1) +
  215. String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
  216. },
  217. camelize: function() {
  218. var parts = this.split('-'), len = parts.length;
  219. if (len == 1) return parts[0];
  220. var camelized = this.charAt(0) == '-'
  221. ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
  222. : parts[0];
  223. for (var i = 1; i < len; i++)
  224. camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
  225. return camelized;
  226. },
  227. capitalize: function(){
  228. return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
  229. },
  230. underscore: function() {
  231. return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
  232. },
  233. dasherize: function() {
  234. return this.gsub(/_/,'-');
  235. },
  236. inspect: function(useDoubleQuotes) {
  237. var escapedString = this.replace(/\\/g, '\\\\');
  238. if (useDoubleQuotes)
  239. return '"' + escapedString.replace(/"/g, '\\"') + '"';
  240. else
  241. return "'" + escapedString.replace(/'/g, '\\\'') + "'";
  242. }
  243. });
  244. String.prototype.gsub.prepareReplacement = function(replacement) {
  245. if (typeof replacement == 'function') return replacement;
  246. var template = new Template(replacement);
  247. return function(match) { return template.evaluate(match) };
  248. }
  249. String.prototype.parseQuery = String.prototype.toQueryParams;
  250. var Template = Class.create();
  251. Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
  252. Template.prototype = {
  253. initialize: function(template, pattern) {
  254. this.template = template.toString();
  255. this.pattern = pattern || Template.Pattern;
  256. },
  257. evaluate: function(object) {
  258. return this.template.gsub(this.pattern, function(match) {
  259. var before = match[1];
  260. if (before == '\\') return match[2];
  261. return before + String.interpret(object[match[3]]);
  262. });
  263. }
  264. }
  265. var $break = new Object();
  266. var $continue = new Object();
  267. var Enumerable = {
  268. each: function(iterator) {
  269. var index = 0;
  270. try {
  271. this._each(function(value) {
  272. try {
  273. iterator(value, index++);
  274. } catch (e) {
  275. if (e != $continue) throw e;
  276. }
  277. });
  278. } catch (e) {
  279. if (e != $break) throw e;
  280. }
  281. return this;
  282. },
  283. eachSlice: function(number, iterator) {
  284. var index = -number, slices = [], array = this.toArray();
  285. while ((index += number) < array.length)
  286. slices.push(array.slice(index, index+number));
  287. return slices.map(iterator);
  288. },
  289. all: function(iterator) {
  290. var result = true;
  291. this.each(function(value, index) {
  292. result = result && !!(iterator || Prototype.K)(value, index);
  293. if (!result) throw $break;
  294. });
  295. return result;
  296. },
  297. any: function(iterator) {
  298. var result = false;
  299. this.each(function(value, index) {
  300. if (result = !!(iterator || Prototype.K)(value, index))
  301. throw $break;
  302. });
  303. return result;
  304. },
  305. collect: function(iterator) {
  306. var results = [];
  307. this.each(function(value, index) {
  308. results.push((iterator || Prototype.K)(value, index));
  309. });
  310. return results;
  311. },
  312. detect: function(iterator) {
  313. var result;
  314. this.each(function(value, index) {
  315. if (iterator(value, index)) {
  316. result = value;
  317. throw $break;
  318. }
  319. });
  320. return result;
  321. },
  322. findAll: function(iterator) {
  323. var results = [];
  324. this.each(function(value, index) {
  325. if (iterator(value, index))
  326. results.push(value);
  327. });
  328. return results;
  329. },
  330. grep: function(pattern, iterator) {
  331. var results = [];
  332. this.each(function(value, index) {
  333. var stringValue = value.toString();
  334. if (stringValue.match(pattern))
  335. results.push((iterator || Prototype.K)(value, index));
  336. })
  337. return results;
  338. },
  339. include: function(object) {
  340. var found = false;
  341. this.each(function(value) {
  342. if (value == object) {
  343. found = true;
  344. throw $break;
  345. }
  346. });
  347. return found;
  348. },
  349. inGroupsOf: function(number, fillWith) {
  350. fillWith = fillWith === undefined ? null : fillWith;
  351. return this.eachSlice(number, function(slice) {
  352. while(slice.length < number) slice.push(fillWith);
  353. return slice;
  354. });
  355. },
  356. inject: function(memo, iterator) {
  357. this.each(function(value, index) {
  358. memo = iterator(memo, value, index);
  359. });
  360. return memo;
  361. },
  362. invoke: function(method) {
  363. var args = $A(arguments).slice(1);
  364. return this.map(function(value) {
  365. return value[method].apply(value, args);
  366. });
  367. },
  368. max: function(iterator) {
  369. var result;
  370. this.each(function(value, index) {
  371. value = (iterator || Prototype.K)(value, index);
  372. if (result == undefined || value >= result)
  373. result = value;
  374. });
  375. return result;
  376. },
  377. min: function(iterator) {
  378. var result;
  379. this.each(function(value, index) {
  380. value = (iterator || Prototype.K)(value, index);
  381. if (result == undefined || value < result)
  382. result = value;
  383. });
  384. return result;
  385. },
  386. partition: function(iterator) {
  387. var trues = [], falses = [];
  388. this.each(function(value, index) {
  389. ((iterator || Prototype.K)(value, index) ?
  390. trues : falses).push(value);
  391. });
  392. return [trues, falses];
  393. },
  394. pluck: function(property) {
  395. var results = [];
  396. this.each(function(value, index) {
  397. results.push(value[property]);
  398. });
  399. return results;
  400. },
  401. reject: function(iterator) {
  402. var results = [];
  403. this.each(function(value, index) {
  404. if (!iterator(value, index))
  405. results.push(value);
  406. });
  407. return results;
  408. },
  409. sortBy: function(iterator) {
  410. return this.map(function(value, index) {
  411. return {value: value, criteria: iterator(value, index)};
  412. }).sort(function(left, right) {
  413. var a = left.criteria, b = right.criteria;
  414. return a < b ? -1 : a > b ? 1 : 0;
  415. }).pluck('value');
  416. },
  417. toArray: function() {
  418. return this.map();
  419. },
  420. zip: function() {
  421. var iterator = Prototype.K, args = $A(arguments);
  422. if (typeof args.last() == 'function')
  423. iterator = args.pop();
  424. var collections = [this].concat(args).map($A);
  425. return this.map(function(value, index) {
  426. return iterator(collections.pluck(index));
  427. });
  428. },
  429. size: function() {
  430. return this.toArray().length;
  431. },
  432. inspect: function() {
  433. return '#<Enumerable:' + this.toArray().inspect() + '>';
  434. }
  435. }
  436. Object.extend(Enumerable, {
  437. map: Enumerable.collect,
  438. find: Enumerable.detect,
  439. select: Enumerable.findAll,
  440. member: Enumerable.include,
  441. entries: Enumerable.toArray
  442. });
  443. var $A = Array.from = function(iterable) {
  444. if (!iterable) return [];
  445. if (iterable.toArray) {
  446. return iterable.toArray();
  447. } else {
  448. var results = [];
  449. for (var i = 0, length = iterable.length; i < length; i++)
  450. results.push(iterable[i]);
  451. return results;
  452. }
  453. }
  454. Object.extend(Array.prototype, Enumerable);
  455. if (!Array.prototype._reverse)
  456. Array.prototype._reverse = Array.prototype.reverse;
  457. Object.extend(Array.prototype, {
  458. _each: function(iterator) {
  459. for (var i = 0, length = this.length; i < length; i++)
  460. iterator(this[i]);
  461. },
  462. clear: function() {
  463. this.length = 0;
  464. return this;
  465. },
  466. first: function() {
  467. return this[0];
  468. },
  469. last: function() {
  470. return this[this.length - 1];
  471. },
  472. compact: function() {
  473. return this.select(function(value) {
  474. return value != null;
  475. });
  476. },
  477. flatten: function() {
  478. return this.inject([], function(array, value) {
  479. return array.concat(value && value.constructor == Array ?
  480. value.flatten() : [value]);
  481. });
  482. },
  483. without: function() {
  484. var values = $A(arguments);
  485. return this.select(function(value) {
  486. return !values.include(value);
  487. });
  488. },
  489. indexOf: function(object) {
  490. for (var i = 0, length = this.length; i < length; i++)
  491. if (this[i] == object) return i;
  492. return -1;
  493. },
  494. reverse: function(inline) {
  495. return (inline !== false ? this : this.toArray())._reverse();
  496. },
  497. reduce: function() {
  498. return this.length > 1 ? this : this[0];
  499. },
  500. uniq: function() {
  501. return this.inject([], function(array, value) {
  502. return array.include(value) ? array : array.concat([value]);
  503. });
  504. },
  505. clone: function() {
  506. return [].concat(this);
  507. },
  508. size: function() {
  509. return this.length;
  510. },
  511. inspect: function() {
  512. return '[' + this.map(Object.inspect).join(', ') + ']';
  513. }
  514. });
  515. Array.prototype.toArray = Array.prototype.clone;
  516. function $w(string){
  517. string = string.strip();
  518. return string ? string.split(/\s+/) : [];
  519. }
  520. if(window.opera){
  521. Array.prototype.concat = function(){
  522. var array = [];
  523. for(var i = 0, length = this.length; i < length; i++) array.push(this[i]);
  524. for(var i = 0, length = arguments.length; i < length; i++) {
  525. if(arguments[i].constructor == Array) {
  526. for(var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
  527. array.push(arguments[i][j]);
  528. } else {
  529. array.push(arguments[i]);
  530. }
  531. }
  532. return array;
  533. }
  534. }
  535. var Hash = function(obj) {
  536. Object.extend(this, obj || {});
  537. };
  538. Object.extend(Hash, {
  539. toQueryString: function(obj) {
  540. var parts = [];
  541. this.prototype._each.call(obj, function(pair) {
  542. if (!pair.key) return;
  543. if (pair.value && pair.value.constructor == Array) {
  544. var values = pair.value.compact();
  545. if (values.length < 2) pair.value = values.reduce();
  546. else {
  547. key = encodeURIComponent(pair.key);
  548. values.each(function(value) {
  549. value = value != undefined ? encodeURIComponent(value) : '';
  550. parts.push(key + '=' + encodeURIComponent(value));
  551. });
  552. return;
  553. }
  554. }
  555. if (pair.value == undefined) pair[1] = '';
  556. parts.push(pair.map(encodeURIComponent).join('='));
  557. });
  558. return parts.join('&');
  559. }
  560. });
  561. Object.extend(Hash.prototype, Enumerable);
  562. Object.extend(Hash.prototype, {
  563. _each: function(iterator) {
  564. for (var key in this) {
  565. var value = this[key];
  566. if (value && value == Hash.prototype[key]) continue;
  567. var pair = [key, value];
  568. pair.key = key;
  569. pair.value = value;
  570. iterator(pair);
  571. }
  572. },
  573. keys: function() {
  574. return this.pluck('key');
  575. },
  576. values: function() {
  577. return this.pluck('value');
  578. },
  579. merge: function(hash) {
  580. return $H(hash).inject(this, function(mergedHash, pair) {
  581. mergedHash[pair.key] = pair.value;
  582. return mergedHash;
  583. });
  584. },
  585. remove: function() {
  586. var result;
  587. for(var i = 0, length = arguments.length; i < length; i++) {
  588. var value = this[arguments[i]];
  589. if (value !== undefined){
  590. if (result === undefined) result = value;
  591. else {
  592. if (result.constructor != Array) result = [result];
  593. result.push(value)
  594. }
  595. }
  596. delete this[arguments[i]];
  597. }
  598. return result;
  599. },
  600. toQueryString: function() {
  601. return Hash.toQueryString(this);
  602. },
  603. inspect: function() {
  604. return '#<Hash:{' + this.map(function(pair) {
  605. return pair.map(Object.inspect).join(': ');
  606. }).join(', ') + '}>';
  607. }
  608. });
  609. function $H(object) {
  610. if (object && object.constructor == Hash) return object;
  611. return new Hash(object);
  612. };
  613. ObjectRange = Class.create();
  614. Object.extend(ObjectRange.prototype, Enumerable);
  615. Object.extend(ObjectRange.prototype, {
  616. initialize: function(start, end, exclusive) {
  617. this.start = start;
  618. this.end = end;
  619. this.exclusive = exclusive;
  620. },
  621. _each: function(iterator) {
  622. var value = this.start;
  623. while (this.include(value)) {
  624. iterator(value);
  625. value = value.succ();
  626. }
  627. },
  628. include: function(value) {
  629. if (value < this.start)
  630. return false;
  631. if (this.exclusive)
  632. return value < this.end;
  633. return value <= this.end;
  634. }
  635. });
  636. var $R = function(start, end, exclusive) {
  637. return new ObjectRange(start, end, exclusive);
  638. }
  639. var Ajax = {
  640. getTransport: function() {
  641. return Try.these(
  642. function() {return new XMLHttpRequest()},
  643. function() {return new ActiveXObject('Msxml2.XMLHTTP')},
  644. function() {return new ActiveXObject('Microsoft.XMLHTTP')}
  645. ) || false;
  646. },
  647. activeRequestCount: 0
  648. }
  649. Ajax.Responders = {
  650. responders: [],
  651. _each: function(iterator) {
  652. this.responders._each(iterator);
  653. },
  654. register: function(responder) {
  655. if (!this.include(responder))
  656. this.responders.push(responder);
  657. },
  658. unregister: function(responder) {
  659. this.responders = this.responders.without(responder);
  660. },
  661. dispatch: function(callback, request, transport, json) {
  662. this.each(function(responder) {
  663. if (typeof responder[callback] == 'function') {
  664. try {
  665. responder[callback].apply(responder, [request, transport, json]);
  666. } catch (e) {}
  667. }
  668. });
  669. }
  670. };
  671. Object.extend(Ajax.Responders, Enumerable);
  672. Ajax.Responders.register({
  673. onCreate: function() {
  674. Ajax.activeRequestCount++;
  675. },
  676. onComplete: function() {
  677. Ajax.activeRequestCount--;
  678. }
  679. });
  680. Ajax.Base = function() {};
  681. Ajax.Base.prototype = {
  682. setOptions: function(options) {
  683. this.options = {
  684. method: 'post',
  685. asynchronous: true,
  686. contentType: 'application/x-www-form-urlencoded',
  687. encoding: 'UTF-8',
  688. parameters: ''
  689. }
  690. Object.extend(this.options, options || {});
  691. this.options.method = this.options.method.toLowerCase();
  692. if (typeof this.options.parameters == 'string')
  693. this.options.parameters = this.options.parameters.toQueryParams();
  694. }
  695. }
  696. Ajax.Request = Class.create();
  697. Ajax.Request.Events =
  698. ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
  699. Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
  700. _complete: false,
  701. initialize: function(url, options) {
  702. this.transport = Ajax.getTransport();
  703. this.setOptions(options);
  704. this.request(url);
  705. },
  706. request: function(url) {
  707. this.url = url;
  708. this.method = this.options.method;
  709. var params = this.options.parameters;
  710. if (!['get', 'post'].include(this.method)) {
  711. // simulate other verbs over post
  712. params['_method'] = this.method;
  713. this.method = 'post';
  714. }
  715. params = Hash.toQueryString(params);
  716. if (params && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_='
  717. // when GET, append parameters to URL
  718. if (this.method == 'get' && params)
  719. this.url += (this.url.indexOf('?') > -1 ? '&' : '?') + params;
  720. try {
  721. Ajax.Responders.dispatch('onCreate', this, this.transport);
  722. this.transport.open(this.method.toUpperCase(), this.url,
  723. this.options.asynchronous);
  724. if (this.options.asynchronous)
  725. setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
  726. this.transport.onreadystatechange = this.onStateChange.bind(this);
  727. this.setRequestHeaders();
  728. var body = this.method == 'post' ? (this.options.postBody || params) : null;
  729. this.transport.send(body);
  730. /* Force Firefox to handle ready state 4 for synchronous requests */
  731. if (!this.options.asynchronous && this.transport.overrideMimeType)
  732. this.onStateChange();
  733. }
  734. catch (e) {
  735. this.dispatchException(e);
  736. }
  737. },
  738. onStateChange: function() {
  739. var readyState = this.transport.readyState;
  740. if (readyState > 1 && !((readyState == 4) && this._complete))
  741. this.respondToReadyState(this.transport.readyState);
  742. },
  743. setRequestHeaders: function() {
  744. var headers = {
  745. 'X-Requested-With': 'XMLHttpRequest',
  746. 'X-Prototype-Version': Prototype.Version,
  747. 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
  748. };
  749. if (this.method == 'post') {
  750. headers['Content-type'] = this.options.contentType +
  751. (this.options.encoding ? '; charset=' + this.options.encoding : '');
  752. /* Force "Connection: close" for older Mozilla browsers to work
  753. * around a bug where XMLHttpRequest sends an incorrect
  754. * Content-length header. See Mozilla Bugzilla #246651.
  755. */
  756. if (this.transport.overrideMimeType &&
  757. (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
  758. headers['Connection'] = 'close';
  759. }
  760. // user-defined headers
  761. if (typeof this.options.requestHeaders == 'object') {
  762. var extras = this.options.requestHeaders;
  763. if (typeof extras.push == 'function')
  764. for (var i = 0, length = extras.length; i < length; i += 2)
  765. headers[extras[i]] = extras[i+1];
  766. else
  767. $H(extras).each(function(pair) { headers[pair.key] = pair.value });
  768. }
  769. for (var name in headers)
  770. this.transport.setRequestHeader(name, headers[name]);
  771. },
  772. success: function() {
  773. return !this.transport.status
  774. || (this.transport.status >= 200 && this.transport.status < 300);
  775. },
  776. respondToReadyState: function(readyState) {
  777. var state = Ajax.Request.Events[readyState];
  778. var transport = this.transport, json = this.evalJSON();
  779. if (state == 'Complete') {
  780. try {
  781. this._complete = true;
  782. (this.options['on' + this.transport.status]
  783. || this.options['on' + (this.success() ? 'Success' : 'Failure')]
  784. || Prototype.emptyFunction)(transport, json);
  785. } catch (e) {
  786. this.dispatchException(e);
  787. }
  788. if ((this.getHeader('Content-type') || 'text/javascript').strip().
  789. match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
  790. this.evalResponse();
  791. }
  792. try {
  793. (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
  794. Ajax.Responders.dispatch('on' + state, this, transport, json);
  795. } catch (e) {
  796. this.dispatchException(e);
  797. }
  798. if (state == 'Complete') {
  799. // avoid memory leak in MSIE: clean up
  800. this.transport.onreadystatechange = Prototype.emptyFunction;
  801. }
  802. },
  803. getHeader: function(name) {
  804. try {
  805. return this.transport.getResponseHeader(name);
  806. } catch (e) { return null }
  807. },
  808. evalJSON: function() {
  809. try {
  810. var json = this.getHeader('X-JSON');
  811. return json ? eval('(' + json + ')') : null;
  812. } catch (e) { return null }
  813. },
  814. evalResponse: function() {
  815. try {
  816. return eval(this.transport.responseText);
  817. } catch (e) {
  818. this.dispatchException(e);
  819. }
  820. },
  821. dispatchException: function(exception) {
  822. (this.options.onException || Prototype.emptyFunction)(this, exception);
  823. Ajax.Responders.dispatch('onException', this, exception);
  824. }
  825. });
  826. Ajax.Updater = Class.create();
  827. Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
  828. initialize: function(container, url, options) {
  829. this.container = {
  830. success: (container.success || container),
  831. failure: (container.failure || (container.success ? null : container))
  832. }
  833. this.transport = Ajax.getTransport();
  834. this.setOptions(options);
  835. var onComplete = this.options.onComplete || Prototype.emptyFunction;
  836. this.options.onComplete = (function(transport, param) {
  837. this.updateContent();
  838. onComplete(transport, param);
  839. }).bind(this);
  840. this.request(url);
  841. },
  842. updateContent: function() {
  843. var receiver = this.container[this.success() ? 'success' : 'failure'];
  844. var response = this.transport.responseText;
  845. if (!this.options.evalScripts) response = response.stripScripts();
  846. if (receiver = $(receiver)) {
  847. if (this.options.insertion)
  848. new this.options.insertion(receiver, response);
  849. else
  850. receiver.update(response);
  851. }
  852. if (this.success()) {
  853. if (this.onComplete)
  854. setTimeout(this.onComplete.bind(this), 10);
  855. }
  856. }
  857. });
  858. Ajax.PeriodicalUpdater = Class.create();
  859. Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
  860. initialize: function(container, url, options) {
  861. this.setOptions(options);
  862. this.onComplete = this.options.onComplete;
  863. this.frequency = (this.options.frequency || 2);
  864. this.decay = (this.options.decay || 1);
  865. this.updater = {};
  866. this.container = container;
  867. this.url = url;
  868. this.start();
  869. },
  870. start: function() {
  871. this.options.onComplete = this.updateComplete.bind(this);
  872. this.onTimerEvent();
  873. },
  874. stop: function() {
  875. this.updater.options.onComplete = undefined;
  876. clearTimeout(this.timer);
  877. (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
  878. },
  879. updateComplete: function(request) {
  880. if (this.options.decay) {
  881. this.decay = (request.responseText == this.lastText ?
  882. this.decay * this.options.decay : 1);
  883. this.lastText = request.responseText;
  884. }
  885. this.timer = setTimeout(this.onTimerEvent.bind(this),
  886. this.decay * this.frequency * 1000);
  887. },
  888. onTimerEvent: function() {
  889. this.updater = new Ajax.Updater(this.container, this.url, this.options);
  890. }
  891. });
  892. function $(element) {
  893. if (arguments.length > 1) {
  894. for (var i = 0, elements = [], length = arguments.length; i < length; i++)
  895. elements.push($(arguments[i]));
  896. return elements;
  897. }
  898. if (typeof element == 'string')
  899. element = document.getElementById(element);
  900. return Element.extend(element);
  901. }
  902. if (Prototype.BrowserFeatures.XPath) {
  903. document._getElementsByXPath = function(expression, parentElement) {
  904. var results = [];
  905. var query = document.evaluate(expression, $(parentElement) || document,
  906. null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  907. for (var i = 0, length = query.snapshotLength; i < length; i++)
  908. results.push(query.snapshotItem(i));
  909. return results;
  910. };
  911. }
  912. document.getElementsByClassName = function(className, parentElement) {
  913. if (Prototype.BrowserFeatures.XPath) {
  914. var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
  915. return document._getElementsByXPath(q, parentElement);
  916. } else {
  917. var children = ($(parentElement) || document.body).getElementsByTagName('*');
  918. var elements = [], child;
  919. for (var i = 0, length = children.length; i < length; i++) {
  920. child = children[i];
  921. if (Element.hasClassName(child, className))
  922. elements.push(Element.extend(child));
  923. }
  924. return elements;
  925. }
  926. };
  927. /*--------------------------------------------------------------------------*/
  928. if (!window.Element)
  929. var Element = new Object();
  930. Element.extend = function(element) {
  931. if (!element || _nativeExtensions || element.nodeType == 3) return element;
  932. if (!element._extended && element.tagName && element != window) {
  933. var methods = Object.clone(Element.Methods), cache = Element.extend.cache;
  934. if (element.tagName == 'FORM')
  935. Object.extend(methods, Form.Methods);
  936. if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
  937. Object.extend(methods, Form.Element.Methods);
  938. Object.extend(methods, Element.Methods.Simulated);
  939. for (var property in methods) {
  940. var value = methods[property];
  941. if (typeof value == 'function' && !(property in element))
  942. element[property] = cache.findOrStore(value);
  943. }
  944. }
  945. element._extended = true;
  946. return element;
  947. };
  948. Element.extend.cache = {
  949. findOrStore: function(value) {
  950. return this[value] = this[value] || function() {
  951. return value.apply(null, [this].concat($A(arguments)));
  952. }
  953. }
  954. };
  955. Element.Methods = {
  956. visible: function(element) {
  957. return $(element).style.display != 'none';
  958. },
  959. toggle: function(element) {
  960. element = $(element);
  961. Element[Element.visible(element) ? 'hide' : 'show'](element);
  962. return element;
  963. },
  964. hide: function(element) {
  965. $(element).style.display = 'none';
  966. return element;
  967. },
  968. show: function(element) {
  969. $(element).style.display = '';
  970. return element;
  971. },
  972. remove: function(element) {
  973. element = $(element);
  974. element.parentNode.removeChild(element);
  975. return element;
  976. },
  977. update: function(element, html) {
  978. html = typeof html == 'undefined' ? '' : html.toString();
  979. $(element).innerHTML = html.stripScripts();
  980. setTimeout(function() {html.evalScripts()}, 10);
  981. return element;
  982. },
  983. replace: function(element, html) {
  984. element = $(element);
  985. html = typeof html == 'undefined' ? '' : html.toString();
  986. if (element.outerHTML) {
  987. element.outerHTML = html.stripScripts();
  988. } else {
  989. var range = element.ownerDocument.createRange();
  990. range.selectNodeContents(element);
  991. element.parentNode.replaceChild(
  992. range.createContextualFragment(html.stripScripts()), element);
  993. }
  994. setTimeout(function() {html.evalScripts()}, 10);
  995. return element;
  996. },
  997. inspect: function(element) {
  998. element = $(element);
  999. var result = '<' + element.tagName.toLowerCase();
  1000. $H({'id': 'id', 'className': 'class'}).each(function(pair) {
  1001. var property = pair.first(), attribute = pair.last();
  1002. var value = (element[property] || '').toString();
  1003. if (value) result += ' ' + attribute + '=' + value.inspect(true);
  1004. });
  1005. return result + '>';
  1006. },
  1007. recursivelyCollect: function(element, property) {
  1008. element = $(element);
  1009. var elements = [];
  1010. while (element = element[property])
  1011. if (element.nodeType == 1)
  1012. elements.push(Element.extend(element));
  1013. return elements;
  1014. },
  1015. ancestors: function(element) {
  1016. return $(element).recursivelyCollect('parentNode');
  1017. },
  1018. descendants: function(element) {
  1019. return $A($(element).getElementsByTagName('*'));
  1020. },
  1021. immediateDescendants: function(element) {
  1022. if (!(element = $(element).firstChild)) return [];
  1023. while (element && element.nodeType != 1) element = element.nextSibling;
  1024. if (element) return [element].concat($(element).nextSiblings());
  1025. return [];
  1026. },
  1027. previousSiblings: function(element) {
  1028. return $(element).recursivelyCollect('previousSibling');
  1029. },
  1030. nextSiblings: function(element) {
  1031. return $(element).recursivelyCollect('nextSibling');
  1032. },
  1033. siblings: function(element) {
  1034. element = $(element);
  1035. return element.previousSiblings().reverse().concat(element.nextSiblings());
  1036. },
  1037. match: function(element, selector) {
  1038. if (typeof selector == 'string')
  1039. selector = new Selector(selector);
  1040. return selector.match($(element));
  1041. },
  1042. up: function(element, expression, index) {
  1043. return Selector.findElement($(element).ancestors(), expression, index);
  1044. },
  1045. down: function(element, expression, index) {
  1046. return Selector.findElement($(element).descendants(), expression, index);
  1047. },
  1048. previous: function(element, expression, index) {
  1049. return Selector.findElement($(element).previousSiblings(), expression, index);
  1050. },
  1051. next: function(element, expression, index) {
  1052. return Selector.findElement($(element).nextSiblings(), expression, index);
  1053. },
  1054. getElementsBySelector: function() {
  1055. var args = $A(arguments), element = $(args.shift());
  1056. return Selector.findChildElements(element, args);
  1057. },
  1058. getElementsByClassName: function(element, className) {
  1059. return document.getElementsByClassName(className, element);
  1060. },
  1061. readAttribute: function(element, name) {
  1062. element = $(element);
  1063. if (document.all && !window.opera) {
  1064. var t = Element._attributeTranslations;
  1065. if (t.values[name]) return t.values[name](element, name);
  1066. if (t.names[name]) name = t.names[name];
  1067. var attribute = element.attributes[name];
  1068. if(attribute) return attribute.nodeValue;
  1069. }
  1070. return element.getAttribute(name);
  1071. },
  1072. getHeight: function(element) {
  1073. return $(element).getDimensions().height;
  1074. },
  1075. getWidth: function(element) {
  1076. return $(element).getDimensions().width;
  1077. },
  1078. classNames: function(element) {
  1079. return new Element.ClassNames(element);
  1080. },
  1081. hasClassName: function(element, className) {
  1082. if (!(element = $(element))) return;
  1083. var elementClassName = element.className;
  1084. if (elementClassName.length == 0) return false;
  1085. if (elementClassName == className ||
  1086. elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
  1087. return true;
  1088. return false;
  1089. },
  1090. addClassName: function(element, className) {
  1091. if (!(element = $(element))) return;
  1092. Element.classNames(element).add(className);
  1093. return element;
  1094. },
  1095. removeClassName: function(element, className) {
  1096. if (!(element = $(element))) return;
  1097. Element.classNames(element).remove(className);
  1098. return element;
  1099. },
  1100. toggleClassName: function(element, className) {
  1101. if (!(element = $(element))) return;
  1102. Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
  1103. return element;
  1104. },
  1105. observe: function() {
  1106. Event.observe.apply(Event, arguments);
  1107. return $A(arguments).first();
  1108. },
  1109. stopObserving: function() {
  1110. Event.stopObserving.apply(Event, arguments);
  1111. return $A(arguments).first();
  1112. },
  1113. // removes whitespace-only text node children
  1114. cleanWhitespace: function(element) {
  1115. element = $(element);
  1116. var node = element.firstChild;
  1117. while (node) {
  1118. var nextNode = node.nextSibling;
  1119. if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
  1120. element.removeChild(node);
  1121. node = nextNode;
  1122. }
  1123. return element;
  1124. },
  1125. empty: function(element) {
  1126. return $(element).innerHTML.match(/^\s*$/);
  1127. },
  1128. descendantOf: function(element, ancestor) {
  1129. element = $(element), ancestor = $(ancestor);
  1130. while (element = element.parentNode)
  1131. if (element == ancestor) return true;
  1132. return false;
  1133. },
  1134. scrollTo: function(element) {
  1135. element = $(element);
  1136. var pos = Position.cumulativeOffset(element);
  1137. window.scrollTo(pos[0], pos[1]);
  1138. return element;
  1139. },
  1140. getStyle: function(element, style) {
  1141. element = $(element);
  1142. if (['float','cssFloat'].include(style))
  1143. style = (typeof element.style.styleFloat != 'undefined' ? 'styleFloat' : 'cssFloat');
  1144. style = style.camelize();
  1145. var value = element.style[style];
  1146. if (!value) {
  1147. if (document.defaultView && document.defaultView.getComputedStyle) {
  1148. var css = document.defaultView.getComputedStyle(element, null);
  1149. value = css ? css[style] : null;
  1150. } else if (element.currentStyle) {
  1151. value = element.currentStyle[style];
  1152. }
  1153. }
  1154. if((value == 'auto') && ['width','height'].include(style) && (element.getStyle('display') != 'none'))
  1155. value = element['offset'+style.capitalize()] + 'px';
  1156. if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
  1157. if (Element.getStyle(element, 'position') == 'static') value = 'auto';
  1158. if(style == 'opacity') {
  1159. if(value) return parseFloat(value);
  1160. if(value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
  1161. if(value[1]) return parseFloat(value[1]) / 100;
  1162. return 1.0;
  1163. }
  1164. return value == 'auto' ? null : value;
  1165. },
  1166. setStyle: function(element, style) {
  1167. element = $(element);
  1168. for (var name in style) {
  1169. var value = style[name];
  1170. if(name == 'opacity') {
  1171. if (value == 1) {
  1172. value = (/Gecko/.test(navigator.userAgent) &&
  1173. !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : 1.0;
  1174. if(/MSIE/.test(navigator.userAgent) && !window.opera)
  1175. element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
  1176. } else if(value == '') {
  1177. if(/MSIE/.test(navigator.userAgent) && !window.opera)
  1178. element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
  1179. } else {
  1180. if(value < 0.00001) value = 0;
  1181. if(/MSIE/.test(navigator.userAgent) && !window.opera)
  1182. element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') +
  1183. 'alpha(opacity='+value*100+')';
  1184. }
  1185. } else if(['float','cssFloat'].include(name)) name = (typeof element.style.styleFloat != 'undefined') ? 'styleFloat' : 'cssFloat';
  1186. element.style[name.camelize()] = value;
  1187. }
  1188. return element;
  1189. },
  1190. getDimensions: function(element) {
  1191. element = $(element);
  1192. var display = $(element).getStyle('display');
  1193. if (display != 'none' && display != null) // Safari bug
  1194. return {width: element.offsetWidth, height: element.offsetHeight};
  1195. // All *Width and *Height properties give 0 on elements with display none,
  1196. // so enable the element temporarily
  1197. var els = element.style;
  1198. var originalVisibility = els.visibility;
  1199. var originalPosition = els.position;
  1200. var originalDisplay = els.display;
  1201. els.visibility = 'hidden';
  1202. els.position = 'absolute';
  1203. els.display = 'block';
  1204. var originalWidth = element.clientWidth;
  1205. var originalHeight = element.clientHeight;
  1206. els.display = originalDisplay;
  1207. els.position = originalPosition;
  1208. els.visibility = originalVisibility;
  1209. return {width: originalWidth, height: originalHeight};
  1210. },
  1211. makePositioned: function(element) {
  1212. element = $(element);
  1213. var pos = Element.getStyle(element, 'position');
  1214. if (pos == 'static' || !pos) {
  1215. element._madePositioned = true;
  1216. element.style.position = 'relative';
  1217. // Opera returns the offset relative to the positioning context, when an
  1218. // element is position relative but top and left have not been defined
  1219. if (window.opera) {
  1220. element.style.top = 0;
  1221. element.style.left = 0;
  1222. }
  1223. }
  1224. return element;
  1225. },
  1226. undoPositioned: function(element) {
  1227. element = $(element);
  1228. if (element._madePositioned) {
  1229. element._madePositioned = undefined;
  1230. element.style.position =
  1231. element.style.top =
  1232. element.style.left =
  1233. element.style.bottom =
  1234. element.style.right = '';
  1235. }
  1236. return element;
  1237. },
  1238. makeClipping: function(element) {
  1239. element = $(element);
  1240. if (element._overflow) return element;
  1241. element._overflow = element.style.overflow || 'auto';
  1242. if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
  1243. element.style.overflow = 'hidden';
  1244. return element;
  1245. },
  1246. undoClipping: function(element) {
  1247. element = $(element);
  1248. if (!element._overflow) return element;
  1249. element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
  1250. element._overflow = null;
  1251. return element;
  1252. }
  1253. };
  1254. Object.extend(Element.Methods, {childOf: Element.Methods.descendantOf});
  1255. Element._attributeTranslations = {};
  1256. Element._attributeTranslations.names = {
  1257. colspan: "colSpan",
  1258. rowspan: "rowSpan",
  1259. valign: "vAlign",
  1260. datetime: "dateTime",
  1261. accesskey: "accessKey",
  1262. tabindex: "tabIndex",
  1263. enctype: "encType",
  1264. maxlength: "maxLength",
  1265. readonly: "readOnly",
  1266. longdesc: "longDesc"
  1267. };
  1268. Element._attributeTranslations.values = {
  1269. _getAttr: function(element, attribute) {
  1270. return element.getAttribute(attribute, 2);
  1271. },
  1272. _flag: function(element, attribute) {
  1273. return $(element).hasAttribute(attribute) ? attribute : null;
  1274. },
  1275. style: function(element) {
  1276. return element.style.cssText.toLowerCase();
  1277. },
  1278. title: function(element) {
  1279. var node = element.getAttributeNode('title');
  1280. return node.specified ? node.nodeValue : null;
  1281. }
  1282. };
  1283. Object.extend(Element._attributeTranslations.values, {
  1284. href: Element._attributeTranslations.values._getAttr,
  1285. src: Element._attributeTranslations.values._getAttr,
  1286. disabled: Element._attributeTranslations.values._flag,
  1287. checked: Element._attributeTranslations.values._flag,
  1288. readonly: Element._attributeTranslations.values._flag,
  1289. multiple: Element._attributeTranslations.values._flag
  1290. });
  1291. Element.Methods.Simulated = {
  1292. hasAttribute: function(element, attribute) {
  1293. var t = Element._attributeTranslations;
  1294. attribute = t.names[attribute] || attribute;
  1295. return $(element).getAttributeNode(attribute).specified;
  1296. }
  1297. };
  1298. // IE is missing .innerHTML support for TABLE-related elements
  1299. if (document.all && !window.opera){
  1300. Element.Methods.update = function(element, html) {
  1301. element = $(element);
  1302. html = typeof html == 'undefined' ? '' : html.toString();
  1303. var tagName = element.tagName.toUpperCase();
  1304. if (['THEAD','TBODY','TR','TD'].include(tagName)) {
  1305. var div = document.createElement('div');
  1306. switch (tagName) {
  1307. case 'THEAD':
  1308. case 'TBODY':
  1309. div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>';
  1310. depth = 2;
  1311. break;
  1312. case 'TR':
  1313. div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>';
  1314. depth = 3;
  1315. break;
  1316. case 'TD':
  1317. div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>';
  1318. depth = 4;
  1319. }
  1320. $A(element.childNodes).each(function(node){
  1321. element.removeChild(node)
  1322. });
  1323. depth.times(function(){ div = div.firstChild });
  1324. $A(div.childNodes).each(
  1325. function(node){ element.appendChild(node) });
  1326. } else {
  1327. element.innerHTML = html.stripScripts();
  1328. }
  1329. setTimeout(function() {html.evalScripts()}, 10);
  1330. return element;
  1331. }
  1332. };
  1333. Object.extend(Element, Element.Methods);
  1334. var _nativeExtensions = false;
  1335. if(/Konqueror|Safari|KHTML/.test(navigator.userAgent))
  1336. ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) {
  1337. var className = 'HTML' + tag + 'Element';
  1338. if(window[className]) return;
  1339. var klass = window[className] = {};
  1340. klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__;
  1341. });
  1342. Element.addMethods = function(methods) {
  1343. Object.extend(Element.Methods, methods || {});
  1344. function copy(methods, destination, onlyIfAbsent) {
  1345. onlyIfAbsent = onlyIfAbsent || false;
  1346. var cache = Element.extend.cache;
  1347. for (var property in methods) {
  1348. var value = methods[property];
  1349. if (!onlyIfAbsent || !(property in destination))
  1350. destination[property] = cache.findOrStore(value);
  1351. }
  1352. }
  1353. if (typeof HTMLElement != 'undefined') {
  1354. copy(Element.Methods, HTMLElement.prototype);
  1355. copy(Element.Methods.Simulated, HTMLElement.prototype, true);
  1356. copy(Form.Methods, HTMLFormElement.prototype);
  1357. [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
  1358. copy(Form.Element.Methods, klass.prototype);
  1359. });
  1360. _nativeExtensions = true;
  1361. }
  1362. }
  1363. var Toggle = new Object();
  1364. Toggle.display = Element.toggle;
  1365. /*--------------------------------------------------------------------------*/
  1366. Abstract.Insertion = function(adjacency) {
  1367. this.adjacency = adjacency;
  1368. }
  1369. Abstract.Insertion.prototype = {
  1370. initialize: function(element, content) {
  1371. this.element = $(element);
  1372. this.content = content.stripScripts();
  1373. if (this.adjacency && this.element.insertAdjacentHTML) {
  1374. try {
  1375. this.element.insertAdjacentHTML(this.adjacency, this.content);
  1376. } catch (e) {
  1377. var tagName = this.element.tagName.toUpperCase();
  1378. if (['TBODY', 'TR'].include(tagName)) {
  1379. this.insertContent(this.contentFromAnonymousTable());
  1380. } else {
  1381. throw e;
  1382. }
  1383. }
  1384. } else {
  1385. this.range = this.element.ownerDocument.createRange();
  1386. if (this.initializeRange) this.initializeRange();
  1387. this.insertContent([this.range.createContextualFragment(this.content)]);
  1388. }
  1389. setTimeout(function() {content.evalScripts()}, 10);
  1390. },
  1391. contentFromAnonymousTable: function() {
  1392. var div = document.createElement('div');
  1393. div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
  1394. return $A(div.childNodes[0].childNodes[0].childNodes);
  1395. }
  1396. }
  1397. var Insertion = new Object();
  1398. Insertion.Before = Class.create();
  1399. Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
  1400. initializeRange: function() {
  1401. this.range.setStartBefore(this.element);
  1402. },
  1403. insertContent: function(fragments) {
  1404. fragments.each((function(fragment) {
  1405. this.element.parentNode.insertBefore(fragment, this.element);
  1406. }).bind(this));
  1407. }
  1408. });
  1409. Insertion.Top = Class.create();
  1410. Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
  1411. initializeRange: function() {
  1412. this.range.selectNodeContents(this.element);
  1413. this.range.collapse(true);
  1414. },
  1415. insertContent: function(fragments) {
  1416. fragments.reverse(false).each((function(fragment) {
  1417. this.element.insertBefore(fragment, this.element.firstChild);
  1418. }).bind(this));
  1419. }
  1420. });
  1421. Insertion.Bottom = Class.create();
  1422. Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
  1423. initializeRange: function() {
  1424. this.range.selectNodeContents(this.element);
  1425. this.range.collapse(this.element);
  1426. },
  1427. insertContent: function(fragments) {
  1428. fragments.each((function(fragment) {
  1429. this.element.appendChild(fragment);
  1430. }).bind(this));
  1431. }
  1432. });
  1433. Insertion.After = Class.create();
  1434. Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
  1435. initializeRange: function() {
  1436. this.range.setStartAfter(this.element);
  1437. },
  1438. insertContent: function(fragments) {
  1439. fragments.each((function(fragment) {
  1440. this.element.parentNode.insertBefore(fragment,
  1441. this.element.nextSibling);
  1442. }).bind(this));
  1443. }
  1444. });
  1445. /*--------------------------------------------------------------------------*/
  1446. Element.ClassNames = Class.create();
  1447. Element.ClassNames.prototype = {
  1448. initialize: function(element) {
  1449. this.element = $(element);
  1450. },
  1451. _each: function(iterator) {
  1452. this.element.className.split(/\s+/).select(function(name) {
  1453. return name.length > 0;
  1454. })._each(iterator);
  1455. },
  1456. set: function(className) {
  1457. this.element.className = className;
  1458. },
  1459. add: function(classNameToAdd) {
  1460. if (this.include(classNameToAdd)) return;
  1461. this.set($A(this).concat(classNameToAdd).join(' '));
  1462. },
  1463. remove: function(classNameToRemove) {
  1464. if (!this.include(classNameToRemove)) return;
  1465. this.set($A(this).without(classNameToRemove).join(' '));
  1466. },
  1467. toString: function() {
  1468. return $A(this).join(' ');
  1469. }
  1470. };
  1471. Object.extend(Element.ClassNames.prototype, Enumerable);
  1472. var Selector = Class.create();
  1473. Selector.prototype = {
  1474. initialize: function(expression) {
  1475. this.params = {classNames: []};
  1476. this.expression = expression.toString().strip();
  1477. this.parseExpression();
  1478. this.compileMatcher();
  1479. },
  1480. parseExpression: function() {
  1481. function abort(message) { throw 'Parse error in selector: ' + message; }
  1482. if (this.expression == '') abort('empty expression');
  1483. var params = this.params, expr = this.expression, match, modifier, clause, rest;
  1484. while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
  1485. params.attributes = params.attributes || [];
  1486. params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
  1487. expr = match[1];
  1488. }
  1489. if (expr == '*') return this.params.wildcard = true;
  1490. while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
  1491. modifier = match[1], clause = match[2], rest = match[3];
  1492. switch (modifier) {
  1493. case '#': params.id = clause; break;
  1494. case '.': params.classNames.push(clause); break;
  1495. case '':
  1496. case undefined: params.tagName = clause.toUpperCase(); break;
  1497. default: abort(expr.inspect());
  1498. }
  1499. expr = rest;
  1500. }
  1501. if (expr.length > 0) abort(expr.inspect());
  1502. },
  1503. buildMatchExpression: function() {
  1504. var params = this.params, conditions = [], clause;
  1505. if (params.wildcard)
  1506. conditions.push('true');
  1507. if (clause = params.id)
  1508. conditions.push('element.readAttribute("id") == ' + clause.inspect());
  1509. if (clause = params.tagName)
  1510. conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
  1511. if ((clause = params.classNames).length > 0)
  1512. for (var i = 0, length = clause.length; i < length; i++)
  1513. conditions.push('element.hasClassName(' + clause[i].inspect() + ')');
  1514. if (clause = params.attributes) {
  1515. clause.each(function(attribute) {
  1516. var value = 'element.readAttribute(' + attribute.name.inspect() + ')';
  1517. var splitValueBy = function(delimiter) {
  1518. return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
  1519. }
  1520. switch (attribute.operator) {
  1521. case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break;
  1522. case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
  1523. case '|=': conditions.push(
  1524. splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
  1525. ); break;
  1526. case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break;
  1527. case '':
  1528. case undefined: conditions.push('element.hasAttribute(' + attribute.name.inspect() + ')'); break;
  1529. default: throw 'Unknown operator ' + attribute.operator + ' in selector';
  1530. }
  1531. });
  1532. }
  1533. return conditions.join(' && ');
  1534. },
  1535. compileMatcher: function() {
  1536. this.match = new Function('element', 'if (!element.tagName) return false; \
  1537. element = $(element); \
  1538. return ' + this.buildMatchExpression());
  1539. },
  1540. findElements: function(scope) {
  1541. var element;
  1542. if (element = $(this.params.id))
  1543. if (this.match(element))
  1544. if (!scope || Element.childOf(element, scope))
  1545. return [element];
  1546. scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
  1547. var results = [];
  1548. for (var i = 0, length = scope.length; i < length; i++)
  1549. if (this.match(element = scope[i]))
  1550. results.push(Element.extend(element));
  1551. return results;
  1552. },
  1553. toString: function() {
  1554. return this.expression;
  1555. }
  1556. }
  1557. Object.extend(Selector, {
  1558. matchElements: function(elements, expression) {
  1559. var selector = new Selector(expression);
  1560. return elements.select(selector.match.bind(selector)).map(Element.extend);
  1561. },
  1562. findElement: function(elements, expression, index) {
  1563. if (typeof expression == 'number') index = expression, expression = false;
  1564. return Selector.matchElements(elements, expression || '*')[index || 0];
  1565. },
  1566. findChildElements: function(element, expressions) {
  1567. return expressions.map(function(expression) {
  1568. return expression.match(/[^\s"]+(?:"[^"]*"[^\s"]+)*/g).inject([null], function(results, expr) {
  1569. var selector = new Selector(expr);
  1570. return results.inject([], function(elements, result) {
  1571. return elements.concat(selector.findElements(result || element));
  1572. });
  1573. });
  1574. }).flatten();
  1575. }
  1576. });
  1577. function $$() {
  1578. return Selector.findChildElements(document, $A(arguments));
  1579. }
  1580. var Form = {
  1581. reset: function(form) {
  1582. $(form).reset();
  1583. return form;
  1584. },
  1585. serializeElements: function(elements, getHash) {
  1586. var data = elements.inject({}, function(result, element) {
  1587. if (!element.disabled && element.name) {
  1588. var key = element.name, value = $(element).getValue();
  1589. if (value != undefined) {
  1590. if (result[key]) {
  1591. if (result[key].constructor != Array) result[key] = [result[key]];
  1592. result[key].push(value);
  1593. }
  1594. else result[key] = value;
  1595. }
  1596. }
  1597. return result;
  1598. });
  1599. return getHash ? data : Hash.toQueryString(data);
  1600. }
  1601. };
  1602. Form.Methods = {
  1603. serialize: function(form, getHash) {
  1604. return Form.serializeElements(Form.getElements(form), getHash);
  1605. },
  1606. getElements: function(form) {
  1607. return $A($(form).getElementsByTagName('*')).inject([],
  1608. function(elements, child) {
  1609. if (Form.Element.Serializers[child.tagName.toLowerCase()])
  1610. elements.push(Element.extend(child));
  1611. return elements;
  1612. }
  1613. );
  1614. },
  1615. getInputs: function(form, typeName, name) {
  1616. form = $(form);
  1617. var inputs = form.getElementsByTagName('input');
  1618. if (!typeName && !name) return $A(inputs).map(Element.extend);
  1619. for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
  1620. var input = inputs[i];
  1621. if ((typeName && input.type != typeName) || (name && input.name != name))
  1622. continue;
  1623. matchingInputs.push(Element.extend(input));
  1624. }
  1625. return matchingInputs;
  1626. },
  1627. disable: function(form) {
  1628. form = $(form);
  1629. form.getElements().each(function(element) {
  1630. element.blur();
  1631. element.disabled = 'true';
  1632. });
  1633. return form;
  1634. },
  1635. enable: function(form) {
  1636. form = $(form);
  1637. form.getElements().each(function(element) {
  1638. element.disabled = '';
  1639. });
  1640. return form;
  1641. },
  1642. findFirstElement: function(form) {
  1643. return $(form).getElements().find(function(element) {
  1644. return element.type != 'hidden' && !element.disabled &&
  1645. ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
  1646. });
  1647. },
  1648. focusFirstElement: function(form) {
  1649. form = $(form);
  1650. form.findFirstElement().activate();
  1651. return form;
  1652. }
  1653. }
  1654. Object.extend(Form, Form.Methods);
  1655. /*--------------------------------------------------------------------------*/
  1656. Form.Element = {
  1657. focus: function(element) {
  1658. $(element).focus();
  1659. return element;
  1660. },
  1661. select: function(element) {
  1662. $(element).select();
  1663. return element;
  1664. }
  1665. }
  1666. Form.Element.Methods = {
  1667. serialize: function(element) {
  1668. element = $(element);
  1669. if (!element.disabled && element.name) {
  1670. var value = element.getValue();
  1671. if (value != undefined) {
  1672. var pair = {};
  1673. pair[element.name] = value;
  1674. return Hash.toQueryString(pair);
  1675. }
  1676. }
  1677. return '';
  1678. },
  1679. getValue: function(element) {
  1680. element = $(element);
  1681. var method = element.tagName.toLowerCase();
  1682. return Form.Element.Serializers[method](element);
  1683. },
  1684. clear: function(element) {
  1685. $(element).value = '';
  1686. return element;
  1687. },
  1688. present: function(element) {
  1689. return $(element).value != '';
  1690. },
  1691. activate: function(element) {
  1692. element = $(element);
  1693. element.focus();
  1694. if (element.select && ( element.tagName.toLowerCase() != 'input' ||
  1695. !['button', 'reset', 'submit'].include(element.type) ) )
  1696. element.select();
  1697. return element;
  1698. },
  1699. disable: function(element) {
  1700. element = $(element);
  1701. element.disabled = true;
  1702. return element;
  1703. },
  1704. enable: function(element) {
  1705. element = $(element);
  1706. element.blur();
  1707. element.disabled = false;
  1708. return element;
  1709. }
  1710. }
  1711. Object.extend(Form.Element, Form.Element.Methods);
  1712. var Field = Form.Element;
  1713. var $F = Form.Element.getValue;
  1714. /*--------------------------------------------------------------------------*/
  1715. Form.Element.Serializers = {
  1716. input: function(element) {
  1717. switch (element.type.toLowerCase()) {
  1718. case 'checkbox':
  1719. case 'radio':
  1720. return Form.Element.Serializers.inputSelector(element);
  1721. default:
  1722. return Form.Element.Serializers.textarea(element);
  1723. }
  1724. },
  1725. inputSelector: function(element) {
  1726. return element.checked ? element.value : null;
  1727. },
  1728. textarea: function(element) {
  1729. return element.value;
  1730. },
  1731. select: function(element) {
  1732. return this[element.type == 'select-one' ?
  1733. 'selectOne' : 'selectMany'](element);
  1734. },
  1735. selectOne: function(element) {
  1736. var index = element.selectedIndex;
  1737. return index >= 0 ? this.optionValue(element.options[index]) : null;
  1738. },
  1739. selectMany: function(element) {
  1740. var values, length = element.length;
  1741. if (!length) return null;
  1742. for (var i = 0, values = []; i < length; i++) {
  1743. var opt = element.options[i];
  1744. if (opt.selected) values.push(this.optionValue(opt));
  1745. }
  1746. return values;
  1747. },
  1748. optionValue: function(opt) {
  1749. // extend element because hasAttribute may not be native
  1750. return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
  1751. }
  1752. }
  1753. /*--------------------------------------------------------------------------*/
  1754. Abstract.TimedObserver = function() {}
  1755. Abstract.TimedObserver.prototype = {
  1756. initialize: function(element, frequency, callback) {
  1757. this.frequency = frequency;
  1758. this.element = $(element);
  1759. this.callback = callback;
  1760. this.lastValue = this.getValue();
  1761. this.registerCallback();
  1762. },
  1763. registerCallback: function() {
  1764. setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  1765. },
  1766. onTimerEvent: function() {
  1767. var value = this.getValue();
  1768. var changed = ('string' == typeof this.lastValue && 'string' == typeof value
  1769. ? this.lastValue != value : String(this.lastValue) != String(value));
  1770. if (changed) {
  1771. this.callback(this.element, value);
  1772. this.lastValue = value;
  1773. }
  1774. }
  1775. }
  1776. Form.Element.Observer = Class.create();
  1777. Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
  1778. getValue: function() {
  1779. return Form.Element.getValue(this.element);
  1780. }
  1781. });
  1782. Form.Observer = Class.create();
  1783. Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
  1784. getValue: function() {
  1785. return Form.serialize(this.element);
  1786. }
  1787. });
  1788. /*--------------------------------------------------------------------------*/
  1789. Abstract.EventObserver = function() {}
  1790. Abstract.EventObserver.prototype = {
  1791. initialize: function(element, callback) {
  1792. this.element = $(element);
  1793. this.callback = callback;
  1794. this.lastValue = this.getValue();
  1795. if (this.element.tagName.toLowerCase() == 'form')
  1796. this.registerFormCallbacks();
  1797. else
  1798. this.registerCallback(this.element);
  1799. },
  1800. onElementEvent: function() {
  1801. var value = this.getValue();
  1802. if (this.lastValue != value) {
  1803. this.callback(this.element, value);
  1804. this.lastValue = value;
  1805. }
  1806. },
  1807. registerFormCallbacks: function() {
  1808. Form.getElements(this.element).each(this.registerCallback.bind(this));
  1809. },
  1810. registerCallback: function(element) {
  1811. if (element.type) {
  1812. switch (element.type.toLowerCase()) {
  1813. case 'checkbox':
  1814. case 'radio':
  1815. Event.observe(element, 'click', this.onElementEvent.bind(this));
  1816. break;
  1817. default:
  1818. Event.observe(element, 'change', this.onElementEvent.bind(this));
  1819. break;
  1820. }
  1821. }
  1822. }
  1823. }
  1824. Form.Element.EventObserver = Class.create();
  1825. Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
  1826. getValue: function() {
  1827. return Form.Element.getValue(this.element);
  1828. }
  1829. });
  1830. Form.EventObserver = Class.create();
  1831. Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
  1832. getValue: function() {
  1833. return Form.serialize(this.element);
  1834. }
  1835. });
  1836. if (!window.Event) {
  1837. var Event = new Object();
  1838. }
  1839. Object.extend(Event, {
  1840. KEY_BACKSPACE: 8,
  1841. KEY_TAB: 9,
  1842. KEY_RETURN: 13,
  1843. KEY_ESC: 27,
  1844. KEY_LEFT: 37,
  1845. KEY_UP: 38,
  1846. KEY_RIGHT: 39,
  1847. KEY_DOWN: 40,
  1848. KEY_DELETE: 46,
  1849. KEY_HOME: 36,
  1850. KEY_END: 35,
  1851. KEY_PAGEUP: 33,
  1852. KEY_PAGEDOWN: 34,
  1853. element: function(event) {
  1854. return event.target || event.srcElement;
  1855. },
  1856. isLeftClick: function(event) {
  1857. return (((event.which) && (event.which == 1)) ||
  1858. ((event.button) && (event.button == 1)));
  1859. },
  1860. pointerX: function(event) {
  1861. return event.pageX || (event.clientX +
  1862. (document.documentElement.scrollLeft || document.body.scrollLeft));
  1863. },
  1864. pointerY: function(event) {
  1865. return event.pageY || (event.clientY +
  1866. (document.documentElement.scrollTop || document.body.scrollTop));
  1867. },
  1868. stop: function(event) {
  1869. if (event.preventDefault) {
  1870. event.preventDefault();
  1871. event.stopPropagation();
  1872. } else {
  1873. event.returnValue = false;
  1874. event.cancelBubble = true;
  1875. }
  1876. },
  1877. // find the first node with the given tagName, starting from the
  1878. // node the event was triggered on; traverses the DOM upwards
  1879. findElement: function(event, tagName) {
  1880. var element = Event.element(event);
  1881. while (element.parentNode && (!element.tagName ||
  1882. (element.tagName.toUpperCase() != tagName.toUpperCase())))
  1883. element = element.parentNode;
  1884. return element;
  1885. },
  1886. observers: false,
  1887. _observeAndCache: function(element, name, observer, useCapture) {
  1888. if (!this.observers) this.observers = [];
  1889. if (element.addEventListener) {
  1890. this.observers.push([element, name, observer, useCapture]);
  1891. element.addEventListener(name, observer, useCapture);
  1892. } else if (element.attachEvent) {
  1893. this.observers.push([element, name, observer, useCapture]);
  1894. element.attachEvent('on' + name, observer);
  1895. }
  1896. },
  1897. unloadCache: function() {
  1898. if (!Event.observers) return;
  1899. for (var i = 0, length = Event.observers.length; i < length; i++) {
  1900. Event.stopObserving.apply(this, Event.observers[i]);
  1901. Event.observers[i][0] = null;
  1902. }
  1903. Event.observers = false;
  1904. },
  1905. observe: function(element, name, observer, useCapture) {
  1906. element = $(element);
  1907. useCapture = useCapture || false;
  1908. if (name == 'keypress' &&
  1909. (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
  1910. || element.attachEvent))
  1911. name = 'keydown';
  1912. Event._observeAndCache(element, name, observer, useCapture);
  1913. },
  1914. stopObserving: function(element, name, observer, useCapture) {
  1915. element = $(element);
  1916. useCapture = useCapture || false;
  1917. if (name == 'keypress' &&
  1918. (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
  1919. || element.detachEvent))
  1920. name = 'keydown';
  1921. if (element.removeEventListener) {
  1922. element.removeEventListener(name, observer, useCapture);
  1923. } else if (element.detachEvent) {
  1924. try {
  1925. element.detachEvent('on' + name, observer);
  1926. } catch (e) {}
  1927. }
  1928. }
  1929. });
  1930. /* prevent memory leaks in IE */
  1931. if (navigator.appVersion.match(/\bMSIE\b/))
  1932. Event.observe(window, 'unload', Event.unloadCache, false);
  1933. var Position = {
  1934. // set to true if needed, warning: firefox performance problems
  1935. // NOT neeeded for page scrolling, only if draggable contained in
  1936. // scrollable elements
  1937. includeScrollOffsets: false,
  1938. // must be called before calling withinIncludingScrolloffset, every time the
  1939. // page is scrolled
  1940. prepare: function() {
  1941. this.deltaX = window.pageXOffset
  1942. || document.documentElement.scrollLeft
  1943. || document.body.scrollLeft
  1944. || 0;
  1945. this.deltaY = window.pageYOffset
  1946. || document.documentElement.scrollTop
  1947. || document.body.scrollTop
  1948. || 0;
  1949. },
  1950. realOffset: function(element) {
  1951. var valueT = 0, valueL = 0;
  1952. do {
  1953. valueT += element.scrollTop || 0;
  1954. valueL += element.scrollLeft || 0;
  1955. element = element.parentNode;
  1956. } while (element);
  1957. return [valueL, valueT];
  1958. },
  1959. cumulativeOffset: function(element) {
  1960. var valueT = 0, valueL = 0;
  1961. do {
  1962. valueT += element.offsetTop || 0;
  1963. valueL += element.offsetLeft || 0;
  1964. element = element.offsetParent;
  1965. } while (element);
  1966. return [valueL, valueT];
  1967. },
  1968. positionedOffset: function(element) {
  1969. var valueT = 0, valueL = 0;
  1970. do {
  1971. valueT += element.offsetTop || 0;
  1972. valueL += element.offsetLeft || 0;
  1973. element = element.offsetParent;
  1974. if (element) {