right-rails 1.0.10 → 1.0.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/README.rdoc +4 -4
  2. data/Rakefile +4 -4
  3. data/lib/right_rails.rb +1 -1
  4. data/public/javascripts/right/autocompleter-src.js +115 -106
  5. data/public/javascripts/right/autocompleter.js +3 -14
  6. data/public/javascripts/right/billboard-src.js +58 -38
  7. data/public/javascripts/right/billboard.js +3 -13
  8. data/public/javascripts/right/calendar-src.js +136 -133
  9. data/public/javascripts/right/calendar.js +4 -33
  10. data/public/javascripts/right/colorpicker-src.js +128 -125
  11. data/public/javascripts/right/colorpicker.js +4 -23
  12. data/public/javascripts/right/dialog-src.js +67 -37
  13. data/public/javascripts/right/dialog.js +3 -17
  14. data/public/javascripts/right/dnd-src.js +44 -43
  15. data/public/javascripts/right/dnd.js +3 -16
  16. data/public/javascripts/right/effects-src.js +125 -98
  17. data/public/javascripts/right/effects.js +3 -13
  18. data/public/javascripts/right/in-edit-src.js +54 -38
  19. data/public/javascripts/right/in-edit.js +4 -10
  20. data/public/javascripts/right/jquerysh-src.js +344 -20
  21. data/public/javascripts/right/jquerysh.js +3 -3
  22. data/public/javascripts/right/json-src.js +22 -35
  23. data/public/javascripts/right/json.js +4 -7
  24. data/public/javascripts/right/keys-src.js +87 -0
  25. data/public/javascripts/right/keys.js +7 -0
  26. data/public/javascripts/right/lightbox-src.js +76 -58
  27. data/public/javascripts/right/lightbox.js +3 -20
  28. data/public/javascripts/right/rails-src.js +108 -107
  29. data/public/javascripts/right/rails.js +4 -11
  30. data/public/javascripts/right/rater-src.js +47 -31
  31. data/public/javascripts/right/rater.js +3 -9
  32. data/public/javascripts/right/resizable-src.js +60 -33
  33. data/public/javascripts/right/resizable.js +3 -11
  34. data/public/javascripts/right/selectable-src.js +87 -51
  35. data/public/javascripts/right/selectable.js +3 -18
  36. data/public/javascripts/right/sizzle-src.js +15 -10
  37. data/public/javascripts/right/sizzle.js +4 -27
  38. data/public/javascripts/right/slider-src.js +49 -33
  39. data/public/javascripts/right/slider.js +3 -10
  40. data/public/javascripts/right/sortable-src.js +46 -32
  41. data/public/javascripts/right/sortable.js +4 -13
  42. data/public/javascripts/right/table-src.js +19 -10
  43. data/public/javascripts/right/table.js +4 -6
  44. data/public/javascripts/right/tabs-src.js +69 -47
  45. data/public/javascripts/right/tabs.js +4 -26
  46. data/public/javascripts/right/tooltips-src.js +78 -56
  47. data/public/javascripts/right/tooltips.js +4 -9
  48. data/public/javascripts/right/uploader-src.js +50 -34
  49. data/public/javascripts/right/uploader.js +3 -9
  50. data/public/javascripts/right-olds-src.js +528 -355
  51. data/public/javascripts/right-olds.js +4 -13
  52. data/public/javascripts/right-safe-src.js +4 -99
  53. data/public/javascripts/right-safe.js +3 -4
  54. data/public/javascripts/right-src.js +1618 -1245
  55. data/public/javascripts/right.js +4 -91
  56. metadata +8 -6
@@ -1,26 +1,26 @@
1
1
  /**
2
- * RightJS, http://rightjs.org
3
- * Released under the MIT license
2
+ * RightJS v2.2.2 - http://rightjs.org
3
+ * Released under the terms of MIT license
4
4
  *
5
- * Copyright (C) 2008-2010 Nikolay Nemshilov
5
+ * Copyright (C) 2008-2011 Nikolay Nemshilov
6
6
  */
7
7
  /**
8
8
  * The basic layout for RightJS builds
9
9
  *
10
- * Copyright (C) 2010 Nikolay Nemshilov
10
+ * Copyright (C) 2008-2011 Nikolay Nemshilov
11
11
  */
12
12
  var RightJS = (function(window, document, Object, Array, String, Function, Number, Math) {
13
13
 
14
14
  /**
15
15
  * The framework description object
16
16
  *
17
- * Copyright (C) 2008-2010 Nikolay Nemshilov
17
+ * Copyright (C) 2008-2011 Nikolay Nemshilov
18
18
  */
19
19
  var RightJS = function(value) {
20
20
  return value; // <- a dummy method to emulate the safe-mode
21
21
  };
22
22
 
23
- RightJS.version = "2.1.1";
23
+ RightJS.version = "2.2.2";
24
24
  RightJS.modules =["core", "dom", "form", "events", "xhr", "fx", "cookie"];
25
25
 
26
26
 
@@ -33,18 +33,16 @@ RightJS.modules =["core", "dom", "form", "events", "xhr", "fx", "cookie"];
33
33
  * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
34
34
  * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
35
35
  *
36
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
36
+ * Copyright (C) 2008-2011 Nikolay V. Nemshilov
37
37
  */
38
38
 
39
39
  /**
40
40
  * Some top-level variables to shortify the things
41
41
  */
42
- var
43
- PROTO = 'prototype', A_proto = Array[PROTO],
44
- to_s = Object[PROTO].toString, slice = A_proto.slice,
45
- dummy = function() { return function() {}; },
46
- HTML = document.documentElement, UID = 1, // !#server
47
- Wrappers_Cache = [], UID_KEY = '_rjs_id',
42
+ var A_proto = Array.prototype,
43
+ to_s = Object.prototype.toString, slice = A_proto.slice,
44
+ HTML = document.documentElement, UID = 1, // !#server
45
+ Wrappers_Cache = [], UID_KEY = 'uniqueNumber', // DON'T change the UID_KEY!
48
46
 
49
47
  /**
50
48
  * extends the first object with the keys and values of the second one
@@ -78,7 +76,7 @@ $ext = RightJS.$ext = function(dest, source, dont_overwrite) {
78
76
  $eval = RightJS.$eval = function(text) {
79
77
  if (text) {
80
78
  if ('execScript' in window) {
81
- $(document).window()._.execScript(text);
79
+ current_Document.win()._.execScript(text);
82
80
  } else {
83
81
  $E('script', {text: text}).insertTo(HTML);
84
82
  }
@@ -92,7 +90,7 @@ $eval = RightJS.$eval = function(text) {
92
90
  * @throws Break
93
91
  */
94
92
  $break = RightJS.$break = function() {
95
- throw new RightJS.Break();
93
+ throw new Break();
96
94
  },
97
95
 
98
96
  /**
@@ -189,7 +187,7 @@ isArray = RightJS.isArray = function(value) {
189
187
  * @return boolean check result
190
188
  */
191
189
  isElement = RightJS.isElement = function(value) {
192
- return !!(value && value.tagName);
190
+ return value != null && value.nodeType === 1;
193
191
  },
194
192
 
195
193
  /** !#server
@@ -199,7 +197,7 @@ isElement = RightJS.isElement = function(value) {
199
197
  * @return boolean check result
200
198
  */
201
199
  isNode = RightJS.isNode = function(value) {
202
- return !!(value && value.nodeType);
200
+ return value != null && value.nodeType != null;
203
201
  },
204
202
 
205
203
  /** !#server
@@ -209,37 +207,24 @@ isNode = RightJS.isNode = function(value) {
209
207
  * @return Element or null
210
208
  */
211
209
  $ = RightJS.$ = function(object) {
212
- if (typeof object === 'string') {
210
+ if (object instanceof Wrapper) {
211
+ return object;
212
+ } else if (typeof object === 'string') {
213
213
  object = document.getElementById(object);
214
214
  }
215
215
 
216
- if (object) {
217
- var wrapper = UID_KEY in object ? Wrappers_Cache[object[UID_KEY]] : undefined;
218
- if (wrapper !== undefined) {
219
- object = wrapper;
220
- } else if (object.nodeType === 1) {
221
- object = new Element(object);
222
- } else if (isElement(object.target) || isElement(object.srcElement)) {
223
- object = new Event(object);
224
- } else if (object.nodeType === 9) {
225
- object = new Document(object);
226
- } else if (object.window == object) {
227
- object = new Window(object);
228
- }
229
- }
230
-
231
- return object;
216
+ return wrap(object);
232
217
  },
233
218
 
234
219
  /** !#server
235
220
  * Finds all the elements in the document by the given css_rule
236
221
  *
237
222
  * @param String element
238
- * @param Object optional context
223
+ * @param Boolean raw search marker
239
224
  * @return Array search result
240
225
  */
241
- $$ = RightJS.$$ = function(css_rule, context) {
242
- return $(context || document).find(css_rule);
226
+ $$ = RightJS.$$ = function(css_rule, raw) {
227
+ return current_Document.find(css_rule, raw);
243
228
  },
244
229
 
245
230
  /** !#server
@@ -263,23 +248,6 @@ $w = RightJS.$w = function(string) {
263
248
  return string.trim().split(/\s+/);
264
249
  },
265
250
 
266
- /**
267
- * converts any iterables into an array
268
- *
269
- * @param Object iterable
270
- * @return Array list
271
- */
272
- $A = RightJS.$A = function(it) {
273
- try {
274
- return slice.call(it);
275
- } catch(e) {
276
- for (var a=[], i=0, length = it.length; i < length; i++) {
277
- a[i] = it[i];
278
- }
279
- return a;
280
- }
281
- },
282
-
283
251
  /**
284
252
  * generates an unique id for an object
285
253
  *
@@ -288,16 +256,42 @@ $A = RightJS.$A = function(it) {
288
256
  */
289
257
  $uid = RightJS.$uid = function(item) {
290
258
  return UID_KEY in item ? item[UID_KEY] : (item[UID_KEY] = UID++);
259
+ },
260
+
261
+ /**
262
+ * converts any iterables into an array
263
+ *
264
+ * @param Object iterable
265
+ * @return Array list
266
+ */
267
+ $A = RightJS.$A = function(it) {
268
+ return slice.call(it, 0);
291
269
  };
292
270
 
271
+ /** !#server
272
+ * IE needs a patch for the $A function
273
+ * because it doesn't handle all the cases
274
+ */
275
+ if (!A_proto.map) {
276
+ $A = RightJS.$A = function(it) {
277
+ try {
278
+ return slice.call(it, 0);
279
+ } catch(e) {
280
+ for (var a=[], i=0, length = it.length; i < length; i++) {
281
+ a[i] = it[i];
282
+ }
283
+ return a;
284
+ }
285
+ };
286
+ }
287
+
293
288
  /** !#server
294
289
  * Internet Explorer needs some additional mumbo-jumbo in here
295
290
  */
296
291
  if (isHash(HTML)) {
297
292
  isHash = RightJS.isHash = function(value) {
298
293
  return to_s.call(value) === '[object Object]' &&
299
- value !== null && typeof(value) !== 'undefined' &&
300
- typeof(value.hasOwnProperty) !== 'undefined';
294
+ value != null && value.hasOwnProperty != null;
301
295
  };
302
296
  }
303
297
  /**
@@ -307,7 +301,7 @@ var i=0, natives = 'Array Function Number String Date RegExp'.split(' '),
307
301
  include_native = function() {
308
302
  for (var i=0; i < arguments.length; i++) {
309
303
  if (isHash(arguments[i])) {
310
- $ext(this[PROTO], arguments[i]);
304
+ $ext(this.prototype, arguments[i]);
311
305
  $ext(this.Methods, arguments[i]);
312
306
  }
313
307
  }
@@ -324,19 +318,6 @@ for (; i < natives.length; i++) {
324
318
  RightJS.Object = Object;
325
319
  RightJS.Math = Math;
326
320
 
327
-
328
- /** #!server
329
- * A functions brutal hackery helper
330
- *
331
- * @param Function original function
332
- * @param RegExp expression
333
- * @param String replacement
334
- * @return freshly hacked function
335
- */
336
- function patch_function(func, re, replacement) {
337
- return eval('['+ func.toString().replace(re, replacement) + ']')[0];
338
- }
339
-
340
321
  /**
341
322
  * Checks if the data is an array and if not,
342
323
  * then makes an array out of it
@@ -356,7 +337,7 @@ function ensure_array(data) {
356
337
  * Some functionality is inspired by
357
338
  * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
358
339
  *
359
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
340
+ * Copyright (C) 2008-2011 Nikolay V. Nemshilov
360
341
  */
361
342
  $ext(Object, {
362
343
  /**
@@ -485,10 +466,13 @@ $ext(Object, {
485
466
  * @return Object merged object
486
467
  */
487
468
  merge: function() {
488
- var object = {}, i=0, length = arguments.length;
489
- for (; i < length; i++) {
490
- if (isHash(arguments[i])) {
491
- $ext(object, arguments[i]);
469
+ var object = {}, i=0, args=arguments, key;
470
+ for (; i < args.length; i++) {
471
+ if (isHash(args[i])) {
472
+ for (key in args[i]) {
473
+ object[key] = isHash(args[i][key]) && !(args[i][key] instanceof Class) ?
474
+ Object.merge(key in object ? object[key] : {}, args[i][key]) : args[i][key];
475
+ }
492
476
  }
493
477
  }
494
478
  return object;
@@ -557,34 +541,76 @@ Math.random = function(min, max) {
557
541
  * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
558
542
  * - Ruby (http://www.ruby-lang.org) Copyright (C) Yukihiro Matsumoto
559
543
  *
560
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
544
+ * Copyright (C) 2008-2010 Nikolay Nemshilov
561
545
  */
562
546
  var original_sort = A_proto.sort,
563
547
 
564
- build_loop = function(pre, body, ret) {
565
- return eval('[function(c,s){'+
566
- 'for(var '+pre+'i=0,l=this.length;i<l;i++){'+
567
- body.replace('_', 'c.call(s,this[i],i,this)') +
568
- '}' +
569
- ret +
570
- '}]')[0];
548
+ // JavaScript 1.6 methods recatching up or faking
549
+ for_each = A_proto.forEach || function(callback, scope) {
550
+ for (var i=0; i < this.length; i++) {
551
+ callback.call(scope, this[i], i, this);
552
+ }
553
+ },
554
+
555
+ filter = A_proto.filter || function(callback, scope) {
556
+ for (var result=[], j=0, i=0; i < this.length; i++) {
557
+ if (callback.call(scope, this[i], i, this)) {
558
+ result[j++] = this[i];
559
+ }
560
+ }
561
+ return result;
562
+ },
563
+
564
+ reject = function(callback, scope) {
565
+ for (var result=[], j=0, i=0; i < this.length; i++) {
566
+ if (!callback.call(scope, this[i], i, this)) {
567
+ result[j++] = this[i];
568
+ }
569
+ }
570
+ return result;
571
+ },
572
+
573
+ map = A_proto.map || function(callback, scope) {
574
+ for (var result=[], i=0; i < this.length; i++) {
575
+ result[i] = callback.call(scope, this[i], i, this);
576
+ }
577
+ return result;
578
+ },
579
+
580
+ some = A_proto.some || function(callback, scope) {
581
+ for (var i=0; i < this.length; i++) {
582
+ if (callback.call(scope, this[i], i, this)) {
583
+ return true;
584
+ }
585
+ }
586
+ return false;
587
+ },
588
+
589
+ every = A_proto.every || function(callback, scope) {
590
+ for (var i=0; i < this.length; i++) {
591
+ if (!callback.call(scope, this[i], i, this)) {
592
+ return false;
593
+ }
594
+ }
595
+ return true;
596
+ },
597
+
598
+ first = function(callback, scope) {
599
+ for (var i=0; i < this.length; i++) {
600
+ if (callback.call(scope, this[i], i, this)) {
601
+ return this[i];
602
+ }
603
+ }
604
+ return undefined;
571
605
  },
572
606
 
573
- // JavaScript 1.6 methods recatching up or faking
574
- for_each = A_proto.forEach || build_loop('', '_', ''),
575
- filter = A_proto.filter || build_loop('r=[],j=0,', 'if(_)r[j++]=this[i]', 'return r'),
576
- reject = build_loop('r=[],j=0,', 'if(!_)r[j++]=this[i]', 'return r'),
577
- map = A_proto.map || build_loop('r=[],', 'r[i]=_', 'return r'),
578
- some = A_proto.some || build_loop('', 'if(_)return true', 'return false'),
579
- every = A_proto.every || build_loop('', 'if(!_)return false', 'return true'),
580
- first = build_loop('', 'if(_)return this[i]', 'return [][0]'),
581
607
  last = function(callback, scope) {
582
608
  for (var i=this.length-1; i > -1; i--) {
583
609
  if (callback.call(scope, this[i], i, this)) {
584
610
  return this[i];
585
611
  }
586
612
  }
587
- return null;
613
+ return undefined;
588
614
  };
589
615
 
590
616
 
@@ -596,9 +622,9 @@ last = function(callback, scope) {
596
622
  function guess_callback(argsi, array) {
597
623
  var callback = argsi[0], args = slice.call(argsi, 1), scope = array, attr;
598
624
 
599
- if (isString(callback)) {
625
+ if (typeof(callback) === 'string') {
600
626
  attr = callback;
601
- if (array.length && isFunction(array[0][attr])) {
627
+ if (array.length !== 0 && typeof(array[0][attr]) === 'function') {
602
628
  callback = function(object) { return object[attr].apply(object, args); };
603
629
  } else {
604
630
  callback = function(object) { return object[attr]; };
@@ -610,15 +636,16 @@ function guess_callback(argsi, array) {
610
636
  return [callback, scope];
611
637
  }
612
638
 
639
+ // defining the manual break errors class
640
+ function Break() {}
641
+
613
642
  // calls the given method with preprocessing the arguments
614
643
  function call_method(func, scope, args) {
615
- var result;
616
-
617
644
  try {
618
- result = func.apply(scope, guess_callback(args, scope));
619
- } catch(e) { if (!(e instanceof RightJS.Break)) { throw(e); } }
645
+ return func.apply(scope, guess_callback(args, scope));
646
+ } catch(e) { if (!(e instanceof Break)) { throw(e); } }
620
647
 
621
- return result;
648
+ return undefined;
622
649
  }
623
650
 
624
651
  // checks the value as a boolean
@@ -641,7 +668,7 @@ Array.include({
641
668
  * @return Integer index or -1 if not found
642
669
  */
643
670
  indexOf: A_proto.indexOf || function(value, from) {
644
- for (var i=(from<0) ? Math.max(0, this.length+from) : from || 0, l = this.length; i < l; i++) {
671
+ for (var i=(from<0) ? Math.max(0, this.length+from) : from || 0; i < this.length; i++) {
645
672
  if (this[i] === value) {
646
673
  return i;
647
674
  }
@@ -689,7 +716,7 @@ Array.include({
689
716
  * @return mixed a random item
690
717
  */
691
718
  random: function() {
692
- return this.length ? this[Math.random(this.length-1)] : null;
719
+ return this.length === 0 ? undefined : this[Math.random(this.length-1)];
693
720
  },
694
721
 
695
722
  /**
@@ -716,7 +743,7 @@ Array.include({
716
743
  * @return boolean check result
717
744
  */
718
745
  empty: function() {
719
- return !this.length;
746
+ return this.length === 0;
720
747
  },
721
748
 
722
749
  /**
@@ -818,11 +845,10 @@ Array.include({
818
845
  * @return Array new merged
819
846
  */
820
847
  merge: function() {
821
- for (var copy = this.clone(), arg, i=0, j, length = arguments.length; i < length; i++) {
822
- arg = arguments[i];
823
- arg = ensure_array(arg);
848
+ for (var copy = this.clone(), arg, i=0; i < arguments.length; i++) {
849
+ arg = ensure_array(arguments[i]);
824
850
 
825
- for (j=0; j < arg.length; j++) {
851
+ for (var j=0; j < arg.length; j++) {
826
852
  if (copy.indexOf(arg[j]) == -1) {
827
853
  copy.push(arg[j]);
828
854
  }
@@ -875,8 +901,8 @@ Array.include({
875
901
  * @return boolean check result
876
902
  */
877
903
  includes: function() {
878
- for (var i=0, length = arguments.length; i < length; i++) {
879
- if (this.indexOf(arguments[i]) == -1) {
904
+ for (var i=0; i < arguments.length; i++) {
905
+ if (this.indexOf(arguments[i]) === -1) {
880
906
  return false;
881
907
  }
882
908
  }
@@ -891,9 +917,9 @@ Array.include({
891
917
  * @return Array filtered copy
892
918
  */
893
919
  without: function() {
894
- var filter = $A(arguments);
920
+ var filter = slice.call(arguments);
895
921
  return this.filter(function(value) {
896
- return !filter.include(value);
922
+ return filter.indexOf(value) === -1;
897
923
  });
898
924
  },
899
925
 
@@ -962,14 +988,12 @@ Array.include({
962
988
  * @return Number a summ of values on the list
963
989
  */
964
990
  sum: function() {
965
- for(var i=0,l=this.length,sum=0; i < l; sum += this[i++]) {}
991
+ for(var sum=0, i=0; i<this.length; sum += this[i++]) {}
966
992
  return sum;
967
993
  }
968
994
  });
969
995
 
970
- $alias(A_proto, {
971
- include: 'includes'
972
- });
996
+ A_proto.include = A_proto.includes;
973
997
 
974
998
 
975
999
  /**
@@ -981,7 +1005,7 @@ $alias(A_proto, {
981
1005
  * The trim function taken from work of Steven Levithan
982
1006
  * - http://blog.stevenlevithan.com/archives/faster-trim-javascript
983
1007
  *
984
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
1008
+ * Copyright (C) 2008-2011 Nikolay V. Nemshilov
985
1009
  */
986
1010
  String.include({
987
1011
  /**
@@ -999,7 +1023,7 @@ String.include({
999
1023
  * @return boolean check result
1000
1024
  */
1001
1025
  blank: function() {
1002
- return (/^\s*$/).test(this);
1026
+ return this == false;
1003
1027
  },
1004
1028
 
1005
1029
  /**
@@ -1007,7 +1031,7 @@ String.include({
1007
1031
  *
1008
1032
  * @return String trimmed version
1009
1033
  */
1010
- trim: String[PROTO].trim || function() {
1034
+ trim: String.prototype.trim || function() {
1011
1035
  var str = this.replace(/^\s\s*/, ''), i = str.length;
1012
1036
  while ((/\s/).test(str.charAt(--i))) {}
1013
1037
  return str.slice(0, i + 1);
@@ -1028,10 +1052,13 @@ String.include({
1028
1052
  * @return String without scripts
1029
1053
  */
1030
1054
  stripScripts: function(option) {
1031
- var scripts = '', text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/img, function(match, source) {
1032
- scripts += source + "\n";
1033
- return '';
1034
- });
1055
+ var scripts = '', text = this.replace(
1056
+ /<script[^>]*>([\s\S]*?)<\/script>/img,
1057
+ function(match, source) {
1058
+ scripts += source + "\n";
1059
+ return '';
1060
+ }
1061
+ );
1035
1062
 
1036
1063
  if (option === true) {
1037
1064
  $eval(scripts);
@@ -1108,9 +1135,9 @@ String.include({
1108
1135
  * @return boolean check result
1109
1136
  */
1110
1137
  startsWith: function(string, ignorecase) {
1111
- var start_str = this.substr(0, string.length);
1112
- return ignorecase ? start_str.toLowerCase() === string.toLowerCase() :
1113
- start_str === string;
1138
+ return (ignorecase !== true ? this.indexOf(string) :
1139
+ this.toLowerCase().indexOf(string.toLowerCase())
1140
+ ) === 0;
1114
1141
  },
1115
1142
 
1116
1143
  /**
@@ -1121,9 +1148,10 @@ String.include({
1121
1148
  * @return boolean check result
1122
1149
  */
1123
1150
  endsWith: function(string, ignorecase) {
1124
- var end_str = this.substring(this.length - string.length);
1125
- return ignorecase ? end_str.toLowerCase() === string.toLowerCase() :
1126
- end_str === string;
1151
+ return this.length - (
1152
+ ignorecase !== true ? this.lastIndexOf(string) :
1153
+ this.toLowerCase().lastIndexOf(string.toLowerCase())
1154
+ ) === string.length;
1127
1155
  },
1128
1156
 
1129
1157
  /**
@@ -1132,7 +1160,7 @@ String.include({
1132
1160
  * @return Integer or NaN
1133
1161
  */
1134
1162
  toInt: function(base) {
1135
- return parseInt(this, base || 10);
1163
+ return parseInt(this, base === undefined ? 10 : base);
1136
1164
  },
1137
1165
 
1138
1166
  /**
@@ -1141,12 +1169,13 @@ String.include({
1141
1169
  * @return Float or NaN
1142
1170
  */
1143
1171
  toFloat: function(strict) {
1144
- return parseFloat(strict ? this : this.replace(',', '.').replace(/(\d)-(\d)/g, '$1.$2'));
1172
+ return parseFloat(strict === true ? this :
1173
+ this.replace(',', '.').replace(/(\d)-(\d)/, '$1.$2'));
1145
1174
  }
1146
1175
 
1147
1176
  });
1148
1177
 
1149
- $alias(String[PROTO], {include: 'includes'});
1178
+ String.prototype.include = String.prototype.includes;
1150
1179
 
1151
1180
 
1152
1181
  /**
@@ -1156,7 +1185,7 @@ $alias(String[PROTO], {include: 'includes'});
1156
1185
  * Some of the functionality inspired by
1157
1186
  * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
1158
1187
  *
1159
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
1188
+ * Copyright (C) 2008-2011 Nikolay V. Nemshilov
1160
1189
  */
1161
1190
  Function.include({
1162
1191
  /**
@@ -1170,7 +1199,10 @@ Function.include({
1170
1199
  bind: function() {
1171
1200
  var args = $A(arguments), scope = args.shift(), func = this;
1172
1201
  return function() {
1173
- return func.apply(scope, (args.length || arguments.length) ? args.concat($A(arguments)) : args);
1202
+ return func.apply(scope,
1203
+ (args.length !== 0 || arguments.length !== 0) ?
1204
+ args.concat($A(arguments)) : args
1205
+ );
1174
1206
  };
1175
1207
  },
1176
1208
 
@@ -1362,81 +1394,65 @@ RegExp.escape = function(string) {
1362
1394
  * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
1363
1395
  * - Ruby (http://www.ruby-lang.org) Copyright (C) Yukihiro Matsumoto
1364
1396
  *
1365
- * Copyright (C) 2008-2010 Nikolay Nemshilov
1397
+ * Copyright (C) 2008-2011 Nikolay Nemshilov
1366
1398
  */
1367
1399
  var Class = RightJS.Class = function() {
1368
- var args = $A(arguments), properties = args.pop() || {},
1369
- parent = args.pop();
1400
+ var args = $A(arguments).slice(0,2),
1401
+ props = args.pop() || {},
1402
+ parent = args.pop(),
1403
+ klass = arguments[2], // you can send your own klass as the third argument
1404
+ SKlass = function() {};
1405
+
1406
+ // if the parent class only was specified
1407
+ if (!args.length && !isHash(props)) {
1408
+ parent = props; props = {};
1409
+ }
1370
1410
 
1371
1411
  // !#server:begin
1372
- if (parent && parent.ancestors && parent.ancestors[0] === Wrapper) {
1373
- return new Wrapper(parent, properties);
1412
+ if (!klass && parent && (parent === Wrapper || parent.ancestors.include(Wrapper))) {
1413
+ klass = Wrapper_makeKlass();
1374
1414
  }
1375
1415
  // !#server:end
1376
1416
 
1377
- // basic class object definition
1378
- function klass() {
1379
- if ('prebind' in this && isArray(this.prebind)) {
1380
- this.prebind.each(function(method) {
1381
- this[method] = this[method].bind(this);
1382
- }, this);
1383
- }
1384
-
1385
- return this.initialize ? this.initialize.apply(this, arguments) : this;
1417
+ // defining the basic klass function
1418
+ klass = $ext(klass || function() {
1419
+ Class_checkPrebind(this);
1420
+ return 'initialize' in this ?
1421
+ this.initialize.apply(this, arguments) :
1422
+ this;
1423
+ }, Class_Methods);
1424
+
1425
+ // handling the inheritance
1426
+ parent = parent || Class;
1427
+
1428
+ SKlass.prototype = parent.prototype;
1429
+ klass.prototype = new SKlass();
1430
+ klass.parent = parent;
1431
+ klass.prototype.constructor = klass;
1432
+
1433
+ // collecting the list of ancestors
1434
+ klass.ancestors = [];
1435
+ while (parent) {
1436
+ klass.ancestors.push(parent);
1437
+ parent = parent.parent;
1386
1438
  }
1387
1439
 
1388
- // if only the parent class has been specified
1389
- if (!args.length && !isHash(properties)) {
1390
- parent = properties; properties = {};
1391
- }
1392
-
1393
- // attaching main class-level methods
1394
- $ext(klass, Class_Methods).inherit(parent);
1395
-
1396
- // catching the injections
1397
- Class_attachInjections(klass, properties);
1440
+ // handling the module injections
1441
+ ['extend', 'include'].each(function(name) {
1442
+ if (name in props) {
1443
+ klass[name].apply(klass, ensure_array(props[name]));
1444
+ }
1445
+ });
1398
1446
 
1399
- return klass.include(properties);
1447
+ return klass.include(props);
1400
1448
  },
1401
1449
 
1402
1450
  /**
1403
1451
  * Class utility methods
1404
1452
  *
1405
- * Copyright (C) 2008-2010 Nikolay Nemshilov
1453
+ * Copyright (C) 2008-2011 Nikolay Nemshilov
1406
1454
  */
1407
- commons = $w('selfExtended self_extended selfIncluded self_included'),
1408
- extend = commons.concat($w(PROTO+' parent extend include')),
1409
- include = commons.concat(['constructor']),
1410
- clean_module = function (module, ext) {
1411
- return Object.without.apply(Object, [module].concat(ext ? extend : include));
1412
- },
1413
-
1414
1455
  Class_Methods = {
1415
- /**
1416
- * Makes the class get inherited from another one
1417
- *
1418
- * @param Object another class
1419
- * @return Class this
1420
- */
1421
- inherit: function(parent) {
1422
- // handling the parent class assign
1423
- if (parent && parent[PROTO]) {
1424
- var s_klass = dummy();
1425
- s_klass[PROTO] = parent[PROTO];
1426
- this[PROTO] = new s_klass();
1427
- this.parent = parent;
1428
- }
1429
-
1430
- // collecting the list of ancestors
1431
- this.ancestors = [];
1432
- while (parent) {
1433
- this.ancestors.push(parent);
1434
- parent = parent.parent;
1435
- }
1436
-
1437
- return (this[PROTO].constructor = this);
1438
- },
1439
-
1440
1456
  /**
1441
1457
  * this method will extend the class-level with the given objects
1442
1458
  *
@@ -1453,13 +1469,8 @@ Class_Methods = {
1453
1469
  */
1454
1470
  extend: function() {
1455
1471
  $A(arguments).filter(isHash).each(function(module) {
1456
- var callback = module.selfExtended || module.self_extended;
1457
-
1458
- $ext(this, clean_module(module, true));
1459
-
1460
- if (callback) {
1461
- callback.call(module, this);
1462
- }
1472
+ $ext(this, Class_clean_module(module, true));
1473
+ Class_handle_module_callbacks(this, module, true);
1463
1474
  }, this);
1464
1475
 
1465
1476
  return this;
@@ -1475,44 +1486,53 @@ Class_Methods = {
1475
1486
  * @return Class the klass
1476
1487
  */
1477
1488
  include: function() {
1478
- var ancestors = (this.ancestors || []).map(PROTO);
1489
+ var klasses = [this].concat(this.ancestors);
1479
1490
 
1480
1491
  $A(arguments).filter(isHash).each(function(module) {
1481
- var callback = module.selfIncluded || module.self_included;
1482
-
1483
- Object.each(clean_module(module, false), function(key, method) {
1484
- var ancestor = ancestors.first(function(proto) { return key in proto && isFunction(proto[key]); });
1492
+ Object.each(Class_clean_module(module, false), function(name, method) {
1493
+ // searching for the super-method
1494
+ for (var super_method, i=0; i < klasses.length; i++) {
1495
+ if (name in klasses[i].prototype) {
1496
+ super_method = klasses[i].prototype[name];
1497
+ break;
1498
+ }
1499
+ }
1485
1500
 
1486
- this[PROTO][key] = !ancestor ? method : function() {
1487
- this.$super = ancestor[key];
1488
- return method.apply(this, arguments);
1489
- };
1501
+ this.prototype[name] = isFunction(method) && isFunction(super_method) ?
1502
+ function() {
1503
+ this.$super = super_method;
1504
+ return method.apply(this, arguments);
1505
+ } : method;
1490
1506
  }, this);
1491
1507
 
1492
- if (callback) {
1493
- callback.call(module, this);
1494
- }
1508
+ Class_handle_module_callbacks(this, module, false);
1495
1509
  }, this);
1496
1510
 
1497
1511
  return this;
1498
1512
  }
1499
- };
1513
+ },
1500
1514
 
1501
- /**
1502
- * Processess the functionality injection properties
1503
- *
1504
- * @param Function klass
1505
- * @param Object properties
1506
- * @return void
1507
- */
1508
- function Class_attachInjections(klass, properties) {
1509
- ['extend', 'include'].each(function(name) {
1510
- var modules = properties[name];
1511
- if (isHash(modules) || isArray(modules)) {
1512
- klass[name].apply(klass, ensure_array(modules));
1513
- delete(properties[name]);
1514
- }
1515
- });
1515
+ Class_module_callback_names = $w(
1516
+ 'selfExtended self_extended selfIncluded self_included extend include'
1517
+ );
1518
+
1519
+ // hooking up the class-methods to the root class
1520
+ $ext(Class, Class_Methods);
1521
+ Class.prototype.$super = undefined;
1522
+
1523
+ function Class_clean_module(module, extend) {
1524
+ return Object.without.apply(Object, [module].concat(
1525
+ Class_module_callback_names.concat( extend ?
1526
+ $w('prototype parent ancestors') : ['constructor']
1527
+ )
1528
+ ));
1529
+ }
1530
+
1531
+ function Class_handle_module_callbacks(klass, module, extend) {
1532
+ (module[Class_module_callback_names[extend ? 0 : 2]] ||
1533
+ module[Class_module_callback_names[extend ? 1 : 3]] ||
1534
+ function() {}
1535
+ ).call(module, klass);
1516
1536
  }
1517
1537
 
1518
1538
  /**
@@ -1528,14 +1548,35 @@ function Class_attachInjections(klass, properties) {
1528
1548
  * @return Object hash or null if nothing found
1529
1549
  */
1530
1550
  function Class_findSet(object, property) {
1531
- var upcased = property.toUpperCase(), capcased = property.capitalize(),
1551
+ var upcased = property.toUpperCase(),
1532
1552
  constructor = object.constructor,
1533
- candidates = [object, constructor].concat('ancestors' in constructor ? constructor.ancestors : []),
1534
- holder = candidates.first(function(o) { return o && (upcased in o || capcased in o); });
1553
+ candidates = [object, constructor].concat(constructor.ancestors || []),
1554
+ i = 0;
1555
+
1556
+ for (; i < candidates.length; i++) {
1557
+ if (upcased in candidates[i]) {
1558
+ return candidates[i][upcased];
1559
+ } else if (property in candidates[i]) {
1560
+ return candidates[i][property];
1561
+ }
1562
+ }
1535
1563
 
1536
- return holder ? holder[upcased] || holder[capcased] : null;
1564
+ return null;
1537
1565
  }
1538
1566
 
1567
+ /**
1568
+ * Handles the 'prebind' feature for Class instances
1569
+ *
1570
+ * @param Class instance
1571
+ * @return void
1572
+ */
1573
+ function Class_checkPrebind(object) {
1574
+ if ('prebind' in object && isArray(object.prebind)) {
1575
+ object.prebind.each(function(method) {
1576
+ object[method] = object[method].bind(object);
1577
+ });
1578
+ }
1579
+ }
1539
1580
 
1540
1581
  /**
1541
1582
  * This is a simple mix-in module to be included in other classes
@@ -1547,7 +1588,7 @@ function Class_findSet(object, property) {
1547
1588
  * The idea of the module is inspired by
1548
1589
  * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
1549
1590
  *
1550
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
1591
+ * Copyright (C) 2008-2011 Nikolay V. Nemshilov
1551
1592
  */
1552
1593
  var Options = RightJS.Options = {
1553
1594
  /**
@@ -1557,7 +1598,9 @@ var Options = RightJS.Options = {
1557
1598
  * @return Object current instance
1558
1599
  */
1559
1600
  setOptions: function(opts) {
1560
- var options = this.options = Object.merge(Class_findSet(this, 'options'), opts), match, key;
1601
+ var options = this.options = $ext($ext({},
1602
+ Object.clone(Class_findSet(this, 'Options'))), opts
1603
+ ), match, key;
1561
1604
 
1562
1605
  // hooking up the observer options
1563
1606
  if (isFunction(this.on)) {
@@ -1597,7 +1640,7 @@ var Options = RightJS.Options = {
1597
1640
  * The naming principle is inspired by
1598
1641
  * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
1599
1642
  *
1600
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
1643
+ * Copyright (C) 2008-2011 Nikolay Nemshilov
1601
1644
  */
1602
1645
  var Observer = RightJS.Observer = new Class({
1603
1646
  include: Options,
@@ -1609,7 +1652,7 @@ var Observer = RightJS.Observer = new Class({
1609
1652
  */
1610
1653
  initialize: function(options) {
1611
1654
  this.setOptions(options);
1612
- Observer_createShortcuts(this, Class_findSet(this, 'events'));
1655
+ Observer_createShortcuts(this, Class_findSet(this, 'Events'));
1613
1656
  return this;
1614
1657
  },
1615
1658
 
@@ -1624,51 +1667,7 @@ var Observer = RightJS.Observer = new Class({
1624
1667
  * @return Observer self
1625
1668
  */
1626
1669
  on: function() {
1627
- var args = $A(arguments), event = args.shift(), name;
1628
-
1629
- if (isString(event)) {
1630
- if (!('$listeners' in this)) { this.$listeners = []; }
1631
-
1632
- var callback = args.shift();
1633
- switch (typeof callback) {
1634
- case "string":
1635
- name = callback;
1636
- callback = this[callback];
1637
-
1638
- case "function":
1639
- var hash = {};
1640
-
1641
- // DON'T move it in the one-line hash variable definition,
1642
- // it causes problems with the Konqueror 3 later on
1643
- hash.e = event;
1644
- hash.f = callback;
1645
- hash.a = args;
1646
- hash.r = name;
1647
-
1648
- this.$listeners.push(hash);
1649
- break;
1650
-
1651
- default:
1652
- if (isArray(callback)) {
1653
- for (var i=0; i < callback.length; i++) {
1654
- this.on.apply(this, [event].concat(
1655
- ensure_array(callback[i])
1656
- ).concat(args));
1657
- }
1658
- }
1659
- }
1660
-
1661
- } else {
1662
- // assuming it's a hash of key-value pairs
1663
- for (name in event) {
1664
- this.on.apply(this, [name].concat(
1665
- ensure_array(event[name])
1666
- ).concat(args));
1667
- }
1668
- }
1669
-
1670
-
1671
-
1670
+ Observer_on(this, arguments, function(h) { return h; });
1672
1671
  return this;
1673
1672
  },
1674
1673
 
@@ -1684,7 +1683,7 @@ var Observer = RightJS.Observer = new Class({
1684
1683
  */
1685
1684
  observes: function(event, callback) {
1686
1685
  if (!isString(event)) { callback = event; event = null; }
1687
- if (isString(callback)) { callback = this[callback]; }
1686
+ if (isString(callback)) { callback = callback in this ? this[callback] : null; }
1688
1687
 
1689
1688
  return (this.$listeners || []).some(function(i) {
1690
1689
  return (event && callback) ? i.e === event && i.f === callback :
@@ -1703,20 +1702,7 @@ var Observer = RightJS.Observer = new Class({
1703
1702
  * @return Observer self
1704
1703
  */
1705
1704
  stopObserving: function(event, callback) {
1706
- if (isHash(event)) {
1707
- for (var key in event) {
1708
- this.stopObserving(key, event[key]);
1709
- }
1710
- } else {
1711
- if (!isString(event)) { callback = event; event = null; }
1712
- if (isString(callback)){ callback = this[callback]; }
1713
-
1714
- this.$listeners = (this.$listeners || []).filter(function(i) {
1715
- return (event && callback) ? (i.e !== event || i.f !== callback) :
1716
- (event ? i.e !== event : i.f !== callback);
1717
- }, this);
1718
- }
1719
-
1705
+ Observer_stopObserving(this, event, callback, function() {});
1720
1706
  return this;
1721
1707
  },
1722
1708
 
@@ -1764,8 +1750,8 @@ var Observer = RightJS.Observer = new Class({
1764
1750
  * @return Object extended object
1765
1751
  */
1766
1752
  Observer_create = Observer.create = function(object, events) {
1767
- $ext(object, Object.without(Observer[PROTO], 'initialize', 'setOptions'), true);
1768
- return Observer_createShortcuts(object, events || Class_findSet(object, 'events'));
1753
+ $ext(object, Object.without(Observer.prototype, 'initialize', 'setOptions'), true);
1754
+ return Observer_createShortcuts(object, events || Class_findSet(object, 'Events'));
1769
1755
  },
1770
1756
 
1771
1757
  /**
@@ -1777,7 +1763,10 @@ Observer_create = Observer.create = function(object, events) {
1777
1763
  */
1778
1764
  Observer_createShortcuts = Observer.createShortcuts = function(object, names) {
1779
1765
  (names || []).each(function(name) {
1780
- var method_name = 'on'+name.replace(/(^|_|:)([a-z])/g, function(match, pre, chr) { return chr.toUpperCase(); });
1766
+ var method_name = 'on'+name.replace(/(^|_|:)([a-z])/g,
1767
+ function(match, pre, chr) { return chr.toUpperCase(); }
1768
+ );
1769
+
1781
1770
  if (!(method_name in object)) {
1782
1771
  object[method_name] = function() {
1783
1772
  return this.on.apply(this, [name].concat($A(arguments)));
@@ -1788,35 +1777,100 @@ Observer_createShortcuts = Observer.createShortcuts = function(object, names) {
1788
1777
  return object;
1789
1778
  };
1790
1779
 
1780
+ function Observer_on(object, o_args, preprocess) {
1781
+ var args = slice.call(o_args, 2),
1782
+ event = o_args[0],
1783
+ callback = o_args[1],
1784
+ name = false;
1785
+
1786
+ if (isString(event)) {
1787
+ switch (typeof callback) {
1788
+ case "string":
1789
+ name = callback;
1790
+ callback = callback in object ? object[callback] : function() {};
1791
+
1792
+ case "function":
1793
+ ('$listeners' in object ? object.$listeners : (
1794
+ object.$listeners = []
1795
+ )).push(preprocess({
1796
+ e: event, f: callback, a: args, r: name || false, t: object
1797
+ }));
1798
+ break;
1799
+
1800
+ default:
1801
+ if (isArray(callback)) {
1802
+ for (var i=0; i < callback.length; i++) {
1803
+ object.on.apply(object, [event].concat(
1804
+ ensure_array(callback[i])
1805
+ ).concat(args));
1806
+ }
1807
+ }
1808
+ }
1809
+
1810
+ } else {
1811
+ // assuming it's a hash of key-value pairs
1812
+ args = slice.call(o_args, 1);
1791
1813
 
1792
- /**
1793
- * iterators in-callbacks break exception
1794
- *
1795
- * Copyright (C) 2009-2010 Nikolay V. Nemshilov
1796
- */
1797
- var Break = RightJS.Break = new Class(Error, {
1798
- message: "Manual break"
1799
- });
1814
+ for (name in event) {
1815
+ object.on.apply(object, [name].concat(
1816
+ ensure_array(event[name])
1817
+ ).concat(args));
1818
+ }
1819
+ }
1820
+ }
1821
+
1822
+ function Observer_stopObserving(object, event, callback, preprocess) {
1823
+ if (isHash(event)) {
1824
+ for (var key in event) {
1825
+ object.stopObserving(key, event[key]);
1826
+ }
1827
+ } else {
1828
+ if (!isString(event)) { callback = event; event = null; }
1829
+ if (isString(callback)){ callback = object[callback]; }
1830
+
1831
+ object.$listeners = (object.$listeners || []).filter(function(i) {
1832
+ var result = (event && callback) ?
1833
+ (i.e !== event || i.f !== callback) :
1834
+ (event ? i.e !== event : i.f !== callback);
1835
+
1836
+ if (!result) { preprocess(i); }
1837
+
1838
+ return result;
1839
+ });
1840
+ }
1841
+ }
1800
1842
 
1801
1843
 
1802
1844
  /**
1803
1845
  * this object will contain info about the current browser
1804
1846
  *
1805
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
1847
+ * Copyright (C) 2008-2011 Nikolay V. Nemshilov
1806
1848
  */
1807
- var agent = navigator.userAgent, looks_like_ie = 'attachEvent' in window, looks_like_opera = 'opera' in window,
1849
+ var agent = navigator.userAgent,
1850
+ Browser_Opera = 'opera' in window,
1851
+ Browser_IE = 'attachEvent' in window && !Browser_Opera,
1808
1852
 
1809
1853
  Browser = RightJS.Browser = {
1810
- IE: looks_like_ie && !looks_like_opera,
1811
- Opera: looks_like_opera,
1854
+ IE: Browser_IE,
1855
+ Opera: Browser_Opera,
1812
1856
  WebKit: agent.include('AppleWebKit/'),
1813
1857
  Gecko: agent.include('Gecko') && !agent.include('KHTML'),
1814
1858
  MobileSafari: /Apple.*Mobile.*Safari/.test(agent),
1815
1859
  Konqueror: agent.include('Konqueror'),
1816
1860
 
1817
- // marker for the browsers which don't give access to the HTMLElement unit
1818
- OLD: looks_like_ie && !looks_like_opera && !document.querySelector
1819
- };
1861
+ // internal marker for the browsers which require the olds module
1862
+ OLD: !document.querySelector,
1863
+ // internal marker for IE browsers version <= 8
1864
+ IE8L: false
1865
+ },
1866
+
1867
+ IE8_OR_LESS = false;
1868
+
1869
+ try {
1870
+ // checking if that an IE version <= 8
1871
+ document.createElement('<input/>');
1872
+ Browser.OLD = Browser.IE8L = IE8_OR_LESS = true;
1873
+ } catch(e) {}
1820
1874
 
1821
1875
 
1822
1876
  /**
@@ -1826,96 +1880,190 @@ Browser = RightJS.Browser = {
1826
1880
  * so that we could control the common functionality
1827
1881
  * among all the wrappers
1828
1882
  *
1829
- * Copyright (C) 2010 Nikolay Nemshilov
1883
+ * Copyright (C) 2010-2011 Nikolay Nemshilov
1830
1884
  */
1831
1885
 
1832
- var Wrapper = RightJS.Wrapper = function(parent, methods) {
1886
+ var Wrapper = RightJS.Wrapper = new Class({
1887
+ // predefining the property in the prototype
1888
+ _: undefined,
1889
+
1890
+ /**
1891
+ * Default constructor
1892
+ *
1893
+ * @param mixed raw dom unit
1894
+ * @return void
1895
+ */
1896
+ initialize: function(raw_object) {
1897
+ this._ = raw_object;
1898
+ }
1899
+ });
1833
1900
 
1834
- // creating the actual wrapper class
1835
- var Klass = function(object, options) {
1836
- this.initialize(object, options);
1901
+ // exposing the cache so it could be manupulated externally
1902
+ Wrapper.Cache = Wrappers_Cache;
1837
1903
 
1838
- var instance = this, unit = instance._, uid, cast;
1904
+ // instantiating the actual class object for a wrapper
1905
+ function Wrapper_makeKlass() {
1906
+ /**
1907
+ * Default wrappers Klass function
1908
+ *
1909
+ * @param mixed the raw object
1910
+ * @param Object options
1911
+ * @return void
1912
+ */
1913
+ return function(object, options) {
1914
+ Class_checkPrebind(this);
1839
1915
 
1840
- // dynamically typecasting in case if the user is creating
1841
- // an element of a subtype via the basic Element constructor
1842
- if (this.constructor === Element && (cast = Wrapper.Cast(unit)) !== undefined) {
1843
- instance = new cast(unit);
1844
- if ('$listeners' in this) {
1845
- instance.$listeners = this.$listeners;
1846
- }
1847
- }
1916
+ this.initialize.apply(this, arguments); // <- there might be a different number of args in a subclass
1848
1917
 
1849
- uid = UID_KEY in unit ? unit[UID_KEY] : (unit[UID_KEY] = UID++);
1918
+ var item = this._, uid = UID_KEY in item ? item[UID_KEY] :
1919
+ // NOTE we use positive indexes for dom-elements and negative for everything else
1920
+ (item[UID_KEY] = (item.nodeType === 1 ? 1 : -1) * UID++);
1850
1921
 
1851
- return (Wrappers_Cache[uid] = instance);
1922
+ Wrappers_Cache[uid] = this;
1852
1923
  };
1924
+ }
1853
1925
 
1854
- // finding the parent
1855
- if (!methods) {
1856
- methods = parent;
1857
- parent = null;
1858
- }
1926
+ /**
1927
+ * Element's own Klass function
1928
+ * we need that because it does some dynamic typecasting mumbo jumbo
1929
+ * plus we would like to optimize some stuff here and there
1930
+ *
1931
+ * @param raw dom element or the tag name
1932
+ * @param Object options
1933
+ * @return Element instance
1934
+ */
1935
+ function Element_Klass(element, options) {
1936
+ Element_initialize(this, element, options);
1859
1937
 
1860
- // hooking up the extedning tools and methods
1861
- $ext(Klass, Class_Methods).inherit(parent || Wrapper);
1938
+ var inst = this, raw = inst._, cast = Wrapper.Cast(raw),
1939
+ uid = UID_KEY in raw ? raw[UID_KEY] : (raw[UID_KEY] = UID++);
1940
+
1941
+ if (cast !== undefined) {
1942
+ inst = new cast(raw, options);
1943
+ if ('$listeners' in this) {
1944
+ inst.$listeners = this.$listeners;
1945
+ }
1946
+ }
1862
1947
 
1863
- // checking for the injections
1864
- Class_attachInjections(Klass, methods);
1948
+ Wrappers_Cache[uid] = inst;
1865
1949
 
1866
- // including the basic tools
1867
- return Klass.include({_: undefined}, methods);
1868
- };
1950
+ return inst;
1951
+ }
1869
1952
 
1870
1953
  // searches for a suitable class for dynamic typecasting
1871
1954
  Wrapper.Cast = function(unit) {
1872
1955
  return unit.tagName in Element_wrappers ? Element_wrappers[unit.tagName] : undefined;
1873
1956
  };
1874
1957
 
1875
- // exposing the cache so it could be manupulated externally
1876
- Wrapper.Cache = Wrappers_Cache;
1877
-
1878
-
1879
1958
  /**
1880
- * A simple document wrapper
1959
+ * Event's own Klass function, we don't need to check
1960
+ * nothing in here, don't need to hit the wrappers cache and so one
1881
1961
  *
1882
- * Copyright (C) 2010 Nikolay Nemshilov
1962
+ * @param raw dom-event or a string event-name
1963
+ * @param bounding element or an object with options
1964
+ * @return void
1883
1965
  */
1884
- var Document = RightJS.Document = new Wrapper({
1885
- initialize: function(document) {
1886
- this._ = document;
1887
- },
1966
+ function Event_Klass(event, bound_element) {
1967
+ if (typeof(event) === 'string') {
1968
+ event = $ext({type: event}, bound_element);
1969
+ this.stopped = event.bubbles === false;
1888
1970
 
1889
- // returns the window reference
1890
- window: function() {
1891
- return $(this._.defaultView || this._.parentWindow);
1971
+ if (isHash(bound_element)) {
1972
+ $ext(this, bound_element);
1973
+ }
1892
1974
  }
1893
- });
1975
+
1976
+ this._ = event;
1977
+ this.type = event.type;
1978
+
1979
+ this.which = event.which;
1980
+ this.keyCode = event.keyCode;
1981
+
1982
+ this.target = wrap(
1983
+ // Webkit throws events on textual nodes as well, gotta fix that
1984
+ event.target != null && 'nodeType' in event.target && event.target.nodeType === 3 ?
1985
+ event.target.parentNode : event.target
1986
+ );
1987
+
1988
+ this.currentTarget = wrap(event.currentTarget);
1989
+ this.relatedTarget = wrap(event.relatedTarget);
1990
+
1991
+ this.pageX = event.pageX;
1992
+ this.pageY = event.pageY;
1993
+
1994
+ // making old IE attrs looks like w3c standards
1995
+ if (IE8_OR_LESS && 'srcElement' in event) {
1996
+ this.which = event.button === 2 ? 3 : event.button === 4 ? 2 : 1;
1997
+
1998
+ this.target = wrap(event.srcElement) || bound_element;
1999
+ this.relatedTarget = this.target._ === event.fromElement ? wrap(event.toElement) : this.target;
2000
+ this.currentTarget = bound_element;
2001
+
2002
+ var scrolls = this.target.win().scrolls();
2003
+
2004
+ this.pageX = event.clientX + scrolls.x;
2005
+ this.pageY = event.clientY + scrolls.y;
2006
+ }
2007
+ }
1894
2008
 
1895
2009
 
1896
2010
  /**
1897
- * the window object extensions
2011
+ * Private quick wrapping function, unlike `$`
2012
+ * it doesn't search by ID and handle double-wrapps
2013
+ * just pure dom-wrapping functionality
1898
2014
  *
1899
- * Copyright (C) 2008-2010 Nikolay Nemshilov
2015
+ * @param raw dom unit
2016
+ * @return Wrapper dom-wrapper
1900
2017
  */
1901
- var Window = RightJS.Window = new Wrapper({
1902
- /**
1903
- * Basic constructor
1904
- *
1905
- * @param Window dom-window reference
1906
- * @return void
1907
- */
1908
- initialize: function(window) {
1909
- this._ = window;
1910
- this.d = window.document;
1911
- },
2018
+ function wrap(object) {
2019
+ if (object != null) {
2020
+ var wrapper = UID_KEY in object ? Wrappers_Cache[object[UID_KEY]] : undefined;
2021
+
2022
+ if (wrapper !== undefined) {
2023
+ return wrapper;
2024
+ } else if (object.nodeType === 1) {
2025
+ return new Element(object);
2026
+ } else if (object.nodeType === 9) {
2027
+ return new Document(object);
2028
+ } else if (object.window == object) {
2029
+ return new Window(object);
2030
+ } else if (isElement(object.target) || isElement(object.srcElement)) {
2031
+ return new Event(object);
2032
+ }
2033
+ }
2034
+
2035
+ return object;
2036
+ }
2037
+
2038
+ /**
2039
+ * A simple document wrapper
2040
+ *
2041
+ * Copyright (C) 2010-2011 Nikolay Nemshilov
2042
+ */
2043
+ var Document = RightJS.Document = new Class(Wrapper, {
2044
+ // returns the window reference
2045
+ win: function() {
2046
+ return wrap(this._.defaultView || this._.parentWindow);
2047
+ }
2048
+ }),
2049
+
2050
+ // a common local wrapped document reference
2051
+ current_Document = wrap(document);
2052
+
1912
2053
 
2054
+ /**
2055
+ * the window object extensions
2056
+ *
2057
+ * Copyright (C) 2008-2011 Nikolay Nemshilov
2058
+ */
2059
+ var Window = RightJS.Window = new Class(Wrapper, {
1913
2060
  /**
1914
- * Generic API reference
2061
+ * Selfreference to have a common interface with the rest of the wrappers
2062
+ * in case of events handling
1915
2063
  *
1916
- * @return Window this
2064
+ * @return Window
1917
2065
  */
1918
- window: function() {
2066
+ win: function() {
1919
2067
  return this;
1920
2068
  },
1921
2069
 
@@ -1925,7 +2073,7 @@ var Window = RightJS.Window = new Wrapper({
1925
2073
  * @return Object x: d+, y: d+
1926
2074
  */
1927
2075
  size: function() {
1928
- var win = this._, html = this.d.documentElement;
2076
+ var win = this._, html = win.document.documentElement;
1929
2077
  return win.innerWidth ? {x: win.innerWidth, y: win.innerHeight} :
1930
2078
  {x: html.clientWidth, y: html.clientHeight};
1931
2079
  },
@@ -1936,7 +2084,7 @@ var Window = RightJS.Window = new Wrapper({
1936
2084
  * @return Object x: d+, y: d+
1937
2085
  */
1938
2086
  scrolls: function() {
1939
- var win = this._, doc = this.d, body = doc.body, html = doc.documentElement;
2087
+ var win = this._, doc = win.document, body = doc.body, html = doc.documentElement;
1940
2088
 
1941
2089
  return (win.pageXOffset || win.pageYOffset) ? {x: win.pageXOffset, y: win.pageYOffset} :
1942
2090
  (body && (body.scrollLeft || body.scrollTop)) ? {x: body.scrollLeft, y: body.scrollTop} :
@@ -1952,9 +2100,10 @@ var Window = RightJS.Window = new Wrapper({
1952
2100
  * @return window self
1953
2101
  */
1954
2102
  scrollTo: function(left, top, fx_options) {
1955
- var left_pos = left, top_pos = top, element = $(left); // moving the values into new vars so they didn't get screwed later on
2103
+ var left_pos = left, top_pos = top,
2104
+ element = isNumber(left) ? null : $(left);
1956
2105
 
1957
- if(element && element instanceof Element) {
2106
+ if(element instanceof Element) {
1958
2107
  left = element.position();
1959
2108
  }
1960
2109
 
@@ -1984,9 +2133,9 @@ var Window = RightJS.Window = new Wrapper({
1984
2133
  * The additional method names are inspired by
1985
2134
  * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
1986
2135
  *
1987
- * Copyright (C) 2008-2010 Nikolay Nemshilov
2136
+ * Copyright (C) 2008-2011 Nikolay Nemshilov
1988
2137
  */
1989
- var Event = RightJS.Event = new Wrapper({
2138
+ var Event = RightJS.Event = new Class(Wrapper, {
1990
2139
  // predefining the keys to spped up the assignments
1991
2140
  type: null,
1992
2141
 
@@ -2007,50 +2156,7 @@ var Event = RightJS.Event = new Wrapper({
2007
2156
  * @param HTMLElement the bound element
2008
2157
  * @return void
2009
2158
  */
2010
- initialize: function(event, bound_element) {
2011
- if (typeof event === 'string') {
2012
- event = Object.merge({type: event}, bound_element);
2013
- this.stopped = event.bubbles === false;
2014
-
2015
- if (isHash(bound_element)) {
2016
- $ext(this, bound_element);
2017
- }
2018
- }
2019
-
2020
- this._ = event;
2021
- this.type = event.type;
2022
-
2023
- this.which = event.which;
2024
- this.keyCode = event.keyCode;
2025
-
2026
- this.target = $(event.target);
2027
- this.currentTarget = $(event.currentTarget);
2028
- this.relatedTarget = $(event.relatedTarget);
2029
-
2030
- this.pageX = event.pageX;
2031
- this.pageY = event.pageY;
2032
-
2033
- if (!('target' in event) && 'srcElement' in event) {
2034
- // grabbin the IE properties
2035
- this.which = event.button == 2 ? 3 : event.button == 4 ? 2 : 1;
2036
-
2037
- // faking the target property
2038
- this.target = $(event.srcElement) || bound_element;
2039
-
2040
- // faking the relatedTarget, currentTarget and other targets
2041
- this.relatedTarget = this.target._ === event.fromElement ? $(event.toElement) : this.target;
2042
- this.currentTarget = bound_element;
2043
-
2044
- // faking the mouse position
2045
- var scrolls = this.target.window().scrolls();
2046
-
2047
- this.pageX = event.clientX + scrolls.x;
2048
- this.pageY = event.clientY + scrolls.y;
2049
- } else if (event.target && 'nodeType' in event.target && event.target.nodeType === 3) {
2050
- // Safari fix
2051
- this.target = $(event.target.parentNode);
2052
- }
2053
- },
2159
+ initialize: Event_Klass, // the actual initialization happens in the Klass function
2054
2160
 
2055
2161
  /**
2056
2162
  * Stops the event bubbling process
@@ -2058,11 +2164,12 @@ var Event = RightJS.Event = new Wrapper({
2058
2164
  * @return RightJS.Event this
2059
2165
  */
2060
2166
  stopPropagation: function() {
2061
- if ('stopPropagation' in this._) {
2167
+ if (this._.stopPropagation) {
2062
2168
  this._.stopPropagation();
2063
2169
  } else {
2064
2170
  this._.cancelBubble = true;
2065
2171
  }
2172
+
2066
2173
  this.stopped = true;
2067
2174
  return this;
2068
2175
  },
@@ -2073,11 +2180,12 @@ var Event = RightJS.Event = new Wrapper({
2073
2180
  * @return RightJS.Event this
2074
2181
  */
2075
2182
  preventDefault: function() {
2076
- if ('preventDefault' in this._) {
2183
+ if (this._.preventDefault) {
2077
2184
  this._.preventDefault();
2078
2185
  } else {
2079
2186
  this._.returnValue = false;
2080
2187
  }
2188
+
2081
2189
  return this;
2082
2190
  },
2083
2191
 
@@ -2102,15 +2210,20 @@ var Event = RightJS.Event = new Wrapper({
2102
2210
  /**
2103
2211
  * Returns the event's offset relative to the target element
2104
2212
  *
2105
- * @return Object {x: ..., y: ...}
2213
+ * @return Object {x: ..., y: ...} or null
2106
2214
  */
2107
2215
  offset: function() {
2108
- var element_position = this.target.position();
2216
+ if(this.target instanceof Element) {
2217
+ var element_position = this.target.position();
2109
2218
 
2110
- return {
2111
- x: this.pageX - element_position.x,
2112
- y: this.pageY - element_position.y
2113
- };
2219
+ return {
2220
+ x: this.pageX - element_position.x,
2221
+ y: this.pageY - element_position.y
2222
+ };
2223
+ }
2224
+
2225
+ // triggered outside browser window (at toolbar etc.)
2226
+ return null;
2114
2227
  },
2115
2228
 
2116
2229
  /**
@@ -2122,19 +2235,21 @@ var Event = RightJS.Event = new Wrapper({
2122
2235
  * @return Element element or null
2123
2236
  */
2124
2237
  find: function(css_rule) {
2125
- if (this.target instanceof Element && !!this.currentTarget) {
2126
- var target = this.target,
2127
- targets = [target].concat(target.parents()),
2128
- search = this.currentTarget.find(css_rule);
2238
+ if (this.target instanceof Wrapper && this.currentTarget instanceof Wrapper) {
2239
+ var target = this.target._,
2240
+ search = this.currentTarget.find(css_rule, true);
2129
2241
 
2130
- return targets.first(function(element) {
2131
- return search.include(element);
2132
- });
2133
- } else {
2134
- return undefined;
2242
+ while (target) {
2243
+ if (search.indexOf(target) !== -1) {
2244
+ return wrap(target);
2245
+ }
2246
+ target = target.parentNode;
2247
+ }
2135
2248
  }
2249
+
2250
+ return undefined;
2136
2251
  }
2137
- }),
2252
+ }, Event_Klass),
2138
2253
 
2139
2254
  Event_delegation_shortcuts = [];
2140
2255
 
@@ -2142,95 +2257,87 @@ Event_delegation_shortcuts = [];
2142
2257
  /**
2143
2258
  * The DOM Element unit handling
2144
2259
  *
2145
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
2260
+ * Copyright (C) 2008-2011 Nikolay Nemshilov
2146
2261
  */
2147
2262
 
2148
- // Element constructor options mapper
2149
- var element_arguments_map = {
2150
- id: 'id',
2151
- html: 'innerHTML',
2152
- 'class': 'className'
2153
- },
2154
-
2155
- element_methods_map = {
2156
- style: 'setStyle',
2157
- on: 'on'
2158
- },
2263
+ var Element = RightJS.Element = new Class(Wrapper, {
2264
+ /**
2265
+ * constructor
2266
+ *
2267
+ * NOTE: this constructor will dynamically typecast
2268
+ * the wrappers depending on the element tag-name
2269
+ *
2270
+ * @param String element tag name or an HTMLElement instance
2271
+ * @param Object options
2272
+ * @return Element element
2273
+ */
2274
+ initialize: function(element, options) {
2275
+ Element_initialize(this, element, options);
2276
+ }
2159
2277
 
2160
- Element_wrappers = {},
2278
+ }, Element_Klass),
2161
2279
 
2162
- // caching the element instances to boos the things up
2280
+ Element_wrappers = Element.Wrappers = {},
2163
2281
  elements_cache = {},
2164
2282
 
2165
2283
  /**
2166
- * The elements constructor
2167
- *
2168
- * NOTE: this function is called in a context of a dom-wrapper
2284
+ * bulds dom-elements
2169
2285
  *
2170
2286
  * @param String element tag name
2171
2287
  * @param Object options
2172
2288
  * @return HTMLElement
2173
2289
  */
2174
- element_constructor = function(element, options) {
2175
- // building the element
2176
- this._ = element = document.createElement(element);
2177
-
2178
- // applying the options
2179
- if (options !== undefined) {
2180
- for (var key in options) {
2181
- if (key in element_arguments_map) {
2182
- element[element_arguments_map[key]] = options[key];
2183
- } else if (key in element_methods_map) {
2184
- this[element_methods_map[key]](options[key]);
2185
- } else {
2186
- this.set(key, options[key]);
2187
- }
2188
- }
2189
- }
2290
+ make_element = function (tag, options) {
2291
+ return (tag in elements_cache ? elements_cache[tag] : (
2292
+ elements_cache[tag] = document.createElement(tag)
2293
+ )).cloneNode(false);
2190
2294
  };
2191
2295
 
2192
2296
  //
2193
2297
  // IE 6,7,8 (not 9!) browsers have a bug with checkbox and radio input elements
2194
- // it doesn't place the 'checked' property correctly, so we kinda hacking
2195
- // the Element constructor a bit for them
2298
+ // it doesn't place the 'checked' property correctly, plus there are some issues
2299
+ // with clonned SELECT objects, so we are replaceing the elements maker in here
2196
2300
  //
2197
- try {
2198
- document.createElement('<input/>'); // <- works for IE < 9 only
2199
- element_constructor = patch_function(element_constructor, /(\((\w+),\s*(\w+)\)\s*\{)/,
2200
- '$1if($2==="input"&&$3)$2="<input name="+$3.name+" type="+$3.type+($3.checked?" checked":"")+"/>";'
2201
- );
2202
- } catch (e) {}
2301
+ if (IE8_OR_LESS) {
2302
+ make_element = function(tag, options) {
2303
+ if (tag === 'input' && options !== undefined) {
2304
+ tag = '<input name="'+ options.name +
2305
+ '" type='+ options.type +
2306
+ (options.checked ? ' checked' : '') +
2307
+ '/>';
2308
+ }
2309
+
2310
+ return document.createElement(tag);
2311
+ };
2312
+ }
2203
2313
 
2204
2314
  /**
2205
- * The actual elements wrapper
2315
+ * Basic element's constructor
2206
2316
  *
2317
+ * @param Element wrapper instance
2318
+ * @param mixed raw dom element of a string tag name
2319
+ * @param Object options
2320
+ * @return void
2207
2321
  */
2208
- var Element = RightJS.Element = new Wrapper({
2209
- /**
2210
- * constructor
2211
- *
2212
- * NOTE: this constructor will dynamically typecast
2213
- * the wrappers depending on the element tag-name
2214
- *
2215
- * @param String element tag name or an HTMLElement instance
2216
- * @param Object options
2217
- * @return Element element
2218
- */
2219
- initialize: function(element, options) {
2220
- if (typeof element === 'string') {
2221
- this.construct(element, options);
2222
- } else {
2223
- this._ = element;
2322
+ function Element_initialize(inst, element, options) {
2323
+ if (typeof element === 'string') {
2324
+ inst._ = make_element(element, options);
2325
+
2326
+ if (options !== undefined) {
2327
+ for (var key in options) {
2328
+ switch (key) {
2329
+ case 'id': inst._.id = options[key]; break;
2330
+ case 'html': inst._.innerHTML = options[key]; break;
2331
+ case 'class': inst._.className = options[key]; break;
2332
+ case 'on': inst.on(options[key]); break;
2333
+ default: inst.set(key, options[key]);
2334
+ }
2335
+ }
2224
2336
  }
2225
- },
2226
-
2227
- // protected
2228
-
2229
- // constructs the event
2230
- construct: element_constructor
2231
- });
2232
-
2233
- Element.Wrappers = Element_wrappers;
2337
+ } else {
2338
+ inst._ = element;
2339
+ }
2340
+ }
2234
2341
 
2235
2342
 
2236
2343
  /**
@@ -2248,12 +2355,16 @@ Element.Wrappers = Element_wrappers;
2248
2355
  * The insertions system implementation is inspired by
2249
2356
  * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
2250
2357
  *
2251
- * Copyright (C) 2008-2010 Nikolay Nemshilov
2358
+ * Copyright (C) 2008-2011 Nikolay Nemshilov
2252
2359
  */
2253
2360
 
2254
2361
  Element.include({
2255
2362
  parent: function(css_rule) {
2256
- return css_rule ? this.parents(css_rule)[0] : $(this._.parentNode || null); // <- IE6 need that || null
2363
+ var parent = this._.parentNode, parent_type = parent && parent.nodeType;
2364
+
2365
+ return css_rule ? this.parents(css_rule)[0] :
2366
+ (parent_type === 1 || parent_type === 9) ? // <- IE6 sometimes has a fragment node in there
2367
+ wrap(parent) : null;
2257
2368
  },
2258
2369
 
2259
2370
  parents: function(css_rule) {
@@ -2305,7 +2416,7 @@ Element.include({
2305
2416
  * The content might be one of the following data
2306
2417
  *
2307
2418
  * o) an element instance
2308
- * o) a String, which will be converted into content to insert (all the scripts will be parsed out and executed)
2419
+ * o) a String (all the scripts will be parsed out and executed)
2309
2420
  * o) a list of Elements
2310
2421
  * o) a hash like {position: content}
2311
2422
  *
@@ -2315,7 +2426,7 @@ Element.include({
2315
2426
  */
2316
2427
  insert: function(content, position) {
2317
2428
  var scripts = null, element = this._;
2318
- position = (position||'bottom').toLowerCase();
2429
+ position = position === undefined ? 'bottom' : position;
2319
2430
 
2320
2431
  if (typeof(content) !== 'object') {
2321
2432
  scripts = content = (''+content);
@@ -2323,11 +2434,12 @@ Element.include({
2323
2434
  content = content._;
2324
2435
  }
2325
2436
 
2326
- Element_insertions[position](element, content.nodeType ? content :
2327
- Element_createFragment.call(
2328
- (position === 'bottom' || position === 'top') ?
2329
- element : element.parentNode, content
2330
- )
2437
+ Element_insertions[position](element,
2438
+ content.nodeType === undefined ?
2439
+ Element_createFragment(
2440
+ (position === 'bottom' || position === 'top') ?
2441
+ element : element.parentNode, content
2442
+ ) : content
2331
2443
  );
2332
2444
 
2333
2445
  if (scripts !== null) { scripts.evalScripts(); }
@@ -2404,8 +2516,8 @@ Element.include({
2404
2516
  * @return String text content or Element this
2405
2517
  */
2406
2518
  text: function(text) {
2407
- return text === undefined ? this._.innerHTML.stripTags() :
2408
- this.update(this.document()._.createTextNode(text));
2519
+ return text === undefined ? (this._.textContent || this._.innerText) :
2520
+ this.update(this.doc()._.createTextNode(text));
2409
2521
  },
2410
2522
 
2411
2523
  /**
@@ -2462,10 +2574,29 @@ Element.include({
2462
2574
  * @return Element new clone
2463
2575
  */
2464
2576
  clone: function() {
2465
- var clone = this._.cloneNode(true);
2466
- // we need manually reassing the UID_KEY because IE will clone it too
2467
- clone[UID_KEY] = UID++;
2468
- return new Element(clone);
2577
+ return new Element(this._.cloneNode(true));
2578
+ },
2579
+
2580
+ /**
2581
+ * Returns an index of the element among the other child elements
2582
+ *
2583
+ * NOTE: doesn't count the textual nodes!
2584
+ *
2585
+ * @return Integer index
2586
+ */
2587
+ index: function() {
2588
+ var node = this._,
2589
+ sibling = node.parentNode.firstChild,
2590
+ index = 0;
2591
+
2592
+ while (sibling !== node) {
2593
+ if (sibling.nodeType === 1) { // counting elements only
2594
+ index ++;
2595
+ }
2596
+ sibling = sibling.nextSibling;
2597
+ }
2598
+
2599
+ return index;
2469
2600
  }
2470
2601
  });
2471
2602
 
@@ -2478,11 +2609,11 @@ Element.include({
2478
2609
  * @return Array found elements
2479
2610
  */
2480
2611
  function recursively_collect(where, attr, css_rule) {
2481
- var node = where._, result = [];
2612
+ var node = where._, result = [], i=0, no_rule = !css_rule;
2482
2613
 
2483
2614
  while ((node = node[attr])) {
2484
- if (node.tagName && (!css_rule || $(node).match(css_rule))) {
2485
- result.push($(node));
2615
+ if (node.nodeType === 1 && (no_rule || wrap(node).match(css_rule))) {
2616
+ result[i++] = wrap(node);
2486
2617
  }
2487
2618
  }
2488
2619
 
@@ -2544,28 +2675,30 @@ $alias(Element_wraps, {
2544
2675
  var fragment = document.createDocumentFragment(),
2545
2676
  tmp_cont = document.createElement('DIV');
2546
2677
 
2547
- function Element_createFragment(content) {
2678
+ function Element_createFragment(context, content) {
2548
2679
  if (typeof(content) === 'string') {
2549
- var tag = this.tagName,
2680
+ var tag = context.tagName,
2550
2681
  tmp = tmp_cont,
2551
- wrap = Element_wraps[tag] || ['', '', 1],
2682
+ wrap = tag in Element_wraps ? Element_wraps[tag] : ['', '', 1],
2552
2683
  depth = wrap[2];
2553
2684
 
2554
2685
  tmp.innerHTML = wrap[0] + '<'+ tag + '>' + content + '</'+ tag + '>' + wrap[1];
2555
2686
 
2556
- while (depth-- > 0) {
2687
+ while (depth-- !== 0) {
2557
2688
  tmp = tmp.firstChild;
2558
2689
  }
2559
2690
 
2560
2691
  content = tmp.childNodes;
2561
- }
2562
2692
 
2563
- for (var i=0, length = content.length, node; i < length; i++) {
2564
- // in case of NodeList unit, the elements will be removed out of the list during the appends
2565
- // therefore if that's an array we use the 'i' variable, and if it's a collection of nodes
2566
- // then we always hit the first element of the stack
2567
- node = content[content.length === length ? i : 0];
2568
- fragment.appendChild(node instanceof Element ? node._ : node);
2693
+ while (content.length !== 0) {
2694
+ fragment.appendChild(content[0]);
2695
+ }
2696
+
2697
+ } else {
2698
+ for (var i=0, length = content.length, node; i < length; i++) {
2699
+ node = content[content.length === length ? i : 0];
2700
+ fragment.appendChild(node instanceof Element ? node._ : node);
2701
+ }
2569
2702
  }
2570
2703
 
2571
2704
  return fragment;
@@ -2581,7 +2714,7 @@ function Element_createFragment(content) {
2581
2714
  * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
2582
2715
  * - Dojo (www.dojotoolkit.org) Copyright (C) The Dojo Foundation
2583
2716
  *
2584
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
2717
+ * Copyright (C) 2008-2011 Nikolay V. Nemshilov
2585
2718
  */
2586
2719
  Element.include({
2587
2720
  /**
@@ -2612,13 +2745,13 @@ Element.include({
2612
2745
  c_key = key.indexOf('-') < 0 ? key : key.camelize();
2613
2746
 
2614
2747
  if (key === 'opacity') {
2615
- if (Browser.IE) {
2748
+ if (Browser_IE) {
2616
2749
  element_style.filter = 'alpha(opacity='+ hash[key] * 100 +')';
2617
2750
  } else {
2618
2751
  element_style.opacity = hash[key];
2619
2752
  }
2620
2753
  } else if (key === 'float') {
2621
- c_key = Browser.IE ? 'styleFloat' : 'cssFloat';
2754
+ c_key = Browser_IE ? 'styleFloat' : 'cssFloat';
2622
2755
  }
2623
2756
 
2624
2757
  element_style[c_key] = hash[key];
@@ -2644,10 +2777,12 @@ Element.include({
2644
2777
  *
2645
2778
  * @return Object/CSSDefinition computed styles
2646
2779
  */
2647
- computedStyles: function() {
2648
- var element = this._;
2649
- // old IE, IE8, W3C
2650
- return element.currentStyle || element.runtimeStyle || element.ownerDocument.defaultView.getComputedStyle(element, null) || {};
2780
+ computedStyles: HTML.currentStyle ? function() {
2781
+ return this._.currentStyle || {};
2782
+ } : HTML.runtimeStyle ? function() {
2783
+ return this._.runtimeStyle || {};
2784
+ } : function() {
2785
+ return this._.ownerDocument.defaultView.getComputedStyle(this._, null);
2651
2786
  },
2652
2787
 
2653
2788
  /**
@@ -2735,28 +2870,28 @@ Element.include({
2735
2870
  * @param String style-key
2736
2871
  * @return String clean style
2737
2872
  */
2738
- function clean_style(style, in_key) {
2739
- var value, key = in_key.camelize();
2740
-
2741
- switch (key) {
2742
- case 'opacity':
2743
- value = !Browser.IE ? style[key].replace(',', '.') :
2744
- ((/opacity=(\d+)/i.exec(style.filter || '') || ['', '100'])[1].toInt() / 100)+'';
2745
- break;
2873
+ function clean_style(style, key) {
2874
+ key = key.camelize();
2875
+
2876
+ if (key === 'opacity') {
2877
+ return Browser_IE ? (
2878
+ (/opacity=(\d+)/i.exec(style.filter || '') ||
2879
+ ['', '100'])[1].toInt() / 100
2880
+ )+'' :style[key].replace(',', '.');
2881
+ }
2746
2882
 
2747
- case 'float':
2748
- key = Browser.IE ? 'styleFloat' : 'cssFloat';
2883
+ if (key === 'float') {
2884
+ key = Browser_IE ? 'styleFloat' : 'cssFloat';
2885
+ }
2749
2886
 
2750
- default:
2751
- value = style[key];
2887
+ var value = style[key];
2752
2888
 
2753
- // Opera returns named colors with quotes
2754
- if (Browser.Opera && /color/i.test(key) && value) {
2755
- value = value.replace(/"/g, '');
2756
- }
2889
+ // Opera returns named colors with quotes
2890
+ if (Browser_Opera && /color/i.test(key) && value) {
2891
+ value = value.replace(/"/g, '');
2757
2892
  }
2758
2893
 
2759
- return value || null;
2894
+ return value;
2760
2895
  }
2761
2896
 
2762
2897
 
@@ -2767,7 +2902,7 @@ function clean_style(style, in_key) {
2767
2902
  * Most of the naming system in the module inspired by
2768
2903
  * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
2769
2904
  *
2770
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
2905
+ * Copyright (C) 2008-2011 Nikolay V. Nemshilov
2771
2906
  */
2772
2907
  Element.include({
2773
2908
  /**
@@ -2783,11 +2918,15 @@ Element.include({
2783
2918
  var key, element = this._;
2784
2919
 
2785
2920
  for (key in hash) {
2786
- // some attributes are not available as properties
2787
- if (!(key in element)) {
2788
- element.setAttribute(key, ''+hash[key]);
2921
+ if (key === 'style') {
2922
+ this.setStyle(hash[key]);
2923
+ } else {
2924
+ // some attributes are not available as properties
2925
+ if (!(key in element)) {
2926
+ element.setAttribute(key, ''+hash[key]);
2927
+ }
2928
+ element[key] = hash[key];
2789
2929
  }
2790
- element[key] = hash[key];
2791
2930
  }
2792
2931
 
2793
2932
  return this;
@@ -2864,16 +3003,25 @@ Element.include({
2864
3003
  /**
2865
3004
  * shows the element
2866
3005
  *
2867
- * @param String optional effect name
2868
- * @param Object the optional effect options
2869
3006
  * @return Element self
2870
3007
  */
2871
- show: function(effect, options) {
3008
+ show: function() {
2872
3009
  if (this.hidden()) {
2873
- // setting 'block' for the divs and 'inline' for the other elements hidden on the css-level
2874
- var element = this._, value = element.tagName == 'DIV' ? 'block' : 'inline';
3010
+ var element = this._, value = this._d, dummy;
3011
+
3012
+ // trying to guess the default 'style.display' for this kind of elements
3013
+ if (!value || value === 'none') {
3014
+ dummy = $E(element.tagName).insertTo(HTML);
3015
+ value = dummy.getStyle('display');
3016
+ dummy.remove();
3017
+ }
3018
+
3019
+ // failsafe in case the user been naughty
3020
+ if (value === 'none') {
3021
+ value = 'block';
3022
+ }
2875
3023
 
2876
- element.style.display = this._d == 'none' ? value : this._d || value;
3024
+ element.style.display = value;
2877
3025
  }
2878
3026
 
2879
3027
  return this;
@@ -2882,12 +3030,10 @@ Element.include({
2882
3030
  /**
2883
3031
  * toggles the visibility state of the element
2884
3032
  *
2885
- * @param String optional effect name
2886
- * @param Object the optional effect options
2887
3033
  * @return Element self
2888
3034
  */
2889
- toggle: function(effect, options) {
2890
- return this[this.visible() ? 'hide' : 'show'](effect, options);
3035
+ toggle: function() {
3036
+ return this[this.visible() ? 'hide' : 'show']();
2891
3037
  },
2892
3038
 
2893
3039
  /**
@@ -2908,7 +3054,7 @@ Element.include({
2908
3054
  * this module contains the Element's part of functionality
2909
3055
  * responsible for the dimensions and positions getting/setting
2910
3056
  *
2911
- * Copyright (C) 2008-2010 Nikolay Nemshilov
3057
+ * Copyright (C) 2008-2011 Nikolay Nemshilov
2912
3058
  */
2913
3059
  Element.include({
2914
3060
  /**
@@ -2916,8 +3062,8 @@ Element.include({
2916
3062
  *
2917
3063
  * @return RightJS.Document
2918
3064
  */
2919
- document: function() {
2920
- return $(this._.ownerDocument);
3065
+ doc: function() {
3066
+ return wrap(this._.ownerDocument);
2921
3067
  },
2922
3068
 
2923
3069
  /**
@@ -2925,8 +3071,8 @@ Element.include({
2925
3071
  *
2926
3072
  * @return RightJS.Window
2927
3073
  */
2928
- window: function() {
2929
- return this.document().window();
3074
+ win: function() {
3075
+ return this.doc().win();
2930
3076
  },
2931
3077
 
2932
3078
  /**
@@ -2947,8 +3093,8 @@ Element.include({
2947
3093
  */
2948
3094
  position: function() {
2949
3095
  var rect = this._.getBoundingClientRect(),
2950
- html = this.document()._.documentElement,
2951
- scrolls = this.window().scrolls();
3096
+ html = this.doc()._.documentElement,
3097
+ scrolls = this.win().scrolls();
2952
3098
 
2953
3099
  return {
2954
3100
  x: rect.left + scrolls.x - html.clientLeft,
@@ -3093,7 +3239,7 @@ Element.include({
3093
3239
  * @return Element self
3094
3240
  */
3095
3241
  scrollThere: function(options) {
3096
- this.window().scrollTo(this, options);
3242
+ this.win().scrollTo(this, options);
3097
3243
  return this;
3098
3244
  }
3099
3245
  });
@@ -3102,74 +3248,115 @@ Element.include({
3102
3248
  /**
3103
3249
  * DOM Element events handling methods
3104
3250
  *
3105
- * Copyright (C) 2008-2010 Nikolay Nemshilov
3251
+ * Copyright (C) 2008-2011 Nikolay Nemshilov
3106
3252
  */
3107
- var Element_observer = Observer_create({});
3253
+ [Element, Document, Window].each('include', $ext(Observer_create({}), {
3254
+ /**
3255
+ * The basic events handling attachment method
3256
+ * SEE Observer#on for more details about supported arguments
3257
+ *
3258
+ * @returnt this
3259
+ */
3260
+ on: function() {
3261
+ Observer_on(this, arguments, function(hash) {
3262
+
3263
+ if (hash.e === 'mouseenter' || hash.e === 'mouseleave') {
3264
+ mouse_io_activate();
3265
+ hash.n = hash.e;
3266
+ hash.w = function() {};
3267
+ // NOTE: we don't attach this listener to the actual element!
3268
+ // so it didn't screw with IE's native enter/leave handlers
3269
+ } else {
3270
+ if (hash.e === 'contextmenu' && Browser.Konqueror) {
3271
+ hash.n = 'rightclick';
3272
+ } else if (hash.e === 'mousewheel' && Browser.Gecko) {
3273
+ hash.n = 'DOMMouseScroll';
3274
+ } else {
3275
+ hash.n = hash.e;
3276
+ }
3108
3277
 
3109
- //
3110
- // HACK HACK HACK
3111
- //
3112
- // I'm kinda patching the observer methods manually in here
3113
- // the reason is in building flat and fast functions
3114
- //
3115
- function hack_observer(name, re, text) {
3116
- Element_observer[name] = patch_function(Element_observer[name], re, text);
3117
- }
3278
+ hash.w = function(event) {
3279
+ event = new Event(event, hash.t);
3280
+ if (hash.f.apply(hash.t, (hash.r?[]:[event]).concat(hash.a)) === false) {
3281
+ event.stop();
3282
+ }
3283
+ };
3118
3284
 
3119
- hack_observer('on',
3120
- /(\$listeners\.push\((\w+?)\);)/,
3121
-
3122
- // aliasing the 'rightclick' to the 'contextmenu' event
3123
- '$1$2.e=$2.n=$2.e==="rightclick"?"contextmenu":$2.e;'+
3124
-
3125
- // swapping a browser related event names
3126
- (Browser.Gecko ? 'if($2.n==="mousewheel")$2.n="DOMMouseScroll";' : '') +
3127
- (Browser.Konqueror ? 'if($2.n==="contextmenu")$2.n="rightclick";' : '') +
3128
-
3129
- '$2.w=function(){'+
3130
- 'var a=$A(arguments),_;'+
3131
- '$2.r?a.shift():_=a[0]=new RightJS.Event(a[0],this);'+
3132
- '$2.f.apply($2.t,a.concat($2.a))===false&&_.stop()'+
3133
- '};$2.t=this;' + (
3134
- looks_like_ie ?
3135
- '$2.w=$2.w.bind(this);this._.attachEvent("on"+$2.n,$2.w);' :
3136
- 'this._.addEventListener($2.n,$2.w,false);'
3137
- )
3138
- );
3285
+ if (IE8_OR_LESS) {
3286
+ hash.t._.attachEvent('on'+hash.n, hash.w);
3287
+ } else {
3288
+ hash.t._.addEventListener(hash.n, hash.w, false);
3289
+ }
3290
+ }
3139
3291
 
3140
- hack_observer('stopObserving',
3141
- /(function\s*\((\w+)\)\s*\{\s*)(return\s*)([^}]+)/m,
3142
- '$1var r=$4;'+
3143
- 'if(!r)this._.' + (looks_like_ie ?
3144
- 'detachEvent("on"+$2.n,$2.w);' :
3145
- 'removeEventListener($2.n,$2.w,false);'
3146
- )+'$3 r'
3147
- );
3292
+ return hash;
3293
+ });
3148
3294
 
3149
- // adding the event generator
3150
- hack_observer('fire',
3151
- /(\w+)(\s*=\s*(\w+).shift\(\))/,
3152
- '$1$2;$1=$1 instanceof RightJS.Event?$1:'+
3153
- 'new RightJS.Event($1,Object.merge({target:this._},$3[0]))'+
3154
- ';$1.currentTarget=this'
3155
- );
3295
+ return this;
3296
+ },
3156
3297
 
3157
- // addjusting the arguments list
3158
- hack_observer('fire',
3159
- /((\w+)\.e\s*===\s*(\w+))([^}]+\2\.f\.apply)[^}]+?\.concat\(\w+\)\)/,
3160
- '$1.type$4(this,($2.r?[]:[$3]).concat($2.a))'
3161
- );
3298
+ /**
3299
+ * Stops an event handling
3300
+ *
3301
+ * @param String event name or a function callback
3302
+ * @param function callback or nothing
3303
+ * @return this
3304
+ */
3305
+ stopObserving: function(event, callback) {
3306
+ Observer_stopObserving(this, event, callback, function(hash) {
3307
+ if (IE8_OR_LESS) {
3308
+ hash.t._.detachEvent('on'+ hash.n, hash.w);
3309
+ } else {
3310
+ hash.t._.removeEventListener(hash.n, hash.w, false);
3311
+ }
3312
+ });
3313
+
3314
+ return this;
3315
+ },
3316
+
3317
+ /**
3318
+ * Artificially trigers the event on the element
3319
+ *
3320
+ * @param string event name or an Event instance
3321
+ * @param Object options
3322
+ * @return this
3323
+ */
3324
+ fire: function(event, options) {
3325
+ var parent = this.parent && this.parent();
3326
+
3327
+ if (!(event instanceof Event)) {
3328
+ event = new Event(event, $ext({target: this._}, options));
3329
+ }
3330
+
3331
+ // setting up the currentTarget reference
3332
+ event.currentTarget = this;
3162
3333
 
3163
- // a simple events terminator method to be hooked like this.onClick('stopEvent');
3164
- Element_observer.stopEvent = function() { return false; };
3334
+ (this.$listeners || []).each(function(hash) {
3335
+ if (hash.e === event.type &&
3336
+ hash.f.apply(this, (hash.r?[]:[event]).concat(hash.a)) === false
3337
+ ) {
3338
+ event.stop();
3339
+ }
3340
+ }, this);
3341
+
3342
+ // manually bypassing the event to the parent one if it should bubble
3343
+ if (parent && parent.fire && !event.stopped) {
3344
+ parent.fire(event);
3345
+ }
3346
+
3347
+ return this;
3348
+ },
3165
3349
 
3166
- // loading the observer interface into the Element object
3167
- Element.include(Element_observer);
3168
- Document.include(Element_observer);
3169
- Window.include(Element_observer);
3350
+ /**
3351
+ * a simple events terminator method to be hooked like this.onClick('stopEvent');
3352
+ *
3353
+ * @return false
3354
+ */
3355
+ stopEvent: function() { return false; }
3356
+ }));
3170
3357
 
3171
3358
  // couple more shortcuts for the window
3172
- Observer_createShortcuts(Window[PROTO], $w('blur focus scroll resize load'));
3359
+ Observer_createShortcuts(Window.prototype, $w('blur focus scroll resize load'));
3173
3360
 
3174
3361
  /**
3175
3362
  * Registers a list of event-binding shortcuts like
@@ -3183,12 +3370,13 @@ function Element_add_event_shortcuts(tokens) {
3183
3370
  tokens = $w(tokens);
3184
3371
  Event_delegation_shortcuts = Event_delegation_shortcuts.concat(tokens);
3185
3372
 
3186
- Observer_createShortcuts(Element[PROTO], tokens);
3187
- Observer_createShortcuts(Document[PROTO], tokens);
3373
+ Observer_createShortcuts(Element.prototype, tokens);
3374
+ Observer_createShortcuts(Document.prototype, tokens);
3188
3375
  }
3189
3376
 
3190
3377
  Element_add_event_shortcuts(
3191
- 'click rightclick contextmenu mousedown mouseup mouseover mouseout mousemove keypress keydown keyup'
3378
+ 'click rightclick contextmenu mousedown mouseup '+
3379
+ 'mouseover mouseout mousemove keypress keydown keyup'
3192
3380
  );
3193
3381
 
3194
3382
 
@@ -3198,21 +3386,9 @@ Element_add_event_shortcuts(
3198
3386
  * NOTE: this module is just a wrap over the native CSS-selectors feature
3199
3387
  * see the olds/css.js file for the manual selector code
3200
3388
  *
3201
- * Copyright (C) 2008-2010 Nikolay Nemshilov
3389
+ * Copyright (C) 2008-2011 Nikolay Nemshilov
3202
3390
  */
3203
3391
 
3204
- /**
3205
- * Native css-selectors include the current element into the search context
3206
- * and as we actually search only inside of the element we add it's tag
3207
- * as a scope for the search
3208
- */
3209
- function stub_rule(css_rule, tag) {
3210
- var rule = css_rule || '*', element = tag._,
3211
- tag_name = 'tagName' in element ? element.tagName : null;
3212
-
3213
- return tag_name === null ? rule : rule.replace(/(^|,)/g, '$1'+ tag_name + ' ');
3214
- }
3215
-
3216
3392
  [Element, Document].each('include', {
3217
3393
  /**
3218
3394
  * Extracts the first element matching the css-rule,
@@ -3222,21 +3398,30 @@ function stub_rule(css_rule, tag) {
3222
3398
  * @return Element matching node or null
3223
3399
  */
3224
3400
  first: function(css_rule) {
3225
- return $(this._.querySelector(stub_rule(css_rule, this)));
3401
+ return wrap(this._.querySelector(css_rule || '*'));
3226
3402
  },
3227
3403
 
3228
3404
  /**
3229
3405
  * Finds a list of matching nodes, or all the descendant nodes if no css-rule provided
3230
3406
  *
3231
3407
  * @param String css-rule
3408
+ * @param boolean raw-search
3232
3409
  * @return Array of elements
3233
3410
  */
3234
- find: function(css_rule) {
3235
- return $A(this._.querySelectorAll(stub_rule(css_rule, this))).map($);
3236
- }
3237
- });
3411
+ find: function(css_rule, raw) {
3412
+ var query = this._.querySelectorAll(css_rule || '*'), result, i=0, l = query.length;
3413
+
3414
+ if (raw === true) {
3415
+ result = $A(query);
3416
+ } else {
3417
+ for (result = []; i < l; i++) {
3418
+ result[i] = wrap(query[i]);
3419
+ }
3420
+ }
3421
+
3422
+ return result;
3423
+ },
3238
3424
 
3239
- Element.include({
3240
3425
  /**
3241
3426
  * checks if the element matches this css-rule
3242
3427
  *
@@ -3246,12 +3431,25 @@ Element.include({
3246
3431
  * @return Boolean check result
3247
3432
  */
3248
3433
  match: function(css_rule) {
3249
- var result, parent = this._.tagName === 'HTML' ? this._.ownerDocument : this.parents().last();
3434
+ // finding the top parent element (the element might not be on the document)
3435
+ var element = this._, parent = element, result, faking = false;
3436
+
3437
+ while (parent.parentNode !== null && parent.parentNode.nodeType !== 11) {
3438
+ parent = parent.parentNode;
3439
+ }
3440
+
3441
+ // creating a fake context when needed
3442
+ if (element === parent) {
3443
+ parent = document.createElement('div');
3444
+ parent.appendChild(element);
3445
+ faking = true;
3446
+ }
3250
3447
 
3251
- // if it's a single node putting it into the context
3252
- result = $(parent || $E('p').insert(this)).find(css_rule).include(this);
3448
+ result = wrap(parent).find(css_rule, true).indexOf(element) !== -1;
3253
3449
 
3254
- if (!parent) { this.remove(); }
3450
+ if (faking) {
3451
+ parent.removeChild(element);
3452
+ }
3255
3453
 
3256
3454
  return result;
3257
3455
  }
@@ -3265,16 +3463,12 @@ Element.include({
3265
3463
  * The basic principles of the module are originated from
3266
3464
  * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
3267
3465
  *
3268
- * Copyright (C) 2009-2010 Nikolay Nemshilov
3466
+ * Copyright (C) 2009-2011 Nikolay Nemshilov
3269
3467
  */
3270
- [Window, Document].each(function(object) {
3271
- var proto = object[PROTO], old_on = proto.on;
3272
-
3273
- // redefining the observer method to catch up
3274
- proto.on = function(name) {
3275
- if (name == 'ready' && !this._wR) {
3468
+ Document.include({
3469
+ on: function(name) {
3470
+ if (name === 'ready' && !this._iR) {
3276
3471
  var document = this._, ready = this.fire.bind(this, 'ready');
3277
- document = document.nodeType == 9 ? document : document.document;
3278
3472
 
3279
3473
  // IE and Konqueror browsers
3280
3474
  if ('readyState' in document) {
@@ -3289,36 +3483,14 @@ Element.include({
3289
3483
  document.addEventListener('DOMContentLoaded', ready, false);
3290
3484
  }
3291
3485
 
3292
- this._wR = true;
3486
+ this._iR = true;
3293
3487
  }
3294
- return old_on.apply(this, arguments);
3295
- };
3296
-
3297
- Observer_createShortcuts(proto, ['ready']);
3298
- });
3299
-
3300
- /**
3301
- * Deprecated method names aliases
3302
- *
3303
- * In RightJS 2 some methods were renamed so those are the aliases
3304
- * to support the old API
3305
- *
3306
- * NOTE: Will be nuked in couple of releases!
3307
- */
3308
- $alias(Element[PROTO], {
3309
- subNodes: 'children',
3310
- sizes: 'size',
3311
- select: 'find'
3312
- });
3313
3488
 
3314
- $alias(Document[PROTO], {
3315
- select: 'find'
3316
- });
3317
-
3318
- $alias(Window[PROTO], {
3319
- sizes: 'size'
3489
+ return this.$super.apply(this, arguments);
3490
+ }
3320
3491
  });
3321
3492
 
3493
+ Observer_createShortcuts(Document.prototype, ['ready']);
3322
3494
 
3323
3495
  /**
3324
3496
  * The form unit class and extensions
@@ -3327,10 +3499,10 @@ $alias(Window[PROTO], {
3327
3499
  * The basic principles of the module are inspired by
3328
3500
  * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
3329
3501
  *
3330
- * Copyright (C) 2009-2010 Nikolay Nemshilov
3502
+ * Copyright (C) 2009-2011 Nikolay Nemshilov
3331
3503
  */
3332
3504
 
3333
- var Form = RightJS.Form = Element_wrappers.FORM = new Wrapper(Element, {
3505
+ var Form = RightJS.Form = Element_wrappers.FORM = new Class(Element, {
3334
3506
  /**
3335
3507
  * constructor
3336
3508
  *
@@ -3385,7 +3557,7 @@ var Form = RightJS.Form = Element_wrappers.FORM = new Wrapper(Element, {
3385
3557
  * @return Input field
3386
3558
  */
3387
3559
  input: function(name) {
3388
- return $(this._[name]);
3560
+ return wrap(this._[name]);
3389
3561
  },
3390
3562
 
3391
3563
  /**
@@ -3444,7 +3616,9 @@ var Form = RightJS.Form = Element_wrappers.FORM = new Wrapper(Element, {
3444
3616
  this.inputs().each(function(element) {
3445
3617
  input = element._;
3446
3618
  name = input.name;
3447
- if (!input.disabled && name && (!['checkbox', 'radio'].include(input.type) || input.checked)) {
3619
+ if (!input.disabled && name && (
3620
+ !['checkbox', 'radio'].include(input.type) || input.checked
3621
+ )) {
3448
3622
  value = element.getValue();
3449
3623
  if (name.endsWith('[]')) {
3450
3624
  value = (values[name] || []).concat([value]);
@@ -3490,16 +3664,11 @@ var Form = RightJS.Form = Element_wrappers.FORM = new Wrapper(Element, {
3490
3664
  // creating the event shortcuts
3491
3665
  Element_add_event_shortcuts('submit reset focus blur disable enable change');
3492
3666
 
3493
- // deprecated alias
3494
- $alias(Form[PROTO], {
3495
- getElements: 'elements'
3496
- });
3497
-
3498
3667
 
3499
3668
  /**
3500
3669
  * The form input element class
3501
3670
  *
3502
- * Copyright (C) 2010 Nikolay Nemshilov
3671
+ * Copyright (C) 2010-2011 Nikolay Nemshilov
3503
3672
  */
3504
3673
  var Input = RightJS.Input =
3505
3674
 
@@ -3510,7 +3679,7 @@ Element_wrappers.SELECT =
3510
3679
  Element_wrappers.TEXTAREA =
3511
3680
  Element_wrappers.OPTGROUP =
3512
3681
 
3513
- new Wrapper(Element, {
3682
+ new Class(Element, {
3514
3683
  /**
3515
3684
  * Constructor
3516
3685
  *
@@ -3549,23 +3718,41 @@ new Wrapper(Element, {
3549
3718
  * @return Form wrapped form
3550
3719
  */
3551
3720
  form: function() {
3552
- return $(this._.form);
3721
+ return wrap(this._.form);
3553
3722
  },
3554
3723
 
3555
3724
  /**
3556
- * Overloading the method so it always called the '#insert' method
3725
+ * Overloading the method to fix some issues with IE and FF
3557
3726
  *
3558
3727
  * @param mixed content
3728
+ * @param string optional position
3559
3729
  * @return Input this
3560
3730
  */
3561
- update: function(content) {
3562
- return this.clean().insert(content);
3731
+ insert: function(content, position) {
3732
+ this.$super(content, position);
3733
+
3734
+ // manually resetting the selected option in here
3735
+ this.find('option').each(function(option) {
3736
+ option._.selected = !!option.get('selected');
3737
+ });
3738
+
3739
+ return this;
3563
3740
  },
3564
3741
 
3565
3742
  /**
3566
- * uniform access to the element values
3743
+ * Overloading the method so it always called the '#insert' method
3567
3744
  *
3568
- * @return String element value
3745
+ * @param mixed content
3746
+ * @return Input this
3747
+ */
3748
+ update: function(content) {
3749
+ return this.clean().insert(content);
3750
+ },
3751
+
3752
+ /**
3753
+ * uniform access to the element values
3754
+ *
3755
+ * @return String element value
3569
3756
  */
3570
3757
  getValue: function() {
3571
3758
  if (this._.type == 'select-multiple') {
@@ -3613,7 +3800,7 @@ new Wrapper(Element, {
3613
3800
  focus: function() {
3614
3801
  this._.focus();
3615
3802
  this.focused = true;
3616
- if (Browser.IE) { this.fire('focus', {bubbles: false}); }
3803
+ if (Browser_IE) { this.fire('focus', {bubbles: false}); }
3617
3804
  return this;
3618
3805
  },
3619
3806
 
@@ -3625,7 +3812,7 @@ new Wrapper(Element, {
3625
3812
  blur: function() {
3626
3813
  this._.blur();
3627
3814
  this.focused = false;
3628
- if (Browser.IE) { this.fire('blur', {bubbles: false}); }
3815
+ if (Browser_IE) { this.fire('blur', {bubbles: false}); }
3629
3816
  return this;
3630
3817
  },
3631
3818
 
@@ -3687,34 +3874,13 @@ new Wrapper(Element, {
3687
3874
  }
3688
3875
  });
3689
3876
 
3690
- // SELECT element has a bug in FF that screws the selected options
3691
- if ($E('select').update('<option selected="true">1</option><option>2</option>')._.value === '2') {
3692
- Input[PROTO].insert = function(content, position) {
3693
- Element[PROTO].insert.call(this, content, position);
3694
-
3695
- // manually resetting the selected option in here
3696
- this.find('option').each(function(option) {
3697
- option._.selected = !!option.get('selected');
3698
- });
3699
-
3700
- return this;
3701
- };
3702
- }
3703
3877
 
3704
3878
  /**
3705
- * This module provides the artificial events bubbling feature
3879
+ * This module provides correct focus/blur events bubbling
3706
3880
  *
3707
- * Copyright (C) 2010 Nikolay Nemshilov
3881
+ * Copyright (C) 2010-2011 Nikolay Nemshilov
3708
3882
  */
3709
3883
 
3710
- // patching the Element's 'fire' method again
3711
- // to make it to bypass the event to its parent
3712
- Element[PROTO].fire = patch_function(
3713
- Element_observer.fire,
3714
- /(\w+)(\s*=\s*\w+\.shift[\s\S]+)(return this)/m,
3715
- '$1$2var p=!$1.stopped&&this.parent&&this.parent();p&&p.fire&&p.fire($1);$3'
3716
- );
3717
-
3718
3884
  /**
3719
3885
  * Triggers a manual focus/blur events bubbling
3720
3886
  *
@@ -3726,7 +3892,7 @@ function focus_boobler(raw_event) {
3726
3892
  target = event.target,
3727
3893
  parent = target.parent && target.parent();
3728
3894
 
3729
- event.type = (raw_event.type === 'focusin' || raw_event.type === 'focus') ? 'focus' : 'blur';
3895
+ event.type = raw_event.type === 'focusin' || raw_event.type === 'focus' ? 'focus' : 'blur';
3730
3896
 
3731
3897
  if (parent) { parent.fire(event); }
3732
3898
  }
@@ -3737,7 +3903,7 @@ function focus_boobler(raw_event) {
3737
3903
  * manually like they were normal events
3738
3904
  *
3739
3905
  */
3740
- if (Browser.IE) {
3906
+ if (IE8_OR_LESS) {
3741
3907
  document.attachEvent('onfocusin', focus_boobler);
3742
3908
  document.attachEvent('onfocusout', focus_boobler);
3743
3909
  } else {
@@ -3745,132 +3911,127 @@ if (Browser.IE) {
3745
3911
  document.addEventListener('blur', focus_boobler, true);
3746
3912
  }
3747
3913
 
3914
+
3748
3915
  /**
3749
- * Tests if there is the event support
3916
+ * Provides the mouse enter/leave events handling emulation
3750
3917
  *
3751
- * @param String event name
3752
- * @retrun Boolean check result
3918
+ * Copyright (C) 2010-2011 Nikolay Nemshilov
3753
3919
  */
3754
- function event_support_for(name, tag) {
3755
- var e = document.createElement(tag);
3756
- e.setAttribute(name, ';');
3757
- return isFunction(e[name]);
3758
- }
3759
-
3760
- if (!event_support_for('onsubmit', 'form')) {
3761
- /**
3762
- * Emulates the 'submit' event bubbling for IE browsers
3763
- *
3764
- * @param raw dom-event
3765
- * @return void
3766
- */
3767
- var submit_boobler = function(raw_event) {
3768
- var event = $(raw_event), element = event.target._,
3769
- type = element.type, form = element.form, parent;
3920
+ var mouse_io_index = [], mouse_io_inactive = true;
3770
3921
 
3771
- if (form && (parent = $(form).parent()) && (
3772
- (raw_event.keyCode === 13 && (type === 'text' || type === 'password')) ||
3773
- (raw_event.type === 'click' && (type === 'submit' || type === 'image'))
3774
- )) {
3775
- event.type = 'submit';
3776
- event.target = $(form);
3777
- parent.fire(event);
3778
- }
3922
+ /**
3923
+ * Fires the actual mouseenter/mouseleave event
3924
+ *
3925
+ * @param original event
3926
+ * @param raw dom element
3927
+ * @param integer uid
3928
+ * @param boolean mouseenter or mouseleave
3929
+ * @return void
3930
+ */
3931
+ function mouse_io_fire(raw, element, uid, enter) {
3932
+ var event = new Event(raw);
3933
+ event.type = enter === true ? 'mouseenter' : 'mouseleave';
3934
+ event.bubbles = false;
3935
+ event.stopped = true;
3936
+ event.target = wrap(element);
3937
+
3938
+ // replacing the #find method so that UJS didn't
3939
+ // get broke with trying to find nested elements
3940
+ event.find = function(css_rule) {
3941
+ return $$(css_rule, true)
3942
+ .indexOf(this.target._) === -1 ?
3943
+ undefined : this.target;
3779
3944
  };
3780
3945
 
3781
- document.attachEvent('onclick', submit_boobler);
3782
- document.attachEvent('onkeypress', submit_boobler);
3946
+ event.target.fire(event);
3947
+ current_Document.fire(event);
3783
3948
  }
3784
3949
 
3785
- if (!event_support_for('onchange', 'input')) {
3786
-
3787
- var get_input_value = function(target) {
3788
- var element = target._,
3789
- type = element.type;
3790
-
3791
- return type === 'radio' || type === 'checkbox' ?
3792
- element.checked : target.getValue();
3793
- },
3794
-
3795
- /**
3796
- * Emulates the 'change' event bubbling
3797
- *
3798
- * @param Event wrapped dom-event
3799
- * @param Input wrapped input element
3800
- * @return void
3801
- */
3802
- change_boobler = function(event, target) {
3803
- var parent = target.parent(),
3804
- value = get_input_value(target);
3950
+ /**
3951
+ * Figures out the enter/leave events by listening the
3952
+ * mouseovers in the document
3953
+ *
3954
+ * @param raw dom event
3955
+ * @return void
3956
+ */
3957
+ function mouse_io_handler(e) {
3958
+ var target = e.target || e.srcElement,
3959
+ from = e.relatedTarget || e.fromElement,
3960
+ element = target,
3961
+ passed = false,
3962
+ parents = [],
3963
+ uid, event;
3964
+
3965
+ while (element.nodeType === 1) {
3966
+ uid = $uid(element);
3967
+
3968
+ if (mouse_io_index[uid] === undefined) {
3969
+ mouse_io_fire(e, element, uid,
3970
+ mouse_io_index[uid] = true
3971
+ );
3972
+ }
3805
3973
 
3806
- if (parent && ''+target._prev_value !== ''+value) {
3807
- target._prev_value = value; // saving the value so it didn't fire up again
3808
- event.type = 'change';
3809
- parent.fire(event);
3974
+ if (element === from) {
3975
+ passed = true;
3810
3976
  }
3811
- },
3812
3977
 
3813
- /**
3814
- * Catches the input field changes
3815
- *
3816
- * @param raw dom-event
3817
- * @return void
3818
- */
3819
- catch_inputs_access = function(raw_event) {
3820
- var event = $(raw_event),
3821
- target = event.target,
3822
- type = target._.type,
3823
- tag = target._.tagName,
3824
- input_is_radio = (type === 'radio' || type === 'checkbox');
3978
+ parents.push(element);
3825
3979
 
3826
- if (
3827
- (event.type === 'click' && (input_is_radio || tag === 'SELECT')) ||
3828
- (event.type === 'keydown' && (
3829
- (event.keyCode == 13 && (tag !== 'TEXTAREA')) ||
3830
- type === 'select-multiple'
3831
- ))
3832
- ) {
3833
- change_boobler(event, target);
3834
- }
3835
- },
3980
+ element = element.parentNode;
3981
+ }
3836
3982
 
3837
- /**
3838
- * Catch inputs blur
3839
- *
3840
- * @param raw dom-event
3841
- * @return void
3842
- */
3843
- catch_input_left = function(raw_event) {
3844
- var event = $(raw_event),
3845
- target = event.target;
3983
+ if (from && !passed) {
3984
+ while (from !== null && from.nodeType === 1 && parents.indexOf(from) === -1) {
3985
+ uid = $uid(from);
3986
+ if (mouse_io_index[uid] !== undefined) {
3987
+ mouse_io_fire(e, from, uid,
3988
+ mouse_io_index[uid] = undefined
3989
+ );
3990
+ }
3846
3991
 
3847
- if (target instanceof Input) {
3848
- change_boobler(event, target);
3992
+ from = from.parentNode;
3849
3993
  }
3850
- };
3994
+ }
3995
+ }
3851
3996
 
3852
- document.attachEvent('onclick', catch_inputs_access);
3853
- document.attachEvent('onkeydown', catch_inputs_access);
3854
- document.attachEvent('onfocusout', catch_input_left);
3997
+ /**
3998
+ * Calling 'mouseleave' for all currently active elements on the page
3999
+ *
4000
+ * @return void
4001
+ */
4002
+ function mouse_io_reset(e) {
4003
+ mouse_io_index.each(function(value, uid) {
4004
+ if (value && Wrappers_Cache[uid]) {
4005
+ mouse_io_fire(e, Wrappers_Cache[uid]._, uid, false);
4006
+ }
4007
+ });
4008
+ }
3855
4009
 
3856
- /**
3857
- * storing the input element previous value, so we could figure out
3858
- * if it was changed later on
3859
- */
3860
- document.attachEvent('onbeforeactivate', function(event) {
3861
- var element = $(event).target;
4010
+ /**
4011
+ * Activating the mouse-io events emulation
4012
+ *
4013
+ * @return void
4014
+ */
4015
+ function mouse_io_activate() {
4016
+ if (mouse_io_inactive) {
4017
+ mouse_io_inactive = false;
3862
4018
 
3863
- if (element instanceof Input) {
3864
- element._prev_value = get_input_value(element);
4019
+ if (Browser_IE) {
4020
+ document.attachEvent('onmouseover', mouse_io_handler);
4021
+ window.attachEvent('blur', mouse_io_reset);
4022
+ } else {
4023
+ document.addEventListener('mouseover', mouse_io_handler, false);
4024
+ window.addEventListener('blur', mouse_io_reset, false);
3865
4025
  }
3866
- });
4026
+ }
3867
4027
  }
3868
4028
 
4029
+ Element_add_event_shortcuts('mouseenter mouseleave');
3869
4030
 
3870
4031
  /**
3871
4032
  * This module the standard events delegation interface
3872
4033
  *
3873
- * Copyright (C) 2010 Nikolay Nemshilov
4034
+ * Copyright (C) 2010-2011 Nikolay Nemshilov
3874
4035
  */
3875
4036
  [Element, Document].each('include', {
3876
4037
  /**
@@ -3972,15 +4133,24 @@ if (!event_support_for('onchange', 'input')) {
3972
4133
  }
3973
4134
  });
3974
4135
 
4136
+ /**
4137
+ * Builds the actual event listener that will delegate stuff
4138
+ * to other elements as they reach the element where the listener
4139
+ * attached
4140
+ *
4141
+ * @param String css rule
4142
+ * @param Arguments the original arguments list
4143
+ * @param Object scope
4144
+ * @return Function the actual event listener
4145
+ */
3975
4146
  function build_delegative_listener(css_rule, entry, scope) {
4147
+ var args = $A(entry), callback = args.shift();
3976
4148
  return function(event) {
3977
- var target = event.target, args = $A(entry), callback = args.shift();
3978
- if (scope.find(css_rule).include(target)) {
3979
- return isFunction(callback) ?
3980
- callback.apply(target, [event].concat(args)) :
3981
- target[callback].apply(target, args);
3982
- }
3983
- return undefined;
4149
+ var target = event.find(css_rule);
4150
+ return target === undefined ? target :
4151
+ typeof(callback) === 'string' ?
4152
+ target[callback].apply(target, args) :
4153
+ callback.apply(target, [event].concat(args));
3984
4154
  };
3985
4155
  }
3986
4156
 
@@ -4044,6 +4214,12 @@ function delegation_listeners(args, object) {
4044
4214
  }
4045
4215
 
4046
4216
 
4217
+ /**
4218
+ * Some String level shortcuts to handle collections of elements
4219
+ *
4220
+ * Copyright (C) 2011 Nikolay Nemshilov
4221
+ */
4222
+
4047
4223
  /**
4048
4224
  * Some nice shortcuts for the document-level events delegation handling
4049
4225
  *
@@ -4077,17 +4253,17 @@ Object.each({
4077
4253
  stopObserving: 'undelegate',
4078
4254
  observes: 'delegates'
4079
4255
  }, function(name, method) {
4080
- String[PROTO][name] = function() {
4081
- var doc = $(document), args = $A(arguments), result;
4256
+ String.prototype[name] = function() {
4257
+ var args = $A(arguments), result;
4082
4258
 
4083
4259
  args.splice(1,0,''+this);
4084
- result = doc[method].apply(doc, args);
4260
+ result = current_Document[method].apply(current_Document, args);
4085
4261
 
4086
- return result === doc ? this : result;
4262
+ return result === current_Document ? this : result;
4087
4263
  };
4088
4264
  });
4089
- var old_on = String[PROTO].on;
4090
- String[PROTO].on = function(hash) {
4265
+ var old_on = String.prototype.on;
4266
+ String.prototype.on = function(hash) {
4091
4267
  if (isHash(hash)) {
4092
4268
  for (var key in hash) {
4093
4269
  old_on.apply(this, [key].concat([hash[key]]));
@@ -4107,11 +4283,44 @@ String[PROTO].on = function(hash) {
4107
4283
  * "#css.rule".onMouseover('method_name');
4108
4284
  */
4109
4285
  Event_delegation_shortcuts.each(function(name) {
4110
- String[PROTO]['on'+name.capitalize()] = function() {
4286
+ String.prototype['on'+name.capitalize()] = function() {
4111
4287
  return this.on.apply(this, [name].concat($A(arguments)));
4112
4288
  };
4113
4289
  });
4114
4290
 
4291
+ /**
4292
+ * The rest of the DOM methods access
4293
+ *
4294
+ * USAGE:
4295
+ * "#css.rule".addClass('boo-hoo');
4296
+ * "#css.rule".setStyle({color: 'red'});
4297
+ *
4298
+ */
4299
+ $w('Element Input Form').each(function(klass) {
4300
+ Object.each(klass in RightJS ? RightJS[klass].prototype : {}, function(name, method) {
4301
+ if (isFunction(method) && !(name in String.prototype)) {
4302
+ String.prototype[name] = function() {
4303
+ var nodes = $$(this, true), i=0, l = nodes.length, first=true, element, result;
4304
+ for (; i < l; i++) {
4305
+ element = wrap(nodes[i]);
4306
+ result = element[name].apply(element, arguments);
4307
+
4308
+ // checking if that's a data-retrieving call
4309
+ if (first) {
4310
+ if (result !== element) {
4311
+ return result;
4312
+ }
4313
+ first = false;
4314
+ }
4315
+ }
4316
+
4317
+ // don't return the string itself in here,
4318
+ // it will screw with data-retrieving calls on empty collections
4319
+ return null;
4320
+ };
4321
+ }
4322
+ });
4323
+ });
4115
4324
 
4116
4325
  /**
4117
4326
  * XMLHttpRequest wrapper
@@ -4122,7 +4331,7 @@ Event_delegation_shortcuts.each(function(name) {
4122
4331
  * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
4123
4332
  * - jQuery (http://jquery.com) Copyright (C) John Resig
4124
4333
  *
4125
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
4334
+ * Copyright (C) 2008-2011 Nikolay V. Nemshilov
4126
4335
  */
4127
4336
  var Xhr = RightJS.Xhr = new Class(Observer, {
4128
4337
  extend: {
@@ -4159,7 +4368,7 @@ var Xhr = RightJS.Xhr = new Class(Observer, {
4159
4368
  * @return Xhr request
4160
4369
  */
4161
4370
  load: function(url, options) {
4162
- return new this(url, Object.merge({method: 'get'}, options)).send();
4371
+ return new this(url, $ext({method: 'get'}, options)).send();
4163
4372
  }
4164
4373
  },
4165
4374
 
@@ -4224,7 +4433,11 @@ var Xhr = RightJS.Xhr = new Class(Observer, {
4224
4433
  * @return Xhr self
4225
4434
  */
4226
4435
  send: function(params) {
4227
- var add_params = {}, url = this.url, method = this.method.toLowerCase(), headers = this.headers, key, xhr;
4436
+ var add_params = {},
4437
+ url = this.url,
4438
+ method = this.method.toLowerCase(),
4439
+ headers = this.headers,
4440
+ key, xhr;
4228
4441
 
4229
4442
  if (method == 'put' || method == 'delete') {
4230
4443
  add_params._method = method;
@@ -4284,7 +4497,7 @@ var Xhr = RightJS.Xhr = new Class(Observer, {
4284
4497
  if (!xhr || xhr.canceled) { return this; }
4285
4498
 
4286
4499
  xhr.abort();
4287
- xhr.onreadystatechange = dummy();
4500
+ xhr.onreadystatechange = function() {};
4288
4501
  xhr.canceled = true;
4289
4502
 
4290
4503
  return this.fire('cancel');
@@ -4302,12 +4515,10 @@ var Xhr = RightJS.Xhr = new Class(Observer, {
4302
4515
  return new Xhr.JSONP(this);
4303
4516
  } else if (this.form && this.form.first('input[type=file]')) {
4304
4517
  return new Xhr.IFramed(this.form);
4518
+ } else if ('ActiveXObject' in window){
4519
+ return new ActiveXObject('MSXML2.XMLHTTP');
4305
4520
  } else {
4306
- try {
4307
- return new XMLHttpRequest();
4308
- } catch(e) {
4309
- return new ActiveXObject('MSXML2.XMLHTTP');
4310
- }
4521
+ return new XMLHttpRequest();
4311
4522
  }
4312
4523
  },
4313
4524
 
@@ -4360,20 +4571,17 @@ var Xhr = RightJS.Xhr = new Class(Observer, {
4360
4571
 
4361
4572
  // sanitizes the json-response texts
4362
4573
  sanitizedJSON: function() {
4363
- try {
4364
- return JSON.parse(this.text);
4365
- } catch(e) {
4366
- // manual json consistancy check
4367
- if (window.JSON || !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(this.text.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''))) {
4368
- if (this.secureJSON) {
4369
- throw "JSON error: "+this.text;
4370
- }
4371
- return null;
4574
+ if (!(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(
4575
+ this.text.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '')
4576
+ )) {
4577
+ if (this.secureJSON) {
4578
+ throw "JSON error: "+this.text;
4372
4579
  }
4580
+ return null;
4373
4581
  }
4374
4582
 
4375
- // the fallback JSON extraction
4376
- return eval("("+this.text+")");
4583
+ return 'JSON' in window ? JSON.parse(this.text) :
4584
+ (new Function("return "+this.text))();
4377
4585
  },
4378
4586
 
4379
4587
  // initializes the request callbacks
@@ -4443,21 +4651,8 @@ $ext(Observer_create(Xhr), {
4443
4651
  * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
4444
4652
  * - jQuery (http://jquery.com) Copyright (C) John Resig
4445
4653
  *
4446
- * Copyright (C) 2009-2010 Nikolay V. Nemshilov
4654
+ * Copyright (C) 2009-2011 Nikolay V. Nemshilov
4447
4655
  */
4448
-
4449
- /**
4450
- * Catches the form submit events and sends the form remotely
4451
- *
4452
- * @param Event submit
4453
- * @param Object xhr options
4454
- * @return void
4455
- */
4456
- function remote_send(event, options) {
4457
- event.stop();
4458
- this.send(Object.merge({spinner: this.first('.spinner')}, options));
4459
- }
4460
-
4461
4656
  Form.include({
4462
4657
  /**
4463
4658
  * sends the form via xhr request
@@ -4469,13 +4664,31 @@ Form.include({
4469
4664
  options = options || {};
4470
4665
  options.method = options.method || this._.method || 'post';
4471
4666
 
4472
- new Xhr(this._.action || document.location.href, options)
4473
- .onComplete(this.enable.bind(this)).send(this);
4667
+ this.xhr = new Xhr(
4668
+ this._.action || document.location.href,
4669
+ $ext({spinner: this.first('.spinner')}, options)
4670
+ )
4671
+ .onComplete(this.enable.bind(this))
4672
+ .onCancel(this.enable.bind(this))
4673
+ .send(this);
4474
4674
 
4475
4675
  this.disable.bind(this).delay(1); // webkit needs this async call with iframed calls
4476
4676
  return this;
4477
4677
  },
4478
4678
 
4679
+ /**
4680
+ * Cancels current Xhr request (if there are any)
4681
+ *
4682
+ * @return Form this
4683
+ */
4684
+ cancelXhr: function() {
4685
+ if (this.xhr instanceof Xhr) {
4686
+ this.xhr.cancel();
4687
+ }
4688
+
4689
+ return this;
4690
+ },
4691
+
4479
4692
  /**
4480
4693
  * makes the form be remote by default
4481
4694
  *
@@ -4483,10 +4696,11 @@ Form.include({
4483
4696
  * @return Form this
4484
4697
  */
4485
4698
  remotize: function(options) {
4486
- if (!this.observes('submit', remote_send)) {
4487
- this.on('submit', remote_send, options);
4699
+ if (!this.remote) {
4700
+ this.on('submit', Form_remote_send, options);
4488
4701
  this.remote = true;
4489
4702
  }
4703
+
4490
4704
  return this;
4491
4705
  },
4492
4706
 
@@ -4496,13 +4710,24 @@ Form.include({
4496
4710
  * @return Form this
4497
4711
  */
4498
4712
  unremotize: function() {
4499
- this.stopObserving('submit', remote_send);
4713
+ this.stopObserving('submit', Form_remote_send);
4500
4714
  this.remote = false;
4501
-
4502
4715
  return this;
4503
4716
  }
4504
4717
  });
4505
4718
 
4719
+ /**
4720
+ * Catches the form submit events and sends the form remotely
4721
+ *
4722
+ * @param Event submit
4723
+ * @param Object xhr options
4724
+ * @return void
4725
+ */
4726
+ function Form_remote_send(event, options) {
4727
+ event.stop();
4728
+ this.send(options);
4729
+ }
4730
+
4506
4731
 
4507
4732
  /**
4508
4733
  * this module contains the Element unit XHR related extensions
@@ -4510,7 +4735,7 @@ Form.include({
4510
4735
  * Credits:
4511
4736
  * - jQuery (http://jquery.com) Copyright (C) John Resig
4512
4737
  *
4513
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
4738
+ * Copyright (C) 2008-2011 Nikolay V. Nemshilov
4514
4739
  */
4515
4740
  Element.include({
4516
4741
  /**
@@ -4522,7 +4747,7 @@ Element.include({
4522
4747
  * @return Element this
4523
4748
  */
4524
4749
  load: function(url, options) {
4525
- new Xhr(url, Object.merge({method: 'get'}, options)).update(this);
4750
+ new Xhr(url, $ext({method: 'get'}, options)).update(this);
4526
4751
  return this;
4527
4752
  }
4528
4753
  });
@@ -4532,13 +4757,12 @@ Element.include({
4532
4757
  * A dummy XmlHTTPRequest interface to be used in other
4533
4758
  * fake requests
4534
4759
  *
4535
- * Copyright (C) 2010 Nikolay Nemshilov
4760
+ * Copyright (C) 2010-2011 Nikolay Nemshilov
4536
4761
  */
4537
4762
  Xhr.Dummy = {
4538
- open: dummy(),
4539
- abort: dummy(),
4540
- setRequestHeader: dummy(),
4541
- onreadystatechange: dummy()
4763
+ open: function() {},
4764
+ setRequestHeader: function() {},
4765
+ onreadystatechange: function() {}
4542
4766
  };
4543
4767
 
4544
4768
 
@@ -4546,7 +4770,7 @@ Xhr.Dummy = {
4546
4770
  * This unit presents a fake drop in replacement for the XmlHTTPRequest unit
4547
4771
  * but works with an iframe targeting in the background
4548
4772
  *
4549
- * Copyright (C) 2008-2010 Nikolay Nemshilov
4773
+ * Copyright (C) 2008-2011 Nikolay Nemshilov
4550
4774
  */
4551
4775
  Xhr.IFramed = new Class({
4552
4776
  include: Xhr.Dummy,
@@ -4561,7 +4785,7 @@ Xhr.IFramed = new Class({
4561
4785
  this.form = form;
4562
4786
  this.id = 'xhr_'+ new Date().getTime();
4563
4787
 
4564
- form.insert('<i><iframe name="'+this.id+'" id="'+this.id+
4788
+ this.form.doc().first('body').append('<i><iframe name="'+this.id+'" id="'+this.id+
4565
4789
  '" width="0" height="0" frameborder="0" src="about:blank"></iframe></i>',
4566
4790
  'after');
4567
4791
 
@@ -4575,7 +4799,7 @@ Xhr.IFramed = new Class({
4575
4799
  onLoad: function() {
4576
4800
  this.status = 200;
4577
4801
  this.readyState = 4;
4578
-
4802
+
4579
4803
  this.form.set('target', '');
4580
4804
 
4581
4805
  try {
@@ -4583,6 +4807,10 @@ Xhr.IFramed = new Class({
4583
4807
  } catch(e) { }
4584
4808
 
4585
4809
  this.onreadystatechange();
4810
+ },
4811
+
4812
+ abort: function() {
4813
+ $(this.id).set('src', 'about:blank');
4586
4814
  }
4587
4815
  });
4588
4816
 
@@ -4590,7 +4818,7 @@ Xhr.IFramed = new Class({
4590
4818
  /**
4591
4819
  * The JSONP Xhr request tonnel
4592
4820
  *
4593
- * Copyright (C) 2010 Nikolay Nemshilov
4821
+ * Copyright (C) 2010-2011 Nikolay Nemshilov
4594
4822
  */
4595
4823
  Xhr.JSONP = new Class({
4596
4824
  include: Xhr.Dummy,
@@ -4654,6 +4882,16 @@ Xhr.JSONP = new Class({
4654
4882
  this.xhr.json = this.xhr.responseJSON = data;
4655
4883
 
4656
4884
  this.onreadystatechange();
4885
+ },
4886
+
4887
+ /**
4888
+ * We can't really cancel a JSONP request
4889
+ * but we can prevent the default handler to ckick in
4890
+ *
4891
+ * @return void
4892
+ */
4893
+ abort: function() {
4894
+ window[this.name] = function() {};
4657
4895
  }
4658
4896
  });
4659
4897
 
@@ -4665,7 +4903,7 @@ Xhr.JSONP = new Class({
4665
4903
  * The basic principles, structures and naming system are inspired by
4666
4904
  * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
4667
4905
  *
4668
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
4906
+ * Copyright (C) 2008-2011 Nikolay V. Nemshilov
4669
4907
  */
4670
4908
  var Fx = RightJS.Fx = new Class(Observer, {
4671
4909
  extend: {
@@ -4680,7 +4918,7 @@ var Fx = RightJS.Fx = new Class(Observer, {
4680
4918
 
4681
4919
  // default options
4682
4920
  Options: {
4683
- fps: Browser.IE ? 40 : 60,
4921
+ fps: IE8_OR_LESS ? 40 : 60,
4684
4922
  duration: 'normal',
4685
4923
  transition: 'Sin',
4686
4924
  queue: true
@@ -4707,10 +4945,7 @@ var Fx = RightJS.Fx = new Class(Observer, {
4707
4945
  Lin: function(i) {
4708
4946
  return i;
4709
4947
  }
4710
- },
4711
-
4712
- ch: [], // scheduled effects registries
4713
- cr: [] // currently running effects registries
4948
+ }
4714
4949
  },
4715
4950
 
4716
4951
  /**
@@ -4720,12 +4955,8 @@ var Fx = RightJS.Fx = new Class(Observer, {
4720
4955
  */
4721
4956
  initialize: function(element, options) {
4722
4957
  this.$super(options);
4723
-
4724
- if ((this.element = element = $(element))) {
4725
- var uid = $uid(element);
4726
- this.ch = (Fx.ch[uid] = Fx.ch[uid] || []);
4727
- this.cr = (Fx.cr[uid] = Fx.cr[uid] || []);
4728
- }
4958
+ this.element = $(element);
4959
+ fx_register(this);
4729
4960
  },
4730
4961
 
4731
4962
  /**
@@ -4734,21 +4965,21 @@ var Fx = RightJS.Fx = new Class(Observer, {
4734
4965
  * @return Fx this
4735
4966
  */
4736
4967
  start: function() {
4737
- if (this.queue(arguments)) { return this; }
4738
- this.prepare.apply(this, arguments);
4968
+ if (fx_add_to_queue(this, arguments)) { return this; }
4739
4969
 
4740
- var options = this.options,
4741
- duration = Fx.Durations[options.duration] || options.duration;
4742
- this.transition = Fx.Transitions[options.transition] || options.transition;
4970
+ var options = this.options,
4971
+ duration = Fx.Durations[options.duration] || options.duration,
4972
+ transition = Fx.Transitions[options.transition] || options.transition,
4973
+ steps = (duration / 1000 * this.options.fps).ceil(),
4974
+ interval = (1000 / this.options.fps).round();
4743
4975
 
4744
- this.steps = (duration / 1000 * this.options.fps).ceil();
4745
- this.number = 1;
4976
+ fx_mark_current(this);
4746
4977
 
4747
- if (this.cr) {
4748
- this.cr.push(this); // adding this effect to the list of currently active
4749
- }
4978
+ this.prepare.apply(this, arguments);
4750
4979
 
4751
- return this.fire('start', this).startTimer();
4980
+ fx_start_timer(this, transition, interval, steps);
4981
+
4982
+ return this.fire('start', this);
4752
4983
  },
4753
4984
 
4754
4985
  /**
@@ -4757,7 +4988,11 @@ var Fx = RightJS.Fx = new Class(Observer, {
4757
4988
  * @return Fx this
4758
4989
  */
4759
4990
  finish: function() {
4760
- return this.stopTimer().unreg().fire('finish').next();
4991
+ fx_stop_timer(this);
4992
+ fx_remove_from_queue(this);
4993
+ this.fire('finish');
4994
+ fx_run_next(this);
4995
+ return this;
4761
4996
  },
4762
4997
 
4763
4998
  /**
@@ -4770,100 +5005,140 @@ var Fx = RightJS.Fx = new Class(Observer, {
4770
5005
  * @return Fx this
4771
5006
  */
4772
5007
  cancel: function() {
4773
- this.ch.clean();
4774
- return this.stopTimer().unreg().fire('cancel');
4775
- },
4776
-
4777
- /**
4778
- * pauses the transition
4779
- *
4780
- * @return Fx this
4781
- */
4782
- pause: function() {
4783
- return this.stopTimer();
4784
- },
4785
-
4786
- /**
4787
- * resumes a paused transition
4788
- *
4789
- * @return Fx this
4790
- */
4791
- resume: function() {
4792
- return this.startTimer();
5008
+ fx_stop_timer(this);
5009
+ fx_remove_from_queue(this);
5010
+ return this.fire('cancel');
4793
5011
  },
4794
5012
 
4795
5013
  // protected
4796
5014
  // dummy method, should be implemented in a subclass
4797
- prepare: function(values) {},
5015
+ prepare: function() {},
4798
5016
 
4799
5017
  // dummy method, processes the element properties
4800
- render: function(delta) {},
5018
+ render: function() {}
5019
+ }),
4801
5020
 
4802
- // the periodically called method
4803
- // NOTE: called outside of the instance scope!
4804
- step: function(that) {
4805
- if (that.number > that.steps) {
4806
- that.finish();
4807
- } else {
4808
- if (!that.w) {
4809
- that.w = true;
4810
- that.render(that.transition(that.number / that.steps));
4811
- that.w = false;
4812
- }
4813
- that.number ++;
4814
- }
4815
- },
5021
+ // global effects registry
5022
+ scheduled_fx = [], running_fx = [];
4816
5023
 
4817
- // starts the effect timer
4818
- startTimer: function() {
4819
- this.timer = this.step.periodical((1000 / this.options.fps).round(), this);
4820
- return this;
4821
- },
5024
+ /**
5025
+ * Registers the element in the effects queue
5026
+ *
5027
+ * @param Fx effect
5028
+ * @return void
5029
+ */
5030
+ function fx_register(fx) {
5031
+ var uid = $uid((fx.element || {})._ || {});
5032
+ fx.ch = (scheduled_fx[uid] = scheduled_fx[uid] || []);
5033
+ fx.cr = (running_fx[uid] = running_fx[uid] || []);
5034
+ }
4822
5035
 
4823
- // stops the effect timer
4824
- stopTimer: function() {
4825
- if (this.timer) {
4826
- this.timer.stop();
4827
- }
4828
- return this;
4829
- },
5036
+ /**
5037
+ * Registers the effect in the effects queue
5038
+ *
5039
+ * @param Fx fx
5040
+ * @param Arguments original arguments list
5041
+ * @return boolean true if it queued and false if it's ready to go
5042
+ */
5043
+ function fx_add_to_queue(fx, args) {
5044
+ var chain = fx.ch, queue = fx.options.queue;
4830
5045
 
4831
- // handles effects queing
4832
- // should return false if there's no queue and true if there is a queue
4833
- queue: function(args) {
4834
- var chain = this.ch, queue = this.options.queue;
5046
+ if (!chain || fx.$ch) {
5047
+ return (fx.$ch = false);
5048
+ }
4835
5049
 
4836
- if (!chain || this.$ch) {
4837
- return (this.$ch = false);
4838
- }
5050
+ if (queue) {
5051
+ chain.push([args, fx]);
5052
+ }
4839
5053
 
4840
- if (queue) {
4841
- chain.push([args, this]);
4842
- }
5054
+ return queue && chain[0][1] !== fx;
5055
+ }
4843
5056
 
4844
- return queue && chain[0][1] !== this;
4845
- },
5057
+ /**
5058
+ * Puts the fx into the list of currently running effects
5059
+ *
5060
+ * @param Fx fx
5061
+ * @return void
5062
+ */
5063
+ function fx_mark_current(fx) {
5064
+ if (fx.cr) {
5065
+ fx.cr.push(fx);
5066
+ }
5067
+ }
4846
5068
 
4847
- // calls for the next effect in the queue
4848
- next: function() {
4849
- var chain = this.ch, next = chain.shift();
4850
- if ((next = chain[0])) {
4851
- next[1].$ch = true;
4852
- next[1].start.apply(next[1], next[0]);
4853
- }
4854
- return this;
4855
- },
5069
+ /**
5070
+ * Removes the fx from the queue
5071
+ *
5072
+ * @param Fx fx
5073
+ * @return void
5074
+ */
5075
+ function fx_remove_from_queue(fx) {
5076
+ var currents = fx.cr;
5077
+ if (currents) {
5078
+ currents.splice(currents.indexOf(fx), 1);
5079
+ }
5080
+ }
4856
5081
 
4857
- // unregisters this effect out of the currently running list
4858
- unreg: function() {
4859
- var currents = this.cr;
4860
- if (currents) {
4861
- currents.splice(currents.indexOf(this), 1);
4862
- }
4863
- return this;
5082
+ /**
5083
+ * Tries to invoke the next effect in the queue
5084
+ *
5085
+ * @param Fx fx
5086
+ * @return void
5087
+ */
5088
+ function fx_run_next(fx) {
5089
+ var chain = fx.ch, next = chain.shift();
5090
+ if ((next = chain[0])) {
5091
+ next[1].$ch = true;
5092
+ next[1].start.apply(next[1], next[0]);
4864
5093
  }
5094
+ }
4865
5095
 
4866
- });
5096
+ /**
5097
+ * Cancels all currently running and scheduled effects
5098
+ * on the element
5099
+ *
5100
+ * @param Element element
5101
+ * @return void
5102
+ */
5103
+ function fx_cancel_all(element) {
5104
+ var uid = $uid(element._);
5105
+
5106
+ (running_fx[uid] || []).each('cancel');
5107
+ (scheduled_fx[uid] || []).splice(0);
5108
+ }
5109
+
5110
+ /**
5111
+ * Initializes the fx rendering timer
5112
+ *
5113
+ * @param Fx fx
5114
+ * @param Function transition stops calculator
5115
+ * @param Float interval
5116
+ * @param Integer number of steps
5117
+ * @return void
5118
+ */
5119
+ function fx_start_timer(fx, transition, interval, steps) {
5120
+ var number = 1;
5121
+ fx._timer = setInterval(function() {
5122
+ if (number > steps) {
5123
+ fx.finish();
5124
+ } else {
5125
+ fx.render(transition(number/steps));
5126
+ number ++;
5127
+ }
5128
+ }, interval);
5129
+ }
5130
+
5131
+ /**
5132
+ * Cancels the Fx rendering timer (if any)
5133
+ *
5134
+ * @param Fx fx
5135
+ * @return void
5136
+ */
5137
+ function fx_stop_timer(fx) {
5138
+ if (fx._timer) {
5139
+ clearInterval(fx._timer);
5140
+ }
5141
+ }
4867
5142
 
4868
5143
 
4869
5144
  /**
@@ -4941,14 +5216,8 @@ String.include({
4941
5216
  * Some ideas are inspired by
4942
5217
  * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
4943
5218
  *
4944
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
5219
+ * Copyright (C) 2008-2011 Nikolay V. Nemshilov
4945
5220
  */
4946
- var methods = Element.prototype,
4947
- old_hide = methods.hide,
4948
- old_show = methods.show,
4949
- old_remove = methods.remove,
4950
- old_scroll = methods.scrollTo;
4951
-
4952
5221
  Element.include({
4953
5222
  /**
4954
5223
  * Stops all the visual effects on the element
@@ -4956,7 +5225,7 @@ Element.include({
4956
5225
  * @return Element this
4957
5226
  */
4958
5227
  stop: function() {
4959
- (Fx.cr[$uid(this)] || []).each('cancel');
5228
+ fx_cancel_all(this);
4960
5229
  return this;
4961
5230
  },
4962
5231
 
@@ -4968,7 +5237,7 @@ Element.include({
4968
5237
  * @return Element this
4969
5238
  */
4970
5239
  hide: function(fx, options) {
4971
- return (fx && this.visible()) ? this.fx(fx, ['out', options]) : old_hide.call(this);
5240
+ return (fx && this.visible()) ? call_fx(this, fx, ['out', options]) : this.$super();
4972
5241
  },
4973
5242
 
4974
5243
  /**
@@ -4979,7 +5248,18 @@ Element.include({
4979
5248
  * @return Element this
4980
5249
  */
4981
5250
  show: function(fx, options) {
4982
- return (fx && !this.visible()) ? this.fx(fx, ['in', options]) : old_show.call(this);
5251
+ return (fx && !this.visible()) ? call_fx(this, fx, ['in', options]) : this.$super();
5252
+ },
5253
+
5254
+ /**
5255
+ * Toggles the element state with visual effect
5256
+ *
5257
+ * @param String fx name
5258
+ * @param Object fx options
5259
+ * @return Element this
5260
+ */
5261
+ toggle: function(fx, options) {
5262
+ return fx ? call_fx(this, fx, ['toggle', options]) : this.$super();
4983
5263
  },
4984
5264
 
4985
5265
  /**
@@ -4990,9 +5270,9 @@ Element.include({
4990
5270
  * @return Element this
4991
5271
  */
4992
5272
  remove: function(fx, options) {
4993
- return (fx && this.visible()) ? this.fx(fx, ['out', Object.merge(options, {
4994
- onFinish: old_remove.bind(this)
4995
- })]) : old_remove.call(this);
5273
+ return (fx && this.visible()) ? call_fx(this, fx, ['out', $ext(options || {}, {
5274
+ onFinish: this.$super.bind(this)
5275
+ })]) : this.$super();
4996
5276
  },
4997
5277
 
4998
5278
  /**
@@ -5003,7 +5283,7 @@ Element.include({
5003
5283
  * @return Element self
5004
5284
  */
5005
5285
  morph: function(style, options) {
5006
- return this.fx('morph', [style, options || {}]); // <- don't replace with arguments
5286
+ return call_fx(this, 'morph', [style, options || {}]); // <- don't replace with arguments
5007
5287
  },
5008
5288
 
5009
5289
  /**
@@ -5015,7 +5295,7 @@ Element.include({
5015
5295
  * @return Element self
5016
5296
  */
5017
5297
  highlight: function() {
5018
- return this.fx('highlight', arguments);
5298
+ return call_fx(this, 'highlight', arguments);
5019
5299
  },
5020
5300
 
5021
5301
  /**
@@ -5025,7 +5305,7 @@ Element.include({
5025
5305
  * @return Element self
5026
5306
  */
5027
5307
  fade: function() {
5028
- return this.fx('fade', arguments);
5308
+ return call_fx(this, 'fade', arguments);
5029
5309
  },
5030
5310
 
5031
5311
  /**
@@ -5036,7 +5316,7 @@ Element.include({
5036
5316
  * @return Element self
5037
5317
  */
5038
5318
  slide: function() {
5039
- return this.fx('slide', arguments);
5319
+ return call_fx(this, 'slide', arguments);
5040
5320
  },
5041
5321
 
5042
5322
  /**
@@ -5047,7 +5327,7 @@ Element.include({
5047
5327
  * @return Element this
5048
5328
  */
5049
5329
  scroll: function(value, options) {
5050
- return this.fx('scroll', [value, options||{}]);
5330
+ return call_fx(this, 'scroll', [value, options||{}]);
5051
5331
  },
5052
5332
 
5053
5333
  /**
@@ -5059,35 +5339,134 @@ Element.include({
5059
5339
  * @return Element this
5060
5340
  */
5061
5341
  scrollTo: function(value, options) {
5062
- return isHash(options) ? this.scroll(value, options) : old_scroll.apply(this, arguments);
5063
- },
5064
-
5065
-
5066
- // protected
5067
-
5068
- // runs an Fx on the element
5069
- fx: function(name, params) {
5070
- var args = $A(params).compact(), options = isHash(args.last()) ? args.pop() : {},
5071
- fx = new Fx[name.capitalize()](this, options);
5342
+ return isHash(options) ? this.scroll(value, options) : this.$super.apply(this, arguments);
5343
+ }
5344
+ });
5072
5345
 
5073
- fx.start.apply(fx, args);
5346
+ /**
5347
+ * Calls the visual effect on the element
5348
+ *
5349
+ * @param Element context
5350
+ * @param String fx-name
5351
+ * @param Object fx-options
5352
+ * @return Element context
5353
+ */
5354
+ function call_fx(element, name, params) {
5355
+ var args = $A(params).compact(),
5356
+ options = isHash(args.last()) ? args.pop() : {},
5357
+ fx = new Fx[name.capitalize()](element, options);
5074
5358
 
5075
- return this;
5076
- }
5359
+ fx.start.apply(fx, args);
5077
5360
 
5078
- });
5361
+ return element;
5362
+ }
5079
5363
 
5080
5364
 
5081
5365
  /**
5082
5366
  * This class provides the basic effect for styles manipulation
5083
5367
  *
5084
- * Credits:
5085
- * The idea is inspired by the Morph effect from
5086
- * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
5087
- *
5088
- * Copyright (C) 2008-2010 Nikolay Nemshilov
5368
+ * Copyright (C) 2008-2011 Nikolay Nemshilov
5089
5369
  */
5090
5370
 
5371
+ /////////////////////////////////////////////////////////////////////////////
5372
+ // Native css-transitions based implementation
5373
+ /////////////////////////////////////////////////////////////////////////////
5374
+
5375
+ var native_fx_prefix = ['WebkitT', 'OT', 'MozT', 'MsT', 't'].first(function(name) {
5376
+ return name + 'ransition' in HTML.style;
5377
+ }),
5378
+ native_fx_transition = native_fx_prefix + 'ransition',
5379
+ native_fx_property = native_fx_transition + 'Property',
5380
+ native_fx_duration = native_fx_transition + 'Duration',
5381
+ native_fx_function = native_fx_transition + 'TimingFunction',
5382
+
5383
+ // basic transition algorithm replacements
5384
+ native_fx_functions = {
5385
+ Sin: 'cubic-bezier(.3,0,.6,1)',
5386
+ Cos: 'cubic-bezier(0,.3,.6,0)',
5387
+ Log: 'cubic-bezier(0.6,.3,.8)',
5388
+ Exp: 'cubic-bezier(.6,0,.8,.3)',
5389
+ Lin: 'cubic-bezier(0,0,1,1)'
5390
+ };
5391
+
5392
+ function native_fx_prepare(style) {
5393
+ var options = this.options,
5394
+ element = this.element,
5395
+ element_style = element._.style,
5396
+ old_style = Object.only(
5397
+ element.computedStyles(),
5398
+ native_fx_property,
5399
+ native_fx_duration,
5400
+ native_fx_function
5401
+ );
5402
+
5403
+ function reset_transitions_style() {
5404
+ for (var key in old_style) {
5405
+ element_style[key] = old_style[key];
5406
+ }
5407
+ }
5408
+
5409
+ this
5410
+ .onFinish(reset_transitions_style)
5411
+ .onCancel(function() {
5412
+ element_style[native_fx_property] = 'none';
5413
+ setTimeout(reset_transitions_style, 1);
5414
+ });
5415
+
5416
+ // setting up the transition
5417
+ element_style[native_fx_property] = 'all';
5418
+ element_style[native_fx_duration] = (Fx.Durations[options.duration] || options.duration) +'ms';
5419
+ element_style[native_fx_function] = native_fx_functions[options.transition] || options.transition;
5420
+
5421
+ setTimeout(function() { element.setStyle(style); }, 0);
5422
+ }
5423
+
5424
+ // NOTE: OPERA's css-transitions are a bit jerky so we disable them by default
5425
+ Fx.Options.engine = native_fx_prefix === undefined || Browser_Opera ? 'javascript' : 'native';
5426
+
5427
+ ////////////////////////////////////////////////////////////////////////////
5428
+ // Manual version
5429
+ ////////////////////////////////////////////////////////////////////////////
5430
+
5431
+ Fx.Morph = new Class(Fx, {
5432
+ // protected
5433
+
5434
+ // parepares the effect
5435
+ prepare: function(style) {
5436
+ if (this.options.engine === 'native' && native_fx_prefix !== undefined) {
5437
+ this.render = this.transition = function() {};
5438
+ native_fx_prepare.call(this, style);
5439
+ } else {
5440
+ var keys = style_keys(style),
5441
+ before = clone_style(this.element, keys),
5442
+ after = end_style(this.element, style, keys);
5443
+
5444
+ clean_styles(this.element, before, after);
5445
+
5446
+ this.before = parse_style(before);
5447
+ this.after = parse_style(after);
5448
+ }
5449
+ },
5450
+
5451
+ render: function(delta) {
5452
+ var before, after, value, style = this.element._.style, key, i, l;
5453
+ for (key in this.after) {
5454
+ before = this.before[key];
5455
+ after = this.after[key];
5456
+
5457
+ for (i=0, l = after.length; i < l; i++) {
5458
+ value = before[i] + (after[i] - before[i]) * delta;
5459
+ if (after.r) {
5460
+ value = Math.round(value);
5461
+ }
5462
+ after.t[i*2 + 1] = value;
5463
+ }
5464
+
5465
+ style[key] = after.t.join('');
5466
+ }
5467
+ }
5468
+ });
5469
+
5091
5470
  // a list of common style names to compact the code a bit
5092
5471
  var directions = $w('Top Left Right Bottom');
5093
5472
 
@@ -5098,6 +5477,32 @@ function add_variants(keys, key, variants) {
5098
5477
  }
5099
5478
  }
5100
5479
 
5480
+ // creates an appropriate style-keys list out of the user styles
5481
+ function style_keys(style) {
5482
+ var keys = [], border_types = ['Style', 'Color', 'Width'], key, i, j;
5483
+
5484
+ for (key in style) {
5485
+ if (key.startsWith('border')) {
5486
+ for (i=0; i < 3; i++) {
5487
+ for (j=0; j < 4; j++) {
5488
+ keys.push('border' + directions[j] + border_types[i]);
5489
+ }
5490
+ }
5491
+ } else if (key === 'margin' || key === 'padding') {
5492
+ add_variants(keys, key, directions);
5493
+ } else if (key.startsWith('background')) {
5494
+ add_variants(keys, 'background', ['Color', 'Position', 'PositionX', 'PositionY']);
5495
+ } else if (key === 'opacity' && Browser_IE) {
5496
+ keys.push('filter');
5497
+ } else {
5498
+ keys.push(key);
5499
+ }
5500
+ }
5501
+
5502
+ return keys;
5503
+ }
5504
+
5505
+
5101
5506
  // checks if the color is transparent
5102
5507
  function is_transparent(color) {
5103
5508
  return color === 'transparent' || color === 'rgba(0, 0, 0, 0)';
@@ -5106,10 +5511,10 @@ function is_transparent(color) {
5106
5511
  // adjusts the border-styles
5107
5512
  function check_border_styles(element, before, after) {
5108
5513
  for (var i=0; i < 4; i++) {
5109
- var direction = directions[i],
5110
- bd_style = 'border' + direction + 'Style',
5111
- bd_width = 'border' + direction + 'Width',
5112
- bd_color = 'border' + direction + 'Color';
5514
+ var
5515
+ bd_style = 'border' + directions[i] + 'Style',
5516
+ bd_width = 'border' + directions[i] + 'Width',
5517
+ bd_color = 'border' + directions[i] + 'Color';
5113
5518
 
5114
5519
  if (bd_style in before && before[bd_style] != after[bd_style]) {
5115
5520
  var style = element._.style;
@@ -5149,7 +5554,7 @@ function parse_style(values) {
5149
5554
 
5150
5555
  // cleans up and optimizies the styles
5151
5556
  function clean_styles(element, before, after) {
5152
- var remove = [], key;
5557
+ var key;
5153
5558
 
5154
5559
  for (key in after) {
5155
5560
  // checking the height/width options
@@ -5169,8 +5574,8 @@ function clean_styles(element, before, after) {
5169
5574
  // cleaing up the list
5170
5575
  for (key in after) {
5171
5576
  // proprocessing colors
5172
- if (after[key] !== before[key] && !remove.include(key) && /color/i.test(key)) {
5173
- if (Browser.Opera) {
5577
+ if (after[key] !== before[key] && /color/i.test(key)) {
5578
+ if (Browser_Opera) {
5174
5579
  after[key] = after[key].replace(/"/g, '');
5175
5580
  before[key] = before[key].replace(/"/g, '');
5176
5581
  }
@@ -5187,131 +5592,54 @@ function clean_styles(element, before, after) {
5187
5592
  }
5188
5593
 
5189
5594
  // removing unprocessable keys
5190
- if (after[key] === before[key] || remove.include(key) || !/\d/.test(before[key]) || !/\d/.test(after[key])) {
5595
+ if (after[key] === before[key] || !/\d/.test(before[key]) || !/\d/.test(after[key])) {
5191
5596
  delete(after[key]);
5192
5597
  delete(before[key]);
5193
5598
  }
5194
5599
  }
5195
5600
  }
5196
5601
 
5197
- /**
5198
- * creates an appropriate style-keys list out of the user styles
5199
- *
5200
- * @param Object the style hash
5201
- * @return Array of clean style keys list
5202
- */
5203
- function style_keys(style) {
5204
- var keys = [], border_types = ['Style', 'Color', 'Width'], key, i, j;
5205
-
5206
- for (key in style) {
5207
- if (key.startsWith('border')) {
5208
- for (i=0; i < border_types.length; i++) {
5209
- for (j=0; j < directions.length; j++) {
5210
- keys.push('border' + directions[j] + border_types[i]);
5211
- }
5212
- }
5213
- } else if (key == 'margin' || key == 'padding') {
5214
- add_variants(keys, key, directions);
5215
- } else if (key.startsWith('background')) {
5216
- add_variants(keys, 'background', ['Color', 'Position', 'PositionX', 'PositionY']);
5217
- } else if (key == 'opacity' && Browser.IE) {
5218
- keys.push('filter');
5219
- } else {
5220
- keys.push(key);
5221
- }
5222
- }
5223
-
5224
- return keys;
5225
- }
5226
-
5227
- Fx.Morph = new Class(Fx, {
5228
-
5229
- // protected
5602
+ // cloning the element current styles hash
5603
+ function clone_style(element, keys) {
5604
+ var i=0, len = keys.length, style = element.computedStyles(), clean = {}, key;
5230
5605
 
5231
- // parepares the effect
5232
- prepare: function(style) {
5233
- var keys = style_keys(style),
5234
- before = this._cloneStyle(this.element, keys),
5235
- after = this._endStyle(style, keys);
5236
-
5237
- clean_styles(this.element, before, after);
5238
-
5239
- this.before = parse_style(before);
5240
- this.after = parse_style(after);
5241
- },
5242
-
5243
- render: function(delta) {
5244
- var before, after, value, style = this.element._.style, key, i, l;
5245
- for (key in this.after) {
5246
- before = this.before[key];
5247
- after = this.after[key];
5248
-
5249
- for (i=0, l = after.length; i < l; i++) {
5250
- value = before[i] + (after[i] - before[i]) * delta;
5251
- if (after.r) {
5252
- value = Math.round(value);
5253
- }
5254
- after.t[i*2 + 1] = value;
5255
- }
5256
-
5257
- style[key] = after.t.join('');
5606
+ for (; i < len; i++) {
5607
+ key = keys[i];
5608
+ if (key in style) {
5609
+ clean[key] = ''+ style[key];
5258
5610
  }
5259
- },
5260
5611
 
5261
- /**
5262
- * Returns a hash of the end style
5263
- *
5264
- * @param Object style
5265
- * @return Object end style
5266
- */
5267
- _endStyle: function(style, keys) {
5268
- var element = this.element,
5269
- dummy = element.clone()
5270
- .setStyle('position:absolute;z-index:-1;visibility:hidden')
5271
- .setWidth(element.size().x)
5272
- .setStyle(style);
5273
-
5274
- if (element.parent()) {
5275
- element.insert(dummy, 'before');
5612
+ // libwebkit bug fix for in case of languages pack applied
5613
+ if (key === 'opacity') {
5614
+ clean[key] = clean[key].replace(',', '.');
5276
5615
  }
5616
+ }
5277
5617
 
5278
- var after = this._cloneStyle(dummy, keys);
5279
-
5280
- dummy.remove();
5281
-
5282
- return after;
5283
- },
5284
-
5285
- /**
5286
- * Fast styles cloning
5287
- *
5288
- * @param Element element
5289
- * @param Array style keys
5290
- * @return Hash of styles
5291
- */
5292
- _cloneStyle: function(element, keys) {
5293
- for (var i=0, len = keys.length, style = element.computedStyles(), clean = {}, key; i < len; i++) {
5294
- key = keys[i];
5295
- if (key in style) {
5296
- clean[key] = ''+ style[key];
5297
- }
5618
+ return clean;
5619
+ }
5298
5620
 
5299
- // libwebkit bug fix for in case of languages pack applied
5300
- if (key === 'opacity') {
5301
- clean[key] = clean[key].replace(',', '.');
5302
- }
5303
- }
5621
+ // calculating the end styles hash
5622
+ function end_style(element, style, keys) {
5623
+ var dummy = element.clone()
5624
+ .setStyle('position:absolute;z-index:-1;visibility:hidden')
5625
+ .setWidth(element.size().x)
5626
+ .setStyle(style), after;
5304
5627
 
5305
- return clean;
5628
+ if (element.parent()) {
5629
+ element.insert(dummy, 'before');
5306
5630
  }
5307
- });
5308
5631
 
5632
+ after = clone_style(dummy, keys);
5633
+ dummy.remove();
5634
+
5635
+ return after;
5636
+ }
5309
5637
 
5310
5638
 
5311
5639
  /**
5312
5640
  * the elements hightlighting effect
5313
5641
  *
5314
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
5642
+ * Copyright (C) 2008-2011 Nikolay V. Nemshilov
5315
5643
  */
5316
5644
  Fx.Highlight = new Class(Fx.Morph, {
5317
5645
  extend: {
@@ -5331,19 +5659,22 @@ Fx.Highlight = new Class(Fx.Morph, {
5331
5659
  * @return self
5332
5660
  */
5333
5661
  prepare: function(start, end) {
5334
- var element = this.element, style = element._.style, end_color = end || element.getStyle('backgroundColor');
5662
+ var element = this.element,
5663
+ element_style = element._.style,
5664
+ style_name = 'backgroundColor',
5665
+ end_color = end || element.getStyle(style_name);
5335
5666
 
5336
5667
  if (is_transparent(end_color)) {
5337
- this.onFinish(function() { style.backgroundColor = 'transparent'; });
5668
+ this.onFinish(function() { element_style[style_name] = 'transparent'; });
5338
5669
 
5339
5670
  // trying to find the end color
5340
- end_color = [element].concat(element.parents()).map(function(node) {
5341
- var bg = node.getStyle('backgroundColor');
5342
- return (bg && !is_transparent(bg)) ? bg : null;
5343
- }).compact().first() || '#FFF';
5671
+ end_color = [element].concat(element.parents())
5672
+ .map('getStyle', style_name)
5673
+ .reject(is_transparent)
5674
+ .compact().first() || '#FFF';
5344
5675
  }
5345
5676
 
5346
- style.backgroundColor = (start || this.options.color);
5677
+ element_style[style_name] = (start || this.options.color);
5347
5678
 
5348
5679
  return this.$super({backgroundColor: end_color});
5349
5680
  }
@@ -5353,7 +5684,7 @@ Fx.Highlight = new Class(Fx.Morph, {
5353
5684
  /**
5354
5685
  * this is a superclass for the bidirectional effects
5355
5686
  *
5356
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
5687
+ * Copyright (C) 2008-2011 Nikolay V. Nemshilov
5357
5688
  */
5358
5689
  Fx.Twin = new Class(Fx.Morph, {
5359
5690
 
@@ -5363,8 +5694,9 @@ Fx.Twin = new Class(Fx.Morph, {
5363
5694
  * @return Fx self
5364
5695
  */
5365
5696
  finish: function() {
5366
- if (this.how == 'out') {
5367
- old_hide.call(this.element);
5697
+ if (this.how === 'out') {
5698
+ // calling 'prototype' to prevent circular calls from subclasses
5699
+ Element.prototype.hide.call(this.element);
5368
5700
  }
5369
5701
 
5370
5702
  return this.$super();
@@ -5380,7 +5712,7 @@ Fx.Twin = new Class(Fx.Morph, {
5380
5712
  setHow: function(how) {
5381
5713
  this.how = how || 'toggle';
5382
5714
 
5383
- if (this.how == 'toggle') {
5715
+ if (this.how === 'toggle') {
5384
5716
  this.how = this.element.visible() ? 'out' : 'in';
5385
5717
  }
5386
5718
  }
@@ -5391,7 +5723,7 @@ Fx.Twin = new Class(Fx.Morph, {
5391
5723
  /**
5392
5724
  * the slide effects wrapper
5393
5725
  *
5394
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
5726
+ * Copyright (C) 2008-2011 Nikolay V. Nemshilov
5395
5727
  */
5396
5728
  Fx.Slide = new Class(Fx.Twin, {
5397
5729
  extend: {
@@ -5404,111 +5736,145 @@ Fx.Slide = new Class(Fx.Twin, {
5404
5736
  prepare: function(how) {
5405
5737
  this.setHow(how);
5406
5738
 
5407
- var element = old_show.call(this.element);
5408
- this.size = element.size();
5409
-
5410
- this.styles = {};
5411
- $w('overflow height width marginTop marginLeft').each(function(key) {
5412
- this.styles[key] = element._.style[key];
5413
- }, this);
5414
-
5415
- element._.style.overflow = 'hidden';
5416
- this.onFinish('_getBack').onCancel('_getBack');
5417
-
5418
- return this.$super(this._getStyle(this.options.direction));
5419
- },
5420
-
5421
- _getBack: function() {
5422
- this.element.setStyle(this.styles);
5423
- },
5424
-
5425
- // calculates the final style
5426
- _getStyle: function(direction) {
5427
- var style = {}, size = this.size,
5428
- margin_left = this.styles.marginLeft.toFloat() || 0,
5429
- margin_top = this.styles.marginTop.toFloat() || 0;
5430
-
5431
- if (this.how == 'out') {
5432
- style[['top', 'bottom'].include(direction) ? 'height' : 'width'] = '0px';
5433
-
5434
- if (direction == 'right') {
5435
- style.marginLeft = margin_left + size.x+'px';
5436
- } else if (direction == 'bottom') {
5437
- style.marginTop = margin_top + size.y +'px';
5739
+ // calling 'prototype' to prevent circular calls from subclasses
5740
+ var element = Element.prototype.show.call(this.element),
5741
+ element_style = element._.style,
5742
+ old_styles = Object.only(
5743
+ element_style,
5744
+ 'overflow', 'width', 'height',
5745
+ 'marginTop', 'marginLeft'
5746
+ );
5747
+
5748
+ function restore_styles() {
5749
+ for (var key in old_styles) {
5750
+ element_style[key] = old_styles[key];
5438
5751
  }
5752
+ }
5439
5753
 
5440
- } else if (this.how == 'in') {
5441
- var element_style = this.element._.style;
5754
+ this.onFinish(restore_styles).onCancel(restore_styles);
5442
5755
 
5443
- if (['top', 'bottom'].include(direction)) {
5444
- style.height = size.y + 'px';
5445
- element_style.height = '0px';
5446
- } else {
5447
- style.width = size.x + 'px';
5448
- element_style.width = '0px';
5449
- }
5756
+ element_style.overflow = 'hidden';
5450
5757
 
5451
- if (direction == 'right') {
5452
- style.marginLeft = margin_left + 'px';
5453
- element_style.marginLeft = margin_left + size.x + 'px';
5454
- } else if (direction == 'bottom') {
5455
- style.marginTop = margin_top + 'px';
5456
- element_style.marginTop = margin_top + size.y + 'px';
5457
- }
5758
+ return this.$super(fx_slide_prepare_styles(
5759
+ element_style,
5760
+ element.size(),
5761
+ this.options.direction,
5762
+ this.how
5763
+ ));
5764
+ }
5765
+ });
5766
+
5767
+ function fx_slide_prepare_styles(element_style, size, direction, how) {
5768
+ var style = {},
5769
+ margin_left = element_style.marginLeft.toFloat() || 0,
5770
+ margin_top = element_style.marginTop.toFloat() || 0,
5771
+ to_right = direction === 'right',
5772
+ to_bottom = direction === 'bottom',
5773
+ vertical = direction === 'top' || to_bottom;
5774
+
5775
+ if (how === 'out') {
5776
+ style[vertical ? 'height' : 'width'] = '0px';
5777
+
5778
+ if (to_right) {
5779
+ style.marginLeft = margin_left + size.x+'px';
5780
+ } else if (to_bottom) {
5781
+ style.marginTop = margin_top + size.y +'px';
5782
+ }
5783
+ } else {
5784
+ if (vertical) {
5785
+ style.height = size.y + 'px';
5786
+ element_style.height = '0px';
5787
+ } else {
5788
+ style.width = size.x + 'px';
5789
+ element_style.width = '0px';
5458
5790
  }
5459
5791
 
5460
- return style;
5792
+ if (to_right) {
5793
+ style.marginLeft = margin_left + 'px';
5794
+ element_style.marginLeft = margin_left + size.x + 'px';
5795
+ } else if (to_bottom) {
5796
+ style.marginTop = margin_top + 'px';
5797
+ element_style.marginTop = margin_top + size.y + 'px';
5798
+ }
5461
5799
  }
5462
5800
 
5463
- });
5801
+ return style;
5802
+ }
5464
5803
 
5465
5804
 
5466
5805
  /**
5467
5806
  * The opacity effects wrapper
5468
5807
  *
5469
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
5808
+ * Copyright (C) 2008-2011 Nikolay V. Nemshilov
5470
5809
  */
5471
5810
  Fx.Fade = new Class(Fx.Twin, {
5472
5811
  prepare: function(how) {
5473
5812
  this.setHow(how);
5474
5813
 
5475
- if (this.how == 'in') {
5476
- old_show.call(this.element.setStyle({opacity: 0}));
5814
+ if (this.how === 'in') {
5815
+ // calling 'prototype' to prevent circular calls from subclasses
5816
+ Element.prototype.show.call(this.element.setStyle({opacity: 0}));
5477
5817
  }
5478
5818
 
5479
- return this.$super({opacity: isNumber(how) ? how : this.how == 'in' ? 1 : 0});
5819
+ return this.$super({opacity: this.how === 'in' ? 1 : 0});
5480
5820
  }
5481
5821
  });
5482
5822
 
5483
5823
 
5824
+ /**
5825
+ * An abstract attributes based Fx
5826
+ *
5827
+ * Copyright (C) 2010 Nikolay Nemshilov
5828
+ */
5829
+ Fx.Attr = new Class(Fx, {
5830
+
5831
+ prepare: function(attrs) {
5832
+ this.before = {};
5833
+ this.after = attrs;
5834
+ var key, element = this.element._;
5835
+
5836
+ for (key in attrs) {
5837
+ this.before[key] = element[key];
5838
+ }
5839
+ },
5840
+
5841
+ render: function(delta) {
5842
+ var key, element = this.element._, before = this.before;
5843
+ for (key in before) {
5844
+ element[key] = before[key] + (this.after[key] - before[key]) * delta;
5845
+ }
5846
+ }
5847
+
5848
+ });
5849
+
5484
5850
  /**
5485
5851
  * A smooth scrolling visual effect
5486
5852
  *
5487
- * Copyright (C) 2009-2010 Nikolay V. Nemshilov
5853
+ * Copyright (C) 2009-2011 Nikolay Nemshilov
5488
5854
  */
5489
- Fx.Scroll = new Class(Fx, {
5855
+ Fx.Scroll = new Class(Fx.Attr, {
5490
5856
 
5491
5857
  initialize: function(element, options) {
5492
5858
  element = $(element);
5493
5859
  // swapping the actual scrollable when it's the window
5494
- this.$super(element instanceof Window ? element._.document[Browser.WebKit ? 'body' : 'documentElement'] : element, options);
5860
+ this.$super(
5861
+ element instanceof Window ?
5862
+ element._.document[
5863
+ Browser.WebKit ? 'body' : 'documentElement'
5864
+ ] : element,
5865
+ options
5866
+ );
5495
5867
  },
5496
5868
 
5497
5869
  prepare: function(value) {
5498
- var before = this.before = {}, element = this.element._;
5499
-
5500
- this.after = value;
5870
+ var attrs = {};
5501
5871
 
5502
- if ('x' in value) { before.x = element.scrollLeft; }
5503
- if ('y' in value) { before.y = element.scrollTop; }
5504
- },
5872
+ if ('x' in value) { attrs.scrollLeft = value.x; }
5873
+ if ('y' in value) { attrs.scrollTop = value.y; }
5505
5874
 
5506
- render: function(delta) {
5507
- var before = this.before, key;
5508
- for (key in before) {
5509
- this.element._['scroll' + (key == 'x' ? 'Left' : 'Top')] = before[key] + (this.after[key] - before[key]) * delta;
5510
- }
5875
+ this.$super(attrs);
5511
5876
  }
5877
+
5512
5878
  });
5513
5879
 
5514
5880
 
@@ -5588,8 +5954,10 @@ var Cookie = RightJS.Cookie = new Class({
5588
5954
  * @return mixed saved value or null if nothing found
5589
5955
  */
5590
5956
  get: function() {
5591
- var value = this.options.document.cookie.match('(?:^|;)\\s*' + RegExp.escape(this.name) + '=([^;]*)');
5592
- return (value) ? decodeURIComponent(value[1]) : null;
5957
+ var value = this.options.document.cookie.match(
5958
+ '(?:^|;)\\s*' + RegExp.escape(this.name) + '=([^;]*)'
5959
+ );
5960
+ return value ? decodeURIComponent(value[1]) : null;
5593
5961
  },
5594
5962
 
5595
5963
  /**
@@ -5618,11 +5986,16 @@ return RightJS;
5618
5986
  * finds the core inclusion tag and uses it's src attribute
5619
5987
  * to dynamically load the olds patch
5620
5988
  *
5621
- * Copyright (C) 2009-2010 Nikolay V. Nemshilov
5989
+ * Copyright (C) 2009-2011 Nikolay V. Nemshilov
5622
5990
  */
5623
- if (!document.querySelector) {
5624
- document.write('<script src="' +
5625
- RightJS.$A(document.getElementsByTagName('script')).last()
5626
- .src.replace(/(^|\/)(right)([^\/]+)$/, '$1$2-olds$3') +
5627
- '"></script>');
5991
+ if (RightJS.Browser.OLD) {
5992
+ (function(d) {
5993
+ var script = d.createElement('script'),
5994
+ scripts = d.getElementsByTagName('script'),
5995
+ rjs_spt = scripts[scripts.length - 1];
5996
+
5997
+ script.src = rjs_spt.src.replace(/(^|\/)(right)([^\/]+)$/, '$1$2-olds$3');
5998
+
5999
+ rjs_spt.parentNode.appendChild(script);
6000
+ })(document);
5628
6001
  }