PageRenderTime 54ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/admin/thirdparty/history-js/vendor/right.js

http://github.com/silverstripe/sapphire
JavaScript | 2666 lines | 1210 code | 330 blank | 1126 comment | 227 complexity | b736a81be95e4c0389dca3bf2bc54edd MD5 | raw file
Possible License(s): BSD-3-Clause, MIT, CC-BY-3.0, GPL-2.0, AGPL-1.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. /**
  2. * RightJS v2.2.3 - http://rightjs.org
  3. * Released under the terms of MIT license
  4. *
  5. * Copyright (C) 2008-2011 Nikolay Nemshilov
  6. */
  7. /**
  8. * The basic layout for RightJS builds
  9. *
  10. * Copyright (C) 2008-2011 Nikolay Nemshilov
  11. */
  12. var RightJS = (function(window, document, Object, Array, String, Function, Number, Math, undefined) {
  13. /**
  14. * The framework description object
  15. *
  16. * Copyright (C) 2008-2011 Nikolay Nemshilov
  17. */
  18. var RightJS = function(value) {
  19. return value; // <- a dummy method to emulate the safe-mode
  20. };
  21. RightJS.version = "2.2.3";
  22. RightJS.modules =["core", "dom", "form", "events", "xhr", "fx", "cookie"];
  23. /**
  24. * There are some util methods
  25. *
  26. * Credits:
  27. * Some of the functionality and names are inspired or copied from
  28. * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
  29. * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
  30. *
  31. * Copyright (C) 2008-2011 Nikolay V. Nemshilov
  32. */
  33. /**
  34. * Some top-level variables to shortify the things
  35. */
  36. var A_proto = Array.prototype,
  37. to_s = Object.prototype.toString, slice = A_proto.slice,
  38. HTML = document.documentElement, UID = 1, // !#server
  39. Wrappers_Cache = [], UID_KEY = 'uniqueNumber', // DON'T change the UID_KEY!
  40. /**
  41. * extends the first object with the keys and values of the second one
  42. *
  43. * NOTE: the third optional argument tells if the existing values
  44. * of the first object should _NOT_ get updated by the values of the second object
  45. *
  46. * @param oritinal Object destintation object
  47. * @param source Object source object
  48. * @param Boolean flag if the function should not overwrite intersecting values
  49. * @return Object extended destination object
  50. */
  51. $ext = RightJS.$ext = function(dest, source, dont_overwrite) {
  52. var src = source || {}, key;
  53. for (key in src) {
  54. if (!dont_overwrite || !(key in dest)) {
  55. dest[key] = src[key];
  56. }
  57. }
  58. return dest;
  59. },
  60. /** !#server
  61. * evals the given javascript text in the context of the current window
  62. *
  63. * @param String javascript
  64. * @return void
  65. */
  66. $eval = RightJS.$eval = function(text) {
  67. if (text) {
  68. if ('execScript' in window) {
  69. current_Document.win()._.execScript(text);
  70. } else {
  71. $E('script', {text: text}).insertTo(HTML);
  72. }
  73. }
  74. },
  75. /**
  76. * throws an exception to break iterations throw a callback
  77. *
  78. * @return void
  79. * @throws Break
  80. */
  81. $break = RightJS.$break = function() {
  82. throw new Break();
  83. },
  84. /**
  85. * generates aliases for the object properties
  86. *
  87. * @param object Object object
  88. * @param names Object aliases hash
  89. * @return Object the extended objects
  90. */
  91. $alias = RightJS.$alias = function(object, names) {
  92. for (var new_name in names) {
  93. object[new_name] = object[names[new_name]];
  94. }
  95. return object;
  96. },
  97. /**
  98. * checks if the given value or a reference points
  99. * to a really defined value
  100. *
  101. * NOTE: will return true for variables equal to null, false, 0, and so one.
  102. *
  103. * EXAMPLE:
  104. *
  105. * var smth = null;
  106. * defined(smth); <- will return true
  107. *
  108. * var obj = {};
  109. * defined(obj['smth']); <- will return false
  110. *
  111. * @param mixed value
  112. * @return boolean check result
  113. */
  114. defined = RightJS.defined = function(value) {
  115. return typeof(value) !== 'undefined';
  116. },
  117. /**
  118. * checks if the given value is a function
  119. *
  120. * @param mixed value
  121. * @return boolean check result
  122. */
  123. isFunction = RightJS.isFunction = function(value) {
  124. return typeof(value) === 'function';
  125. },
  126. /**
  127. * checks if the given value is a string
  128. *
  129. * @param mixed value
  130. * @return boolean check result
  131. */
  132. isString = RightJS.isString = function(value) {
  133. return typeof(value) === 'string';
  134. },
  135. /**
  136. * checks if the given value is a number
  137. *
  138. * @param mixed value to check
  139. * @return boolean check result
  140. */
  141. isNumber = RightJS.isNumber = function(value) {
  142. return typeof(value) === 'number';
  143. },
  144. /**
  145. * checks if the given value is a hash-like object
  146. *
  147. * @param mixed value
  148. * @return boolean check result
  149. */
  150. isHash = RightJS.isHash = function(value) {
  151. return to_s.call(value) === '[object Object]';
  152. },
  153. /**
  154. * checks if the given value is an array
  155. *
  156. * @param mixed value to check
  157. * @return boolean check result
  158. */
  159. isArray = RightJS.isArray = function(value) {
  160. return to_s.call(value) === '[object Array]';
  161. },
  162. /** !#server
  163. * checks if the given value is an element
  164. *
  165. * @param mixed value to check
  166. * @return boolean check result
  167. */
  168. isElement = RightJS.isElement = function(value) {
  169. return value != null && value.nodeType === 1;
  170. },
  171. /** !#server
  172. * checks if the given value is a DOM-node
  173. *
  174. * @param mixed value to check
  175. * @return boolean check result
  176. */
  177. isNode = RightJS.isNode = function(value) {
  178. return value != null && value.nodeType != null;
  179. },
  180. /** !#server
  181. * searches an element by id and/or extends it with the framework extentions
  182. *
  183. * @param String element id or Element to extend
  184. * @return Element or null
  185. */
  186. $ = RightJS.$ = function(object) {
  187. if (object instanceof Wrapper) {
  188. return object;
  189. } else if (typeof object === 'string') {
  190. object = document.getElementById(object);
  191. }
  192. return wrap(object);
  193. },
  194. /** !#server
  195. * Finds all the elements in the document by the given css_rule
  196. *
  197. * @param String element
  198. * @param Boolean raw search marker
  199. * @return Array search result
  200. */
  201. $$ = RightJS.$$ = function(css_rule, raw) {
  202. return current_Document.find(css_rule, raw);
  203. },
  204. /** !#server
  205. * shortcut to instance new elements
  206. *
  207. * @param String tag name
  208. * @param object options
  209. * @return Element instance
  210. */
  211. $E = RightJS.$E = function(tag_name, options) {
  212. return new Element(tag_name, options);
  213. },
  214. /**
  215. * shortcut, generates an array of words from a given string
  216. *
  217. * @param String string
  218. * @return Array of words
  219. */
  220. $w = RightJS.$w = function(string) {
  221. return string.trim().split(/\s+/);
  222. },
  223. /**
  224. * generates an unique id for an object
  225. *
  226. * @param Object object
  227. * @return Integer uniq id
  228. */
  229. $uid = RightJS.$uid = function(item) {
  230. return UID_KEY in item ? item[UID_KEY] : (item[UID_KEY] = UID++);
  231. },
  232. /**
  233. * converts any iterables into an array
  234. *
  235. * @param Object iterable
  236. * @return Array list
  237. */
  238. $A = RightJS.$A = function(it) {
  239. return slice.call(it, 0);
  240. };
  241. /** !#server
  242. * IE needs a patch for the $A function
  243. * because it doesn't handle all the cases
  244. */
  245. if (!A_proto.map) {
  246. $A = RightJS.$A = function(it) {
  247. try {
  248. return slice.call(it, 0);
  249. } catch(e) {
  250. for (var a=[], i=0, length = it.length; i < length; i++) {
  251. a[i] = it[i];
  252. }
  253. return a;
  254. }
  255. };
  256. }
  257. /** !#server
  258. * Internet Explorer needs some additional mumbo-jumbo in here
  259. */
  260. if (isHash(HTML)) {
  261. isHash = RightJS.isHash = function(value) {
  262. return to_s.call(value) === '[object Object]' &&
  263. value != null && value.hasOwnProperty != null;
  264. };
  265. }
  266. /**
  267. * Generating methods for native units extending
  268. */
  269. // adds a standard '.include' method to the native unit
  270. function extend_native(klass) {
  271. return $ext(klass, {
  272. Methods: {},
  273. include: function() {
  274. for (var i=0, l = arguments.length; i < l; i++) {
  275. if (isHash(arguments[i])) {
  276. $ext(klass.prototype, arguments[i]);
  277. $ext(klass.Methods, arguments[i]);
  278. }
  279. }
  280. }
  281. });
  282. }
  283. for (var i=0, natives = 'Array Function Number String Date RegExp'.split(' '); i < natives.length; i++) {
  284. RightJS[natives[i]] = extend_native(new Function('return '+ natives[i])());
  285. }
  286. // referring those two as well
  287. RightJS.Object = Object;
  288. RightJS.Math = Math;
  289. /**
  290. * Checks if the data is an array and if not,
  291. * then makes an array out of it
  292. *
  293. * @param mixed in data
  294. * @return Array data
  295. */
  296. function ensure_array(data) {
  297. return isArray(data) ? data : [data];
  298. }
  299. /**
  300. * The Object class extentions
  301. *
  302. * Credits:
  303. * Some functionality is inspired by
  304. * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
  305. *
  306. * Copyright (C) 2008-2011 Nikolay V. Nemshilov
  307. */
  308. $ext(Object, {
  309. /**
  310. * extracts the list of the attribute names of the given object
  311. *
  312. * @param Object object
  313. * @return Array keys list
  314. */
  315. keys: function(object) {
  316. var keys = [], key;
  317. for (key in object) {
  318. keys.push(key);
  319. }
  320. return keys;
  321. },
  322. /**
  323. * extracts the list of the attribute values of the given object
  324. *
  325. * @param Object object
  326. * @return Array values list
  327. */
  328. values: function(object) {
  329. var values = [], key;
  330. for (key in object) {
  331. values.push(object[key]);
  332. }
  333. return values;
  334. },
  335. /**
  336. * Calls the function with every key/value pair on the hash
  337. *
  338. * @param in Object the data hash
  339. * @param Function the callback
  340. * @param scope Object an optional scope
  341. * @return Object the original hash
  342. */
  343. each: function(object, callback, scope) {
  344. for (var key in object) {
  345. callback.call(scope, key, object[key]);
  346. }
  347. return object;
  348. },
  349. /**
  350. * checks if the object-hash has no keys
  351. *
  352. * @param Object object
  353. * @return check result
  354. */
  355. empty: function(object) {
  356. for (var key in object) { return false; }
  357. return true;
  358. },
  359. /**
  360. * A simple cloning method
  361. * NOTE: does not clone the things recoursively!
  362. *
  363. * @param Object object
  364. * @return Object clone
  365. */
  366. clone: function(object) {
  367. return Object.merge(object);
  368. },
  369. /**
  370. * returns a copy of the object which contains
  371. * all the same keys/values except the key-names
  372. * passed the the method arguments
  373. *
  374. * @param Object object
  375. * @param String key-name to exclude
  376. * .....
  377. * @return Object filtered copy
  378. */
  379. without: function() {
  380. var filter = $A(arguments), object = filter.shift(), copy = {}, key;
  381. for (key in object) {
  382. if (!filter.include(key)) {
  383. copy[key] = object[key];
  384. }
  385. }
  386. return copy;
  387. },
  388. /**
  389. * returns a copy of the object which contains all the
  390. * key/value pairs from the specified key-names list
  391. *
  392. * NOTE: if some key does not exists in the original object, it will be just skipped
  393. *
  394. * @param Object object
  395. * @param String key name to exclude
  396. * .....
  397. * @return Object filtered copy
  398. */
  399. only: function() {
  400. var filter = $A(arguments), object = filter.shift(), copy = {},
  401. i=0, length = filter.length;
  402. for (; i < length; i++) {
  403. if (filter[i] in object) {
  404. copy[filter[i]] = object[filter[i]];
  405. }
  406. }
  407. return copy;
  408. },
  409. /**
  410. * merges the given objects and returns the result
  411. *
  412. * NOTE this method _DO_NOT_ change the objects, it creates a new object
  413. * which conatins all the given ones.
  414. * if there is some keys introspections, the last object wins.
  415. * all non-object arguments will be omitted
  416. *
  417. * @param first Object object
  418. * @param second Object mixing
  419. * ......
  420. * @return Object merged object
  421. */
  422. merge: function() {
  423. var object = {}, i=0, args=arguments, key;
  424. for (l = args.length; i < l; i++) {
  425. if (isHash(args[i])) {
  426. for (key in args[i]) {
  427. object[key] = isHash(args[i][key]) && !(args[i][key] instanceof Class) ?
  428. Object.merge(key in object ? object[key] : {}, args[i][key]) : args[i][key];
  429. }
  430. }
  431. }
  432. return object;
  433. },
  434. /**
  435. * converts a hash-object into an equivalent url query string
  436. *
  437. * @param Object object
  438. * @return String query
  439. */
  440. toQueryString: function(object) {
  441. var tokens = [], key, value, encode = encodeURIComponent;
  442. for (key in object) {
  443. value = ensure_array(object[key]);
  444. for (var i=0, l = value.length; i < l; i++) {
  445. tokens.push(encode(key) +'='+ encode(value[i]));
  446. }
  447. }
  448. return tokens.join('&');
  449. }
  450. }, true);
  451. /**
  452. * here are the starndard Math object extends
  453. *
  454. * Credits:
  455. * The idea of random mehtod is taken from
  456. * - Ruby (http://www.ruby-lang.org) Copyright (C) Yukihiro Matsumoto
  457. *
  458. * Copyright (C) 2008-2010 Nikolay Nemshilov
  459. */
  460. var Math_old_random = Math.random;
  461. /**
  462. * the standard random method replacement, to make it more useful
  463. *
  464. * USE:
  465. * Math.random(); // original functionality, returns a float between 0 and 1
  466. * Math.random(10); // returns an integer between 0 and 10
  467. * Math.random(1,4); // returns an integer between 1 and 4
  468. *
  469. * @param min Integer minimum value if there's two arguments and maximum value if there's only one
  470. * @param max Integer maximum value
  471. * @return Float random between 0 and 1 if there's no arguments or an integer in the given range
  472. */
  473. Math.random = function(min, max) {
  474. if (arguments.length === 0) {
  475. return Math_old_random();
  476. } else if (arguments.length === 1) {
  477. max = min;
  478. min = 0;
  479. }
  480. return ~~(Math_old_random() * (max-min+1) + ~~min);
  481. };
  482. /**
  483. * The Array class extentions
  484. *
  485. * Credits:
  486. * Some of the functionality is inspired by
  487. * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
  488. * - Ruby (http://www.ruby-lang.org) Copyright (C) Yukihiro Matsumoto
  489. *
  490. * Copyright (C) 2008-2010 Nikolay Nemshilov
  491. */
  492. var original_sort = A_proto.sort,
  493. // JavaScript 1.6 methods recatching up or faking
  494. for_each = A_proto.forEach || function(callback, scope) {
  495. for (var i=0, l=this.length; i < l; i++) {
  496. callback.call(scope, this[i], i, this);
  497. }
  498. },
  499. filter = A_proto.filter || function(callback, scope) {
  500. for (var result=[], j=0, i=0, l=this.length; i < l; i++) {
  501. if (callback.call(scope, this[i], i, this)) {
  502. result[j++] = this[i];
  503. }
  504. }
  505. return result;
  506. },
  507. reject = function(callback, scope) {
  508. for (var result=[], j=0, i=0, l=this.length; i < l; i++) {
  509. if (!callback.call(scope, this[i], i, this)) {
  510. result[j++] = this[i];
  511. }
  512. }
  513. return result;
  514. },
  515. map = A_proto.map || function(callback, scope) {
  516. for (var result=[], i=0, l=this.length; i < l; i++) {
  517. result[i] = callback.call(scope, this[i], i, this);
  518. }
  519. return result;
  520. },
  521. some = A_proto.some || function(callback, scope) {
  522. for (var i=0, l=this.length; i < l; i++) {
  523. if (callback.call(scope, this[i], i, this)) {
  524. return true;
  525. }
  526. }
  527. return false;
  528. },
  529. every = A_proto.every || function(callback, scope) {
  530. for (var i=0, l=this.length; i < l; i++) {
  531. if (!callback.call(scope, this[i], i, this)) {
  532. return false;
  533. }
  534. }
  535. return true;
  536. },
  537. first = function(callback, scope) {
  538. for (var i=0, l=this.length; i < l; i++) {
  539. if (callback.call(scope, this[i], i, this)) {
  540. return this[i];
  541. }
  542. }
  543. return undefined;
  544. },
  545. last = function(callback, scope) {
  546. for (var i=this.length-1; i > -1; i--) {
  547. if (callback.call(scope, this[i], i, this)) {
  548. return this[i];
  549. }
  550. }
  551. return undefined;
  552. };
  553. //
  554. // RightJS callbacks magick preprocessing
  555. //
  556. // prepares a correct callback function
  557. function guess_callback(argsi, array) {
  558. var callback = argsi[0], args = slice.call(argsi, 1), scope = array, attr;
  559. if (typeof(callback) === 'string') {
  560. attr = callback;
  561. if (array.length !== 0 && typeof(array[0][attr]) === 'function') {
  562. callback = function(object) { return object[attr].apply(object, args); };
  563. } else {
  564. callback = function(object) { return object[attr]; };
  565. }
  566. } else {
  567. scope = args[0];
  568. }
  569. return [callback, scope];
  570. }
  571. // defining the manual break errors class
  572. function Break() {}
  573. // calls the given method with preprocessing the arguments
  574. function call_method(func, scope, args) {
  575. try {
  576. return func.apply(scope, guess_callback(args, scope));
  577. } catch(e) { if (!(e instanceof Break)) { throw(e); } }
  578. return undefined;
  579. }
  580. // checks the value as a boolean
  581. function boolean_check(i) {
  582. return !!i;
  583. }
  584. // default sorting callback
  585. function default_sort(a, b) {
  586. return a > b ? 1 : a < b ? -1 : 0;
  587. }
  588. Array.include({
  589. /**
  590. * IE fix
  591. * returns the index of the value in the array
  592. *
  593. * @param mixed value
  594. * @param Integer optional offset
  595. * @return Integer index or -1 if not found
  596. */
  597. indexOf: A_proto.indexOf || function(value, from) {
  598. for (var i=(from<0) ? Math.max(0, this.length+from) : from || 0, l=this.length; i < l; i++) {
  599. if (this[i] === value) {
  600. return i;
  601. }
  602. }
  603. return -1;
  604. },
  605. /**
  606. * IE fix
  607. * returns the last index of the value in the array
  608. *
  609. * @param mixed value
  610. * @return Integer index or -1 if not found
  611. */
  612. lastIndexOf: A_proto.lastIndexOf || function(value) {
  613. for (var i=this.length-1; i > -1; i--) {
  614. if (this[i] === value) {
  615. return i;
  616. }
  617. }
  618. return -1;
  619. },
  620. /**
  621. * returns the first element of the array
  622. *
  623. * @return mixed first element of the array
  624. */
  625. first: function() {
  626. return arguments.length ? call_method(first, this, arguments) : this[0];
  627. },
  628. /**
  629. * returns the last element of the array
  630. *
  631. * @return mixed last element of the array
  632. */
  633. last: function() {
  634. return arguments.length ? call_method(last, this, arguments) : this[this.length-1];
  635. },
  636. /**
  637. * returns a random item of the array
  638. *
  639. * @return mixed a random item
  640. */
  641. random: function() {
  642. return this.length === 0 ? undefined : this[Math.random(this.length-1)];
  643. },
  644. /**
  645. * returns the array size
  646. *
  647. * @return Integer the array size
  648. */
  649. size: function() {
  650. return this.length;
  651. },
  652. /**
  653. * cleans the array
  654. * @return Array this
  655. */
  656. clean: function() {
  657. this.length = 0;
  658. return this;
  659. },
  660. /**
  661. * checks if the array has no elements in it
  662. *
  663. * @return boolean check result
  664. */
  665. empty: function() {
  666. return this.length === 0;
  667. },
  668. /**
  669. * creates a copy of the given array
  670. *
  671. * @return Array copy of the array
  672. */
  673. clone: function() {
  674. return this.slice(0);
  675. },
  676. /**
  677. * calls the given callback function in the given scope for each element of the array
  678. *
  679. * @param Function callback
  680. * @param Object scope
  681. * @return Array this
  682. */
  683. each: function() {
  684. call_method(for_each, this, arguments);
  685. return this;
  686. },
  687. forEach: for_each,
  688. /**
  689. * creates a list of the array items converted in the given callback function
  690. *
  691. * @param Function callback
  692. * @param Object optional scope
  693. * @return Array collected
  694. */
  695. map: function() {
  696. return call_method(map, this, arguments);
  697. },
  698. /**
  699. * creates a list of the array items which are matched in the given callback function
  700. *
  701. * @param Function callback
  702. * @param Object optional scope
  703. * @return Array filtered copy
  704. */
  705. filter: function() {
  706. return call_method(filter, this, arguments);
  707. },
  708. /**
  709. * creates a list of the array items that are not matching the give callback function
  710. *
  711. * @param Function callback
  712. * @param Object optionl scope
  713. * @return Array filtered copy
  714. */
  715. reject: function() {
  716. return call_method(reject, this, arguments);
  717. },
  718. /**
  719. * checks if any of the array elements is logically true
  720. *
  721. * @param Function optional callback for checks
  722. * @param Object optional scope for the callback
  723. * @return boolean check result
  724. */
  725. some: function(value) {
  726. return call_method(some, this, value ? arguments : [boolean_check]);
  727. },
  728. /**
  729. * checks if all the array elements are logically true
  730. *
  731. * @param Function optional callback for checks
  732. * @param Object optional scope for the callback
  733. * @return Boolean check result
  734. */
  735. every: function(value) {
  736. return call_method(every, this, value ? arguments : [boolean_check]);
  737. },
  738. /**
  739. * applies the given lambda to each element in the array
  740. *
  741. * NOTE: changes the array by itself
  742. *
  743. * @param Function callback
  744. * @param Object optional scope
  745. * @return Array this
  746. */
  747. walk: function() {
  748. this.map.apply(this, arguments).forEach(function(value, i) { this[i] = value; }, this);
  749. return this;
  750. },
  751. /**
  752. * similar to the concat function but it adds only the values which are not on the list yet
  753. *
  754. * @param Array to merge
  755. * ....................
  756. * @return Array new merged
  757. */
  758. merge: function() {
  759. for (var copy = this.clone(), arg, i=0; i < arguments.length; i++) {
  760. arg = ensure_array(arguments[i]);
  761. for (var j=0; j < arg.length; j++) {
  762. if (copy.indexOf(arg[j]) == -1) {
  763. copy.push(arg[j]);
  764. }
  765. }
  766. }
  767. return copy;
  768. },
  769. /**
  770. * flats out complex array into a single dimension array
  771. *
  772. * @return Array flatten copy
  773. */
  774. flatten: function() {
  775. var copy = [];
  776. this.forEach(function(value) {
  777. if (isArray(value)) {
  778. copy = copy.concat(value.flatten());
  779. } else {
  780. copy.push(value);
  781. }
  782. });
  783. return copy;
  784. },
  785. /**
  786. * returns a copy of the array whithout any null or undefined values
  787. *
  788. * @return Array filtered version
  789. */
  790. compact: function() {
  791. return this.without(null, undefined);
  792. },
  793. /**
  794. * returns a copy of the array which contains only the unique values
  795. *
  796. * @return Array filtered copy
  797. */
  798. uniq: function() {
  799. return [].merge(this);
  800. },
  801. /**
  802. * checks if all of the given values
  803. * exists in the given array
  804. *
  805. * @param mixed value
  806. * ....
  807. * @return boolean check result
  808. */
  809. includes: function() {
  810. for (var i=0; i < arguments.length; i++) {
  811. if (this.indexOf(arguments[i]) === -1) {
  812. return false;
  813. }
  814. }
  815. return true;
  816. },
  817. /**
  818. * returns a copy of the array without the items passed as the arguments
  819. *
  820. * @param mixed value
  821. * ......
  822. * @return Array filtered copy
  823. */
  824. without: function() {
  825. var filter = slice.call(arguments);
  826. return this.filter(function(value) {
  827. return filter.indexOf(value) === -1;
  828. });
  829. },
  830. /**
  831. * Shuffles the array items in a random order
  832. *
  833. * @return Array shuffled version
  834. */
  835. shuffle: function() {
  836. var shuff = this.clone(), j, x, i = shuff.length;
  837. for (; i > 0; j = Math.random(i-1), x = shuff[--i], shuff[i] = shuff[j], shuff[j] = x) {}
  838. return shuff;
  839. },
  840. /**
  841. * Default sort fix for numeric values
  842. *
  843. * @param Function callback
  844. * @return Array self
  845. */
  846. sort: function(callback) {
  847. return original_sort.apply(this, (callback || !isNumber(this[0])) ? arguments : [default_sort]);
  848. },
  849. /**
  850. * sorts the array by running its items though a lambda or calling their attributes
  851. *
  852. * @param Function callback or attribute name
  853. * @param Object scope or attribute argument
  854. * @return Array sorted copy
  855. */
  856. sortBy: function() {
  857. var pair = guess_callback(arguments, this);
  858. return this.sort(function(a, b) {
  859. return default_sort(
  860. pair[0].call(pair[1], a),
  861. pair[0].call(pair[1], b)
  862. );
  863. });
  864. },
  865. /**
  866. * Returns the minimal value on the list
  867. *
  868. * @return Number minimal value
  869. */
  870. min: function() {
  871. return Math.min.apply(Math, this);
  872. },
  873. /**
  874. * Returns the maximal value
  875. *
  876. * @return Number maximal value
  877. */
  878. max: function() {
  879. return Math.max.apply(Math, this);
  880. },
  881. /**
  882. * Returns a summ of all the items on the list
  883. *
  884. * @return Number a summ of values on the list
  885. */
  886. sum: function() {
  887. for(var sum=0, i=0, l=this.length; i < l; sum += this[i++]) {}
  888. return sum;
  889. }
  890. });
  891. A_proto.include = A_proto.includes;
  892. /**
  893. * The String class extentions
  894. *
  895. * Credits:
  896. * Some of the functionality inspired by
  897. * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
  898. * The trim function taken from work of Steven Levithan
  899. * - http://blog.stevenlevithan.com/archives/faster-trim-javascript
  900. *
  901. * Copyright (C) 2008-2011 Nikolay V. Nemshilov
  902. */
  903. String.include({
  904. /**
  905. * checks if the string is an empty string
  906. *
  907. * @return boolean check result
  908. */
  909. empty: function() {
  910. return this == '';
  911. },
  912. /**
  913. * checks if the string contains only white-spaces
  914. *
  915. * @return boolean check result
  916. */
  917. blank: function() {
  918. return this == false;
  919. },
  920. /**
  921. * removes trailing whitespaces
  922. *
  923. * @return String trimmed version
  924. */
  925. trim: String.prototype.trim || function() {
  926. var str = this.replace(/^\s\s*/, ''), i = str.length;
  927. while ((/\s/).test(str.charAt(--i))) {}
  928. return str.slice(0, i + 1);
  929. },
  930. /**
  931. * returns a copy of the string with all the tags removed
  932. * @return String without tags
  933. */
  934. stripTags: function() {
  935. return this.replace(/<\/?[^>]+>/ig, '');
  936. },
  937. /**
  938. * removes all the scripts declarations out of the string
  939. * @param mixed option. If it equals true the scrips will be executed,
  940. * if a function the scripts will be passed in it
  941. * @return String without scripts
  942. */
  943. stripScripts: function(option) {
  944. var scripts = '', text = this.replace(
  945. /<script[^>]*>([\s\S]*?)<\/script>/img,
  946. function(match, source) {
  947. scripts += source + "\n";
  948. return '';
  949. }
  950. );
  951. if (option === true) {
  952. $eval(scripts);
  953. } else if (isFunction(option)) {
  954. option(scripts, text);
  955. }
  956. return text;
  957. },
  958. /**
  959. * extracts all the scripts out of the string
  960. *
  961. * @return String the extracted stcripts
  962. */
  963. extractScripts: function() {
  964. var scripts = '';
  965. this.stripScripts(function(s) { scripts = s; });
  966. return scripts;
  967. },
  968. /**
  969. * evals all the scripts in the string
  970. *
  971. * @return String self (unchanged version with scripts still in their place)
  972. */
  973. evalScripts: function() {
  974. this.stripScripts(true);
  975. return this;
  976. },
  977. /**
  978. * converts underscored or dasherized string to a camelized one
  979. * @returns String camelized version
  980. */
  981. camelize: function() {
  982. return this.replace(/(\-|_)+(.)?/g, function(match, dash, chr) {
  983. return chr ? chr.toUpperCase() : '';
  984. });
  985. },
  986. /**
  987. * converts a camelized or dasherized string into an underscored one
  988. * @return String underscored version
  989. */
  990. underscored: function() {
  991. return this.replace(/([a-z\d])([A-Z]+)/g, '$1_$2').replace(/\-/g, '_').toLowerCase();
  992. },
  993. /**
  994. * returns a capitalised version of the string
  995. *
  996. * @return String captialised version
  997. */
  998. capitalize: function() {
  999. return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
  1000. },
  1001. /**
  1002. * checks if the string contains the given substring
  1003. *
  1004. * @param String string
  1005. * @return boolean check result
  1006. */
  1007. includes: function(string) {
  1008. return this.indexOf(string) != -1;
  1009. },
  1010. /**
  1011. * checks if the string starts with the given substring
  1012. *
  1013. * @param String string
  1014. * @param boolean ignore the letters case
  1015. * @return boolean check result
  1016. */
  1017. startsWith: function(string, ignorecase) {
  1018. return (ignorecase !== true ? this.indexOf(string) :
  1019. this.toLowerCase().indexOf(string.toLowerCase())
  1020. ) === 0;
  1021. },
  1022. /**
  1023. * checks if the string ends with the given substring
  1024. *
  1025. * @param String substring
  1026. * @param boolean ignore the letters case
  1027. * @return boolean check result
  1028. */
  1029. endsWith: function(string, ignorecase) {
  1030. return this.length - (
  1031. ignorecase !== true ? this.lastIndexOf(string) :
  1032. this.toLowerCase().lastIndexOf(string.toLowerCase())
  1033. ) === string.length;
  1034. },
  1035. /**
  1036. * converts the string to an integer value
  1037. * @param Integer base
  1038. * @return Integer or NaN
  1039. */
  1040. toInt: function(base) {
  1041. return parseInt(this, base === undefined ? 10 : base);
  1042. },
  1043. /**
  1044. * converts the string to a float value
  1045. * @param boolean flat if the method should not use a flexible matching
  1046. * @return Float or NaN
  1047. */
  1048. toFloat: function(strict) {
  1049. return parseFloat(strict === true ? this :
  1050. this.replace(',', '.').replace(/(\d)-(\d)/, '$1.$2'));
  1051. }
  1052. });
  1053. String.prototype.include = String.prototype.includes;
  1054. /**
  1055. * The Function class extentions
  1056. *
  1057. * Credits:
  1058. * Some of the functionality inspired by
  1059. * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
  1060. *
  1061. * Copyright (C) 2008-2011 Nikolay V. Nemshilov
  1062. */
  1063. Function.include({
  1064. /**
  1065. * binds the function to be executed in the given scope
  1066. *
  1067. * @param Object scope
  1068. * @param mixed optional curry (left) argument
  1069. * ....
  1070. * @return Function binded function
  1071. */
  1072. bind: function() {
  1073. var args = $A(arguments), scope = args.shift(), func = this;
  1074. return function() {
  1075. return func.apply(scope,
  1076. (args.length !== 0 || arguments.length !== 0) ?
  1077. args.concat($A(arguments)) : args
  1078. );
  1079. };
  1080. },
  1081. /**
  1082. * binds the function as an event listener to the given scope object
  1083. *
  1084. * @param Object scope
  1085. * @param mixed optional curry (left) argument
  1086. * .......
  1087. * @return Function binded function
  1088. */
  1089. bindAsEventListener: function() {
  1090. var args = $A(arguments), scope = args.shift(), func = this;
  1091. return function(event) {
  1092. return func.apply(scope, [event].concat(args).concat($A(arguments)));
  1093. };
  1094. },
  1095. /**
  1096. * allows you to put some curry in your cookery
  1097. *
  1098. * @param mixed value to curry
  1099. * ....
  1100. * @return Function curried function
  1101. */
  1102. curry: function() {
  1103. return this.bind.apply(this, [this].concat($A(arguments)));
  1104. },
  1105. /**
  1106. * The right side curry feature
  1107. *
  1108. * @param mixed value to curry
  1109. * ....
  1110. * @return Function curried function
  1111. */
  1112. rcurry: function() {
  1113. var curry = $A(arguments), func = this;
  1114. return function() {
  1115. return func.apply(func, $A(arguments).concat(curry));
  1116. };
  1117. },
  1118. /**
  1119. * delays the function execution
  1120. *
  1121. * @param Integer delay ms
  1122. * @param mixed value to curry
  1123. * .....
  1124. * @return Integer timeout marker
  1125. */
  1126. delay: function() {
  1127. var args = $A(arguments), timeout = args.shift(),
  1128. timer = new Number(setTimeout(this.bind.apply(this, [this].concat(args)), timeout));
  1129. timer.cancel = function() { clearTimeout(this); };
  1130. return timer;
  1131. },
  1132. /**
  1133. * creates a periodical execution of the function with the given timeout
  1134. *
  1135. * @param Integer delay ms
  1136. * @param mixed value to curry
  1137. * ...
  1138. * @return Ineger interval marker
  1139. */
  1140. periodical: function() {
  1141. var args = $A(arguments), timeout = args.shift(),
  1142. timer = new Number(setInterval(this.bind.apply(this, [this].concat(args)), timeout));
  1143. timer.stop = function() { clearInterval(this); };
  1144. return timer;
  1145. },
  1146. /**
  1147. * Chains the given function after the current one
  1148. *
  1149. * @param Function the next function
  1150. * @param mixed optional value to curry
  1151. * ......
  1152. * @return Function chained function
  1153. */
  1154. chain: function() {
  1155. var args = $A(arguments), func = args.shift(), current = this;
  1156. return function() {
  1157. var result = current.apply(current, arguments);
  1158. func.apply(func, args);
  1159. return result;
  1160. };
  1161. }
  1162. });
  1163. /**
  1164. * The Number class extentions
  1165. *
  1166. * Credits:
  1167. * Some methods inspired by
  1168. * - Ruby (http://www.ruby-lang.org) Copyright (C) Yukihiro Matsumoto
  1169. *
  1170. * Copyright (C) 2008-2010 Nikolay V. Nemshilov
  1171. */
  1172. Number.include({
  1173. /**
  1174. * executes the given callback the given number of times
  1175. *
  1176. * @param Function callback
  1177. * @param Object optional callback execution scope
  1178. * @return void
  1179. */
  1180. times: function(callback, scope) {
  1181. for (var i=0; i < this; i++) {
  1182. callback.call(scope, i);
  1183. }
  1184. return this;
  1185. },
  1186. upto: function(number, callback, scope) {
  1187. for (var i=this+0; i <= number; i++) {
  1188. callback.call(scope, i);
  1189. }
  1190. return this;
  1191. },
  1192. downto: function(number, callback, scope) {
  1193. for (var i=this+0; i >= number; i--) {
  1194. callback.call(scope, i);
  1195. }
  1196. return this;
  1197. },
  1198. abs: function() {
  1199. return Math.abs(this);
  1200. },
  1201. round: function(size) {
  1202. return size ? parseFloat(this.toFixed(size)) : Math.round(this);
  1203. },
  1204. ceil: function() {
  1205. return Math.ceil(this);
  1206. },
  1207. floor: function() {
  1208. return Math.floor(this);
  1209. },
  1210. min: function(value) {
  1211. return this < value ? value : this + 0;
  1212. },
  1213. max: function(value) {
  1214. return this > value ? value : this + 0;
  1215. }
  1216. });
  1217. /**
  1218. * The Regexp class extentions
  1219. *
  1220. * Credits:
  1221. * Inspired by
  1222. * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
  1223. *
  1224. * Copyright (C) 2008-2010 Nikolay V. Nemshilov
  1225. */
  1226. /**
  1227. * Escapes the string for safely use as a regular expression
  1228. *
  1229. * @param String raw string
  1230. * @return String escaped string
  1231. */
  1232. RegExp.escape = function(string) {
  1233. return (''+string).replace(/([.*+?\^=!:${}()|\[\]\/\\])/g, '\\$1');
  1234. };
  1235. /**
  1236. * The basic Class unit
  1237. *
  1238. * Credits:
  1239. * The Class unit is inspired by its implementation in
  1240. * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
  1241. * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
  1242. * - Ruby (http://www.ruby-lang.org) Copyright (C) Yukihiro Matsumoto
  1243. *
  1244. * Copyright (C) 2008-2011 Nikolay Nemshilov
  1245. */
  1246. var Class = RightJS.Class = function() {
  1247. var args = $A(arguments).slice(0,2),
  1248. props = args.pop() || {},
  1249. parent = args.pop(),
  1250. klass = arguments[2], // you can send your own klass as the third argument
  1251. SKlass = function() {};
  1252. // if the parent class only was specified
  1253. if (!args.length && !isHash(props)) {
  1254. parent = props; props = {};
  1255. }
  1256. // !#server:begin
  1257. if (!klass && parent && (parent === Wrapper || parent.ancestors.include(Wrapper))) {
  1258. klass = Wrapper_makeKlass();
  1259. }
  1260. // !#server:end
  1261. // defining the basic klass function
  1262. klass = $ext(klass || function() {
  1263. Class_checkPrebind(this);
  1264. return 'initialize' in this ?
  1265. this.initialize.apply(this, arguments) :
  1266. this;
  1267. }, Class_Methods);
  1268. // handling the inheritance
  1269. parent = parent || Class;
  1270. SKlass.prototype = parent.prototype;
  1271. klass.prototype = new SKlass();
  1272. klass.parent = parent;
  1273. klass.prototype.constructor = klass;
  1274. // collecting the list of ancestors
  1275. klass.ancestors = [];
  1276. while (parent) {
  1277. klass.ancestors.push(parent);
  1278. parent = parent.parent;
  1279. }
  1280. // handling the module injections
  1281. ['extend', 'include'].each(function(name) {
  1282. if (name in props) {
  1283. klass[name].apply(klass, ensure_array(props[name]));
  1284. }
  1285. });
  1286. return klass.include(props);
  1287. },
  1288. /**
  1289. * Class utility methods
  1290. *
  1291. * Copyright (C) 2008-2011 Nikolay Nemshilov
  1292. */
  1293. Class_Methods = {
  1294. /**
  1295. * this method will extend the class-level with the given objects
  1296. *
  1297. * NOTE: this method _WILL_OVERWRITE_ the existing itercecting entries
  1298. *
  1299. * NOTE: this method _WILL_NOT_OVERWRITE_ the class prototype and
  1300. * the class 'name' and 'parent' attributes. If one of those
  1301. * exists in one of the received modeuls, the attribute will be
  1302. * skipped
  1303. *
  1304. * @param Object module to extend
  1305. * ....
  1306. * @return Class the klass
  1307. */
  1308. extend: function() {
  1309. $A(arguments).filter(isHash).each(function(module) {
  1310. $ext(this, Class_clean_module(module, true));
  1311. Class_handle_module_callbacks(this, module, true);
  1312. }, this);
  1313. return this;
  1314. },
  1315. /**
  1316. * extends the class prototype with the given objects
  1317. * NOTE: this method _WILL_OVERWRITE_ the existing itercecting entries
  1318. * NOTE: this method _WILL_NOT_OVERWRITE_ the 'klass' attribute of the klass.prototype
  1319. *
  1320. * @param Object module to include
  1321. * ....
  1322. * @return Class the klass
  1323. */
  1324. include: function() {
  1325. var klasses = [this].concat(this.ancestors);
  1326. $A(arguments).filter(isHash).each(function(module) {
  1327. Object.each(Class_clean_module(module, false), function(name, method) {
  1328. // searching for the super-method
  1329. for (var super_method, i=0, l = klasses.length; i < l; i++) {
  1330. if (name in klasses[i].prototype) {
  1331. super_method = klasses[i].prototype[name];
  1332. break;
  1333. }
  1334. }
  1335. this.prototype[name] = isFunction(method) && isFunction(super_method) ?
  1336. function() {
  1337. this.$super = super_method;
  1338. return method.apply(this, arguments);
  1339. } : method;
  1340. }, this);
  1341. Class_handle_module_callbacks(this, module, false);
  1342. }, this);
  1343. return this;
  1344. }
  1345. },
  1346. Class_module_callback_names = $w(
  1347. 'selfExtended self_extended selfIncluded self_included extend include'
  1348. );
  1349. // hooking up the class-methods to the root class
  1350. $ext(Class, Class_Methods);
  1351. Class.prototype.$super = undefined;
  1352. function Class_clean_module(module, extend) {
  1353. return Object.without.apply(Object, [module].concat(
  1354. Class_module_callback_names.concat( extend ?
  1355. $w('prototype parent ancestors') : ['constructor']
  1356. )
  1357. ));
  1358. }
  1359. function Class_handle_module_callbacks(klass, module, extend) {
  1360. (module[Class_module_callback_names[extend ? 0 : 2]] ||
  1361. module[Class_module_callback_names[extend ? 1 : 3]] ||
  1362. function() {}
  1363. ).call(module, klass);
  1364. }
  1365. /**
  1366. * This method gets through a list of the object its class and all the ancestors
  1367. * and finds a hash named after property, used for configuration purposes with
  1368. * the Observer and Options modules
  1369. *
  1370. * NOTE: this method will look for capitalized and uppercased versions of the
  1371. * property name
  1372. *
  1373. * @param Object a class instance
  1374. * @param String property name
  1375. * @return Object hash or null if nothing found
  1376. */
  1377. function Class_findSet(object, property) {
  1378. var upcased = property.toUpperCase(),
  1379. constructor = object.constructor,
  1380. candidates = [object, constructor].concat(constructor.ancestors || []),
  1381. i = 0;
  1382. for (l = candidates.length; i < l; i++) {
  1383. if (upcased in candidates[i]) {
  1384. return candidates[i][upcased];
  1385. } else if (property in candidates[i]) {
  1386. return candidates[i][property];
  1387. }
  1388. }
  1389. return null;
  1390. }
  1391. /**
  1392. * Handles the 'prebind' feature for Class instances
  1393. *
  1394. * @param Class instance
  1395. * @return void
  1396. */
  1397. function Class_checkPrebind(object) {
  1398. if ('prebind' in object && isArray(object.prebind)) {
  1399. object.prebind.each(function(method) {
  1400. object[method] = object[method].bind(object);
  1401. });
  1402. }
  1403. }
  1404. /**
  1405. * This is a simple mix-in module to be included in other classes
  1406. *
  1407. * Basically it privdes the <tt>setOptions</tt> method which processes
  1408. * an instance options assigment and merging with the default options
  1409. *
  1410. * Credits:
  1411. * The idea of the module is inspired by
  1412. * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
  1413. *
  1414. * Copyright (C) 2008-2011 Nikolay V. Nemshilov
  1415. */
  1416. var Options = RightJS.Options = {
  1417. /**
  1418. * assigns the options by merging them with the default ones
  1419. *
  1420. * @param Object options
  1421. * @return Object current instance
  1422. */
  1423. setOptions: function(opts) {
  1424. var options = this.options = $ext($ext({},
  1425. Object.clone(Class_findSet(this, 'Options'))), opts
  1426. ), match, key;
  1427. // hooking up the observer options
  1428. if (isFunction(this.on)) {
  1429. for (key in options) {
  1430. if ((match = key.match(/on([A-Z][A-Za-z]+)/))) {
  1431. this.on(match[1].toLowerCase(), options[key]);
  1432. delete(options[key]);
  1433. }
  1434. }
  1435. }
  1436. return this;
  1437. },
  1438. /**
  1439. * Cuts of an options hash from the end of the arguments list
  1440. * assigns them using the #setOptions method and then
  1441. * returns the list of other arguments as an Array instance
  1442. *
  1443. * @param mixed iterable
  1444. * @return Array of the arguments
  1445. */
  1446. cutOptions: function(in_args) {
  1447. var args = $A(in_args);
  1448. this.setOptions(isHash(args.last()) ? args.pop() : {});
  1449. return args;
  1450. }
  1451. };
  1452. /**
  1453. * standard Observer class.
  1454. *
  1455. * Might be used as a usual class or as a builder over another objects
  1456. *
  1457. * Credits:
  1458. * The naming principle is inspired by
  1459. * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
  1460. *
  1461. * Copyright (C) 2008-2011 Nikolay Nemshilov
  1462. */
  1463. var Observer = RightJS.Observer = new Class({
  1464. include: Options,
  1465. /**
  1466. * general constructor
  1467. *
  1468. * @param Object options
  1469. */
  1470. initialize: function(options) {
  1471. this.setOptions(options);
  1472. Observer_createShortcuts(this, Class_findSet(this, 'Events'));
  1473. return this;
  1474. },
  1475. /**
  1476. * binds an event listener
  1477. *
  1478. * USAGE:
  1479. * on(String event, Function callback[, arguments, ...]);
  1480. * on(String event, String method_name[, arguments, ...]);
  1481. * on(Object events_hash);
  1482. *
  1483. * @return Observer self
  1484. */
  1485. on: function() {
  1486. Observer_on(this, arguments, function(h) { return h; });
  1487. return this;
  1488. },
  1489. /**
  1490. * checks if the observer observes given event and/or callback
  1491. *
  1492. * USAGE:
  1493. * observes(String event)
  1494. * observes(Function callback)
  1495. * observes(String event, Function callback)
  1496. *
  1497. * @retun boolean check result
  1498. */
  1499. observes: function(event, callback) {
  1500. if (!isString(event)) { callback = event; event = null; }
  1501. if (isString(callback)) { callback = callback in this ? this[callback] : null; }
  1502. return (this.$listeners || []).some(function(i) {
  1503. return (event && callback) ? i.e === event && i.f === callback :
  1504. event ? i.e === event : i.f === callback;
  1505. });
  1506. },
  1507. /**
  1508. * stops observing an event or/and function
  1509. *
  1510. * USAGE:
  1511. * stopObserving(String event)
  1512. * stopObserving(Function callback)
  1513. * stopObserving(String event, Function callback)
  1514. *
  1515. * @return Observer self
  1516. */
  1517. stopObserving: function(event, callback) {
  1518. Observer_stopObserving(this, event, callback, function() {});
  1519. return this;
  1520. },
  1521. /**
  1522. * returns the listeners list for the event
  1523. *
  1524. * NOTE: if no event was specified the method will return _all_
  1525. * event listeners for _all_ the events
  1526. *
  1527. * @param String event name
  1528. * @return Array of listeners
  1529. */
  1530. listeners: function(event) {
  1531. return (this.$listeners || []).filter(function(i) {
  1532. return !event || i.e === event;
  1533. }).map(function(i) { return i.f; }).uniq();
  1534. },
  1535. /**
  1536. * initiates the event handling
  1537. *
  1538. * @param String event name
  1539. * @param mixed optional argument
  1540. * ........
  1541. * @return Observer self
  1542. */
  1543. fire: function() {
  1544. var args = $A(arguments), event = args.shift();
  1545. (this.$listeners || []).each(function(i) {
  1546. if (i.e === event) {
  1547. i.f.apply(this, i.a.concat(args));
  1548. }
  1549. }, this);
  1550. return this;
  1551. }
  1552. }),
  1553. /**
  1554. * adds an observer functionality to any object
  1555. *
  1556. * @param Object object
  1557. * @param Array optional events list to build shortcuts
  1558. * @return Object extended object
  1559. */
  1560. Observer_create = Observer.create = function(object, events) {
  1561. $ext(object, Object.without(Observer.prototype, 'initialize', 'setOptions'), true);
  1562. return Observer_createShortcuts(object, events || Class_findSet(object, 'Events'));
  1563. },
  1564. /**
  1565. * builds shortcut methods to wire/fire events on the object
  1566. *
  1567. * @param Object object to extend
  1568. * @param Array list of event names
  1569. * @return Object extended object
  1570. */
  1571. Observer_createShortcuts = Observer.createShortcuts = function(object, names) {
  1572. (names || []).each(function(name) {
  1573. var method_name = 'on'+name.replace(/(^|_|:)([a-z])/g,
  1574. function(match, pre, chr) { return chr.toUpperCase(); }
  1575. );
  1576. if (!(method_name in object)) {
  1577. object[method_name] = function() {
  1578. return this.on.apply(this, [name].concat($A(arguments)));
  1579. };
  1580. }
  1581. });
  1582. return object;
  1583. };
  1584. function Observer_on(object, o_args, preprocess) {
  1585. var args = slice.call(o_args, 2),
  1586. event = o_args[0],
  1587. callback = o_args[1],
  1588. name = false;
  1589. if (isString(event)) {
  1590. switch (typeof callback) {
  1591. case "string":
  1592. name = callback;
  1593. callback = callback in object ? object[callback] : function() {};
  1594. case "function":
  1595. ('$listeners' in object ? object.$listeners : (
  1596. object.$listeners = []
  1597. )).push(preprocess({
  1598. e: event, f: callback, a: args, r: name || false, t: object
  1599. }));
  1600. break;
  1601. default:
  1602. if (isArray(callback)) {
  1603. for (var i=0; i < callback.length; i++) {
  1604. object.on.apply(object, [event].concat(
  1605. ensure_array(callback[i])
  1606. ).concat(args));
  1607. }
  1608. }
  1609. }
  1610. } else {
  1611. // assuming it's a hash of key-value pairs
  1612. args = slice.call(o_args, 1);
  1613. for (name in event) {
  1614. object.on.apply(object, [name].concat(
  1615. ensure_array(event[name])
  1616. ).concat(args));
  1617. }
  1618. }
  1619. }
  1620. function Observer_stopObserving(object, event, callback, preprocess) {
  1621. if (isHash(event)) {
  1622. for (var key in event) {
  1623. object.stopObserving(key, event[key]);
  1624. }
  1625. } else {
  1626. if (!isString(event)) { callback = event; event = null; }
  1627. if (isString(callback)){ callback = object[callback]; }
  1628. object.$listeners = (object.$listeners || []).filter(function(i) {
  1629. var result = (event && callback) ?
  1630. (i.e !== event || i.f !== callback) :
  1631. (event ? i.e !== event : i.f !== callback);
  1632. if (!result) { preprocess(i); }
  1633. return result;
  1634. });
  1635. }
  1636. }
  1637. /**
  1638. * this object will contain info about the current browser
  1639. *
  1640. * Copyright (C) 2008-2011 Nikolay V. Nemshilov
  1641. */
  1642. var agent = navigator.userAgent,
  1643. Browser_Opera = 'opera' in window,
  1644. Browser_IE = 'attachEvent' in window && !Browser_Opera,
  1645. Browser = RightJS.Browser = {
  1646. IE: Browser_IE,
  1647. Opera: Browser_Opera,
  1648. WebKit: agent.include('AppleWebKit/'),
  1649. Gecko: agent.include('Gecko') && !agent.include('KHTML'),
  1650. MobileSafari: /Apple.*Mobile.*Safari/.test(agent),
  1651. Konqueror: agent.include('Konqueror'),
  1652. // internal marker for the browsers which require the olds module
  1653. OLD: !document.querySelector,
  1654. // internal marker for IE browsers version <= 8
  1655. IE8L: false
  1656. },
  1657. IE8_OR_LESS = false,
  1658. IE_OPACITY = !('opacity' in HTML.style) && ('filter' in HTML.style);
  1659. try {
  1660. // checking if that an IE version <= 8
  1661. document.createElement('<input/>');
  1662. Browser.OLD = Browser.IE8L = IE8_OR_LESS = true;
  1663. } catch(e) {}
  1664. /**
  1665. * The dom-wrapper main unit
  1666. *
  1667. * This unit is basically for the internal use
  1668. * so that we could control the common functionality
  1669. * among all the wrappers
  1670. *
  1671. * Copyright (C) 2010-2011 Nikolay Nemshilov
  1672. */
  1673. var Wrapper = RightJS.Wrapper = new Class({
  1674. // predefining the property in the prototype
  1675. _: undefined,
  1676. /**
  1677. * Default constructor
  1678. *
  1679. * @param mixed raw dom unit
  1680. * @return void
  1681. */
  1682. initialize: function(raw_object) {
  1683. this._ = raw_object;
  1684. }
  1685. });
  1686. // exposing the cache so it could be manupulated externally
  1687. Wrapper.Cache = Wrappers_Cache;
  1688. // instantiating the actual class object for a wrapper
  1689. function Wrapper_makeKlass() {
  1690. /**
  1691. * Default wrappers Klass function
  1692. *
  1693. * @param mixed the raw object
  1694. * @param Object options
  1695. * @return void
  1696. */
  1697. return function(object, options) {
  1698. Class_checkPrebind(this);
  1699. this.initialize.apply(this, arguments); // <- there might be a different number of args in a subclass
  1700. var item = this._, uid = UID_KEY in item ? item[UID_KEY] :
  1701. // NOTE we use positive indexes for dom-elements and negative for everything else
  1702. (item[UID_KEY] = (item.nodeType === 1 ? 1 : -1) * UID++);
  1703. Wrappers_Cache[uid] = this;
  1704. };
  1705. }
  1706. /**
  1707. * Element's own Klass function
  1708. * we need that because it does some dynamic typecasting mumbo jumbo
  1709. * plus we would like to optimize some stuff here and there
  1710. *
  1711. * @param raw dom element or the tag name
  1712. * @param Object options
  1713. * @return Element instance
  1714. */
  1715. function Element_Klass(element, options) {
  1716. Element_initialize(this, element, options);
  1717. var inst = this, raw = inst._, cast = Wrapper.Cast(raw),
  1718. uid = UID_KEY in raw ? raw[UID_KEY] : (raw[UID_KEY] = UID++);
  1719. if (cast !== undefined) {
  1720. inst = new cast(raw, options);
  1721. if ('$listeners' in this) {
  1722. inst.$listeners = this.$listeners;
  1723. }
  1724. }
  1725. Wrappers_Cache[uid] = inst;
  1726. return inst;
  1727. }
  1728. // searches for a suitable class for dynamic typecasting
  1729. Wrapper.Cast = function(unit) {
  1730. return unit.tagName in Element_wrappers ? Element_wrappers[unit.tagName] : undefined;
  1731. };
  1732. /**
  1733. * Event's own Klass function, we don't need to check
  1734. * nothing in here, don't need to hit the wrappers cache and so one
  1735. *
  1736. * @param raw dom-event or a string event-name
  1737. * @param bounding element or an object with options
  1738. * @return void
  1739. */
  1740. function Event_Klass(event, bound_element) {
  1741. if (typeof(event) === 'string') {
  1742. event = $ext({type: event}, bound_element);
  1743. this.stopped = event.bubbles === false;
  1744. if (isHash(bound_element)) {
  1745. $ext(this, bound_element);
  1746. }
  1747. }
  1748. this._ = event;
  1749. this.type = event.type;
  1750. this.which = event.which;
  1751. this.keyCode = event.keyCode;
  1752. this.target = wrap(
  1753. // Webkit throws events on textual nodes as well, gotta fix that
  1754. event.target != null && 'nodeType' in event.target && event.target.nodeType === 3 ?
  1755. event.target.parentNode : event.target
  1756. );
  1757. this.currentTarget = wrap(event.currentTarget);
  1758. this.relatedTarget = wrap(event.relatedTarget);
  1759. this.pageX = event.pageX;
  1760. this.pageY = event.pageY;
  1761. // making old IE attrs looks like w3c standards
  1762. if (IE8_OR_LESS && 'srcElement' in event) {
  1763. this.which = event.button === 2 ? 3 : event.button === 4 ? 2 : 1;
  1764. this.target = wrap(event.srcElement) || bound_element;
  1765. this.relatedTarget = this.target._ === event.fromElement ? wrap(event.toElement) : this.target;
  1766. this.currentTarget = bound_element;
  1767. var scrolls = this.target.win().scrolls();
  1768. this.pageX = event.clientX + scrolls.x;
  1769. this.pageY = event.clientY + scrolls.y;
  1770. }
  1771. }
  1772. /**
  1773. * Private quick wrapping function, unlike `$`
  1774. * it doesn't search by ID and handle double-wrapps
  1775. * just pure dom-wrapping functionality
  1776. *
  1777. * @param raw dom unit
  1778. * @return Wrapper dom-wrapper
  1779. */
  1780. function wrap(object) {
  1781. if (object != null) {
  1782. var wrapper = UID_KEY in object ? Wrappers_Cache[object[UID_KEY]] : undefined;
  1783. if (wrapper !== undefined) {
  1784. return wrapper;
  1785. } else if (object.nodeType === 1) {
  1786. return new Element(object);
  1787. } else if (object.nodeType === 9) {
  1788. return new Document(object);
  1789. } else if (object.window == object) {
  1790. return new Window(object);
  1791. } else if (isElement(object.target) || isElement(object.srcElement)) {
  1792. return new Event(object);
  1793. }

Large files files are truncated, but you can click here to view the full file