right-rails 1.0.10 → 1.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  }