puffer 0.0.23 → 0.0.24

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. data/.rspec +1 -0
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +55 -53
  4. data/VERSION +1 -1
  5. data/app/assets/javascripts/puffer/application.js +6 -3
  6. data/app/assets/javascripts/puffer/paginator.js +223 -0
  7. data/app/assets/javascripts/puffer/puffer.js +12 -0
  8. data/app/assets/javascripts/puffer/rails.js +1 -0
  9. data/app/assets/javascripts/puffer/{right-autocompleter.js → right-autocompleter-src.js} +45 -41
  10. data/app/assets/javascripts/puffer/{right-calendar.js → right-calendar-src.js} +53 -50
  11. data/app/assets/javascripts/puffer/right-dialog-src.js +768 -0
  12. data/app/assets/javascripts/puffer/right-slider-src.js +507 -0
  13. data/app/assets/javascripts/puffer/{right.js → right-src.js} +1000 -230
  14. data/app/assets/stylesheets/puffer/application.css +2 -0
  15. data/app/assets/stylesheets/puffer/paginator.css +33 -0
  16. data/app/assets/stylesheets/puffer/right.css +4 -0
  17. data/app/components/base/form.html.erb +15 -0
  18. data/app/components/base_component.rb +15 -0
  19. data/app/components/boolean/form.html.erb +3 -0
  20. data/app/components/boolean/index.html.erb +3 -0
  21. data/app/components/boolean_component.rb +13 -0
  22. data/app/components/date_time/form.html.erb +5 -0
  23. data/app/components/date_time_component.rb +12 -0
  24. data/app/components/file/form.html.erb +5 -0
  25. data/app/components/file_component.rb +3 -0
  26. data/app/components/hidden/form.html.erb +1 -0
  27. data/app/components/hidden_component.rb +3 -0
  28. data/app/components/password/form.html.erb +5 -0
  29. data/app/components/password_component.rb +7 -0
  30. data/app/components/references_many/form.html.erb +1 -0
  31. data/app/components/references_many_component.rb +7 -0
  32. data/app/components/references_one/choose.html.erb +9 -0
  33. data/app/components/references_one/form.html.erb +28 -0
  34. data/app/components/references_one_component.rb +12 -0
  35. data/app/components/select/form.html.erb +5 -0
  36. data/app/components/select_component.rb +15 -0
  37. data/app/components/string/form.html.erb +5 -0
  38. data/app/components/string_component.rb +3 -0
  39. data/app/components/text/form.html.erb +5 -0
  40. data/app/components/text_component.rb +3 -0
  41. data/app/controllers/puffer/base.rb +4 -0
  42. data/app/views/puffer/base/_form.html.erb +0 -1
  43. data/app/views/puffer/base/_table.html.erb +25 -0
  44. data/app/views/puffer/base/index.html.erb +14 -28
  45. data/app/views/puffer/tree_base/_record.html.erb +1 -1
  46. data/lib/generators/puffer/component/USAGE +12 -0
  47. data/lib/generators/puffer/component/component_generator.rb +19 -0
  48. data/lib/generators/puffer/component/templates/component.rb +15 -0
  49. data/lib/generators/puffer/component/templates/component_spec.rb +19 -0
  50. data/lib/puffer/component.rb +141 -0
  51. data/lib/puffer/controller/dsl.rb +25 -12
  52. data/lib/puffer/engine.rb +5 -0
  53. data/lib/puffer/extensions/controller.rb +11 -9
  54. data/lib/puffer/extensions/form.rb +2 -1
  55. data/lib/puffer/extensions/mapper.rb +2 -0
  56. data/lib/puffer/field.rb +30 -19
  57. data/lib/puffer/field_set.rb +17 -2
  58. data/lib/puffer.rb +25 -8
  59. data/puffer.gemspec +59 -28
  60. data/spec/app/components/base_component_spec.rb +19 -0
  61. data/spec/app/components/boolean_component_spec.rb +36 -0
  62. data/spec/app/components/date_time_component_spec.rb +26 -0
  63. data/spec/app/components/file_component_spec.rb +25 -0
  64. data/spec/app/components/hidden_component_spec.rb +24 -0
  65. data/spec/app/components/password_component_spec.rb +37 -0
  66. data/spec/app/components/references_many_component_spec.rb +19 -0
  67. data/spec/app/components/references_one_component_spec.rb +19 -0
  68. data/spec/app/components/select_component_spec.rb +30 -0
  69. data/spec/app/components/string_component_spec.rb +25 -0
  70. data/spec/app/components/text_component_spec.rb +25 -0
  71. data/spec/dummy/app/controllers/admin/categories_controller.rb +3 -3
  72. data/spec/dummy/app/controllers/admin/posts_controller.rb +3 -0
  73. data/spec/dummy/app/controllers/{puffer → admin}/sessions_controller.rb +1 -1
  74. data/spec/dummy/app/controllers/admin/users_controller.rb +2 -2
  75. data/spec/dummy/app/models/post.rb +4 -0
  76. data/spec/dummy/db/migrate/20100930132656_create_posts.rb +2 -0
  77. data/spec/dummy/db/migrate/20100930132726_create_categories.rb +1 -0
  78. data/spec/dummy/db/schema.rb +3 -0
  79. data/spec/dummy/db/seeds.rb +6 -1
  80. data/spec/fabricators/categories_fabricator.rb +1 -0
  81. data/spec/fabricators/posts_fabricator.rb +1 -0
  82. data/spec/lib/component_spec.rb +7 -0
  83. data/spec/lib/fields_spec.rb +0 -4
  84. metadata +85 -56
  85. data/app/views/puffer/base/associated/_many.html.erb +0 -56
  86. data/app/views/puffer/base/associated/many.rjs +0 -1
  87. data/app/views/puffer/base/associated/one.js.erb +0 -13
  88. data/app/views/puffer/base/association/_many.html.erb +0 -7
  89. data/lib/puffer/controller/generated.rb +0 -65
  90. data/lib/puffer/customs.rb +0 -64
  91. data/lib/puffer/inputs/association.rb +0 -38
  92. data/lib/puffer/inputs/base.rb +0 -51
  93. data/lib/puffer/inputs/boolean.rb +0 -19
  94. data/lib/puffer/inputs/collection_association.rb +0 -11
  95. data/lib/puffer/inputs/date_time.rb +0 -16
  96. data/lib/puffer/inputs/file.rb +0 -11
  97. data/lib/puffer/inputs/hidden.rb +0 -15
  98. data/lib/puffer/inputs/password.rb +0 -11
  99. data/lib/puffer/inputs/select.rb +0 -19
  100. data/lib/puffer/inputs/text.rb +0 -11
@@ -1,27 +1,27 @@
1
1
  /**
2
- * RightJS, http://rightjs.org
3
- * Released under the MIT license
2
+ * RightJS v2.2.3 - 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
- var RightJS = (function(window, document, Object, Array, String, Function, Number, Math) {
12
+ var RightJS = (function(window, document, Object, Array, String, Function, Number, Math, undefined) {
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.2.0";
24
- RightJS.modules =["core", "dom", "form", "events", "xhr", "fx", "cookie"];
23
+ RightJS.version = "2.2.3";
24
+ RightJS.modules =["core", "dom", "form", "events", "xhr", "fx", "cookie", "olds"];
25
25
 
26
26
 
27
27
 
@@ -187,7 +187,7 @@ isArray = RightJS.isArray = function(value) {
187
187
  * @return boolean check result
188
188
  */
189
189
  isElement = RightJS.isElement = function(value) {
190
- return !!(value && value.tagName);
190
+ return value != null && value.nodeType === 1;
191
191
  },
192
192
 
193
193
  /** !#server
@@ -197,7 +197,7 @@ isElement = RightJS.isElement = function(value) {
197
197
  * @return boolean check result
198
198
  */
199
199
  isNode = RightJS.isNode = function(value) {
200
- return !!(value && value.nodeType);
200
+ return value != null && value.nodeType != null;
201
201
  },
202
202
 
203
203
  /** !#server
@@ -248,23 +248,6 @@ $w = RightJS.$w = function(string) {
248
248
  return string.trim().split(/\s+/);
249
249
  },
250
250
 
251
- /**
252
- * converts any iterables into an array
253
- *
254
- * @param Object iterable
255
- * @return Array list
256
- */
257
- $A = RightJS.$A = function(it) {
258
- try {
259
- return slice.call(it);
260
- } catch(e) {
261
- for (var a=[], i=0, length = it.length; i < length; i++) {
262
- a[i] = it[i];
263
- }
264
- return a;
265
- }
266
- },
267
-
268
251
  /**
269
252
  * generates an unique id for an object
270
253
  *
@@ -273,42 +256,73 @@ $A = RightJS.$A = function(it) {
273
256
  */
274
257
  $uid = RightJS.$uid = function(item) {
275
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);
276
269
  };
277
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
+
278
288
  /** !#server
279
289
  * Internet Explorer needs some additional mumbo-jumbo in here
280
290
  */
281
291
  if (isHash(HTML)) {
282
292
  isHash = RightJS.isHash = function(value) {
283
293
  return to_s.call(value) === '[object Object]' &&
284
- value !== null && typeof(value) !== 'undefined' &&
285
- typeof(value.hasOwnProperty) !== 'undefined';
294
+ value != null && value.hasOwnProperty != null;
286
295
  };
287
296
  }
297
+
298
+
288
299
  /**
289
300
  * Generating methods for native units extending
290
301
  */
291
- var i=0, natives = 'Array Function Number String Date RegExp'.split(' '),
292
- include_native = function() {
293
- for (var i=0; i < arguments.length; i++) {
294
- if (isHash(arguments[i])) {
295
- $ext(this.prototype, arguments[i]);
296
- $ext(this.Methods, arguments[i]);
297
- }
298
- }
299
- };
300
-
301
- for (; i < natives.length; i++) {
302
- $ext(RightJS[natives[i]] = window[natives[i]], {
302
+ // adds a standard '.include' method to the native unit
303
+ function extend_native(klass) {
304
+ return $ext(klass, {
303
305
  Methods: {},
304
- include: include_native
306
+ include: function() {
307
+ for (var i=0, l = arguments.length; i < l; i++) {
308
+ if (isHash(arguments[i])) {
309
+ $ext(klass.prototype, arguments[i]);
310
+ $ext(klass.Methods, arguments[i]);
311
+ }
312
+ }
313
+ }
305
314
  });
306
315
  }
307
316
 
317
+ for (var i=0, natives = 'Array Function Number String Date RegExp'.split(' '); i < natives.length; i++) {
318
+ RightJS[natives[i]] = extend_native(new Function('return '+ natives[i])());
319
+ }
320
+
308
321
  // referring those two as well
309
322
  RightJS.Object = Object;
310
323
  RightJS.Math = Math;
311
324
 
325
+
312
326
  /**
313
327
  * Checks if the data is an array and if not,
314
328
  * then makes an array out of it
@@ -458,7 +472,7 @@ $ext(Object, {
458
472
  */
459
473
  merge: function() {
460
474
  var object = {}, i=0, args=arguments, key;
461
- for (; i < args.length; i++) {
475
+ for (l = args.length; i < l; i++) {
462
476
  if (isHash(args[i])) {
463
477
  for (key in args[i]) {
464
478
  object[key] = isHash(args[i][key]) && !(args[i][key] instanceof Class) ?
@@ -479,7 +493,7 @@ $ext(Object, {
479
493
  var tokens = [], key, value, encode = encodeURIComponent;
480
494
  for (key in object) {
481
495
  value = ensure_array(object[key]);
482
- for (var i=0; i < value.length; i++) {
496
+ for (var i=0, l = value.length; i < l; i++) {
483
497
  tokens.push(encode(key) +'='+ encode(value[i]));
484
498
  }
485
499
  }
@@ -538,13 +552,13 @@ var original_sort = A_proto.sort,
538
552
 
539
553
  // JavaScript 1.6 methods recatching up or faking
540
554
  for_each = A_proto.forEach || function(callback, scope) {
541
- for (var i=0; i < this.length; i++) {
555
+ for (var i=0, l=this.length; i < l; i++) {
542
556
  callback.call(scope, this[i], i, this);
543
557
  }
544
558
  },
545
559
 
546
560
  filter = A_proto.filter || function(callback, scope) {
547
- for (var result=[], j=0, i=0; i < this.length; i++) {
561
+ for (var result=[], j=0, i=0, l=this.length; i < l; i++) {
548
562
  if (callback.call(scope, this[i], i, this)) {
549
563
  result[j++] = this[i];
550
564
  }
@@ -553,7 +567,7 @@ filter = A_proto.filter || function(callback, scope) {
553
567
  },
554
568
 
555
569
  reject = function(callback, scope) {
556
- for (var result=[], j=0, i=0; i < this.length; i++) {
570
+ for (var result=[], j=0, i=0, l=this.length; i < l; i++) {
557
571
  if (!callback.call(scope, this[i], i, this)) {
558
572
  result[j++] = this[i];
559
573
  }
@@ -562,14 +576,14 @@ reject = function(callback, scope) {
562
576
  },
563
577
 
564
578
  map = A_proto.map || function(callback, scope) {
565
- for (var result=[], i=0; i < this.length; i++) {
579
+ for (var result=[], i=0, l=this.length; i < l; i++) {
566
580
  result[i] = callback.call(scope, this[i], i, this);
567
581
  }
568
582
  return result;
569
583
  },
570
584
 
571
585
  some = A_proto.some || function(callback, scope) {
572
- for (var i=0; i < this.length; i++) {
586
+ for (var i=0, l=this.length; i < l; i++) {
573
587
  if (callback.call(scope, this[i], i, this)) {
574
588
  return true;
575
589
  }
@@ -578,7 +592,7 @@ some = A_proto.some || function(callback, scope) {
578
592
  },
579
593
 
580
594
  every = A_proto.every || function(callback, scope) {
581
- for (var i=0; i < this.length; i++) {
595
+ for (var i=0, l=this.length; i < l; i++) {
582
596
  if (!callback.call(scope, this[i], i, this)) {
583
597
  return false;
584
598
  }
@@ -587,7 +601,7 @@ every = A_proto.every || function(callback, scope) {
587
601
  },
588
602
 
589
603
  first = function(callback, scope) {
590
- for (var i=0; i < this.length; i++) {
604
+ for (var i=0, l=this.length; i < l; i++) {
591
605
  if (callback.call(scope, this[i], i, this)) {
592
606
  return this[i];
593
607
  }
@@ -629,7 +643,6 @@ function guess_callback(argsi, array) {
629
643
 
630
644
  // defining the manual break errors class
631
645
  function Break() {}
632
- Break.prototype = Error.prototype;
633
646
 
634
647
  // calls the given method with preprocessing the arguments
635
648
  function call_method(func, scope, args) {
@@ -660,7 +673,7 @@ Array.include({
660
673
  * @return Integer index or -1 if not found
661
674
  */
662
675
  indexOf: A_proto.indexOf || function(value, from) {
663
- for (var i=(from<0) ? Math.max(0, this.length+from) : from || 0; i < this.length; i++) {
676
+ for (var i=(from<0) ? Math.max(0, this.length+from) : from || 0, l=this.length; i < l; i++) {
664
677
  if (this[i] === value) {
665
678
  return i;
666
679
  }
@@ -980,7 +993,7 @@ Array.include({
980
993
  * @return Number a summ of values on the list
981
994
  */
982
995
  sum: function() {
983
- for(var sum=0, i=0; i<this.length; sum += this[i++]) {}
996
+ for(var sum=0, i=0, l=this.length; i < l; sum += this[i++]) {}
984
997
  return sum;
985
998
  }
986
999
  });
@@ -1015,7 +1028,7 @@ String.include({
1015
1028
  * @return boolean check result
1016
1029
  */
1017
1030
  blank: function() {
1018
- return (/^\s*$/).test(this);
1031
+ return this == false;
1019
1032
  },
1020
1033
 
1021
1034
  /**
@@ -1044,10 +1057,13 @@ String.include({
1044
1057
  * @return String without scripts
1045
1058
  */
1046
1059
  stripScripts: function(option) {
1047
- var scripts = '', text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/img, function(match, source) {
1048
- scripts += source + "\n";
1049
- return '';
1050
- });
1060
+ var scripts = '', text = this.replace(
1061
+ /<script[^>]*>([\s\S]*?)<\/script>/img,
1062
+ function(match, source) {
1063
+ scripts += source + "\n";
1064
+ return '';
1065
+ }
1066
+ );
1051
1067
 
1052
1068
  if (option === true) {
1053
1069
  $eval(scripts);
@@ -1158,7 +1174,8 @@ String.include({
1158
1174
  * @return Float or NaN
1159
1175
  */
1160
1176
  toFloat: function(strict) {
1161
- return parseFloat(strict === true ? this : this.replace(',', '.').replace(/(\d)-(\d)/g, '$1.$2'));
1177
+ return parseFloat(strict === true ? this :
1178
+ this.replace(',', '.').replace(/(\d)-(\d)/, '$1.$2'));
1162
1179
  }
1163
1180
 
1164
1181
  });
@@ -1173,7 +1190,7 @@ String.prototype.include = String.prototype.includes;
1173
1190
  * Some of the functionality inspired by
1174
1191
  * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
1175
1192
  *
1176
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
1193
+ * Copyright (C) 2008-2011 Nikolay V. Nemshilov
1177
1194
  */
1178
1195
  Function.include({
1179
1196
  /**
@@ -1187,7 +1204,10 @@ Function.include({
1187
1204
  bind: function() {
1188
1205
  var args = $A(arguments), scope = args.shift(), func = this;
1189
1206
  return function() {
1190
- return func.apply(scope, (args.length || arguments.length) ? args.concat($A(arguments)) : args);
1207
+ return func.apply(scope,
1208
+ (args.length !== 0 || arguments.length !== 0) ?
1209
+ args.concat($A(arguments)) : args
1210
+ );
1191
1211
  };
1192
1212
  },
1193
1213
 
@@ -1291,7 +1311,7 @@ Function.include({
1291
1311
  * Some methods inspired by
1292
1312
  * - Ruby (http://www.ruby-lang.org) Copyright (C) Yukihiro Matsumoto
1293
1313
  *
1294
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
1314
+ * Copyright (C) 2008-2011 Nikolay V. Nemshilov
1295
1315
  */
1296
1316
  Number.include({
1297
1317
  /**
@@ -1322,6 +1342,33 @@ Number.include({
1322
1342
  return this;
1323
1343
  },
1324
1344
 
1345
+ /**
1346
+ * Maps a list of numbers from current to given
1347
+ * or map a result of calls of the callback on those numbers
1348
+ *
1349
+ * @param {Number} end number
1350
+ * @param {Function} optional callback
1351
+ * @param {Object} optional callback scope
1352
+ * @return {Array} the result list
1353
+ */
1354
+ to: function(number, callback, scope) {
1355
+ var start = this + 0, end = number, result = [], i=start;
1356
+
1357
+ callback = callback || function(i) { return i; };
1358
+
1359
+ if (end > start) {
1360
+ for (; i <= end; i++) {
1361
+ result.push(callback.call(scope, i));
1362
+ }
1363
+ } else {
1364
+ for (; i >= end; i--) {
1365
+ result.push(callback.call(scope, i));
1366
+ }
1367
+ }
1368
+
1369
+ return result;
1370
+ },
1371
+
1325
1372
  abs: function() {
1326
1373
  return Math.abs(this);
1327
1374
  },
@@ -1476,7 +1523,7 @@ Class_Methods = {
1476
1523
  $A(arguments).filter(isHash).each(function(module) {
1477
1524
  Object.each(Class_clean_module(module, false), function(name, method) {
1478
1525
  // searching for the super-method
1479
- for (var super_method, i=0; i < klasses.length; i++) {
1526
+ for (var super_method, i=0, l = klasses.length; i < l; i++) {
1480
1527
  if (name in klasses[i].prototype) {
1481
1528
  super_method = klasses[i].prototype[name];
1482
1529
  break;
@@ -1497,7 +1544,9 @@ Class_Methods = {
1497
1544
  }
1498
1545
  },
1499
1546
 
1500
- Class_module_callback_names = $w('selfExtended self_extended selfIncluded self_included extend include');
1547
+ Class_module_callback_names = $w(
1548
+ 'selfExtended self_extended selfIncluded self_included extend include'
1549
+ );
1501
1550
 
1502
1551
  // hooking up the class-methods to the root class
1503
1552
  $ext(Class, Class_Methods);
@@ -1536,7 +1585,7 @@ function Class_findSet(object, property) {
1536
1585
  candidates = [object, constructor].concat(constructor.ancestors || []),
1537
1586
  i = 0;
1538
1587
 
1539
- for (; i < candidates.length; i++) {
1588
+ for (l = candidates.length; i < l; i++) {
1540
1589
  if (upcased in candidates[i]) {
1541
1590
  return candidates[i][upcased];
1542
1591
  } else if (property in candidates[i]) {
@@ -1581,7 +1630,9 @@ var Options = RightJS.Options = {
1581
1630
  * @return Object current instance
1582
1631
  */
1583
1632
  setOptions: function(opts) {
1584
- var options = this.options = $ext($ext({}, Class_findSet(this, 'Options')), opts), match, key;
1633
+ var options = this.options = $ext($ext({},
1634
+ Object.clone(Class_findSet(this, 'Options'))), opts
1635
+ ), match, key;
1585
1636
 
1586
1637
  // hooking up the observer options
1587
1638
  if (isFunction(this.on)) {
@@ -1744,7 +1795,10 @@ Observer_create = Observer.create = function(object, events) {
1744
1795
  */
1745
1796
  Observer_createShortcuts = Observer.createShortcuts = function(object, names) {
1746
1797
  (names || []).each(function(name) {
1747
- var method_name = 'on'+name.replace(/(^|_|:)([a-z])/g, function(match, pre, chr) { return chr.toUpperCase(); });
1798
+ var method_name = 'on'+name.replace(/(^|_|:)([a-z])/g,
1799
+ function(match, pre, chr) { return chr.toUpperCase(); }
1800
+ );
1801
+
1748
1802
  if (!(method_name in object)) {
1749
1803
  object[method_name] = function() {
1750
1804
  return this.on.apply(this, [name].concat($A(arguments)));
@@ -1836,9 +1890,20 @@ Browser = RightJS.Browser = {
1836
1890
  MobileSafari: /Apple.*Mobile.*Safari/.test(agent),
1837
1891
  Konqueror: agent.include('Konqueror'),
1838
1892
 
1839
- // marker for the browsers which require the olds module
1840
- OLD: !document.querySelector
1841
- };
1893
+ // internal marker for the browsers which require the olds module
1894
+ OLD: !document.querySelector,
1895
+ // internal marker for IE browsers version <= 8
1896
+ IE8L: false
1897
+ },
1898
+
1899
+ IE8_OR_LESS = false,
1900
+ IE_OPACITY = !('opacity' in HTML.style) && ('filter' in HTML.style);
1901
+
1902
+ try {
1903
+ // checking if that an IE version <= 8
1904
+ document.createElement('<input/>');
1905
+ Browser.OLD = Browser.IE8L = IE8_OR_LESS = true;
1906
+ } catch(e) {}
1842
1907
 
1843
1908
 
1844
1909
  /**
@@ -1880,7 +1945,9 @@ function Wrapper_makeKlass() {
1880
1945
  */
1881
1946
  return function(object, options) {
1882
1947
  Class_checkPrebind(this);
1883
- this.initialize(object, options);
1948
+
1949
+ this.initialize.apply(this, arguments); // <- there might be a different number of args in a subclass
1950
+
1884
1951
  var item = this._, uid = UID_KEY in item ? item[UID_KEY] :
1885
1952
  // NOTE we use positive indexes for dom-elements and negative for everything else
1886
1953
  (item[UID_KEY] = (item.nodeType === 1 ? 1 : -1) * UID++);
@@ -1905,7 +1972,7 @@ function Element_Klass(element, options) {
1905
1972
  uid = UID_KEY in raw ? raw[UID_KEY] : (raw[UID_KEY] = UID++);
1906
1973
 
1907
1974
  if (cast !== undefined) {
1908
- inst = new cast(raw);
1975
+ inst = new cast(raw, options);
1909
1976
  if ('$listeners' in this) {
1910
1977
  inst.$listeners = this.$listeners;
1911
1978
  }
@@ -1925,11 +1992,12 @@ Wrapper.Cast = function(unit) {
1925
1992
  * Event's own Klass function, we don't need to check
1926
1993
  * nothing in here, don't need to hit the wrappers cache and so one
1927
1994
  *
1928
- * @param raw dom-event or an event-name
1995
+ * @param raw dom-event or a string event-name
1929
1996
  * @param bounding element or an object with options
1997
+ * @return void
1930
1998
  */
1931
1999
  function Event_Klass(event, bound_element) {
1932
- if (typeof event === 'string') {
2000
+ if (typeof(event) === 'string') {
1933
2001
  event = $ext({type: event}, bound_element);
1934
2002
  this.stopped = event.bubbles === false;
1935
2003
 
@@ -1946,8 +2014,9 @@ function Event_Klass(event, bound_element) {
1946
2014
 
1947
2015
  this.target = wrap(
1948
2016
  // Webkit throws events on textual nodes as well, gotta fix that
1949
- 'target' in event && 'nodeType' in event.target && event.target.nodeType === 3 ?
1950
- event.target.parentNode : event.target);
2017
+ event.target != null && 'nodeType' in event.target && event.target.nodeType === 3 ?
2018
+ event.target.parentNode : event.target
2019
+ );
1951
2020
 
1952
2021
  this.currentTarget = wrap(event.currentTarget);
1953
2022
  this.relatedTarget = wrap(event.relatedTarget);
@@ -1955,9 +2024,9 @@ function Event_Klass(event, bound_element) {
1955
2024
  this.pageX = event.pageX;
1956
2025
  this.pageY = event.pageY;
1957
2026
 
1958
- // Converting IE properties into W3C ones
1959
- if (!('target' in event) && 'srcElement' in event) {
1960
- this.which = event.button == 2 ? 3 : event.button == 4 ? 2 : 1;
2027
+ // making old IE attrs looks like w3c standards
2028
+ if (IE8_OR_LESS && 'srcElement' in event) {
2029
+ this.which = event.button === 2 ? 3 : event.button === 4 ? 2 : 1;
1961
2030
 
1962
2031
  this.target = wrap(event.srcElement) || bound_element;
1963
2032
  this.relatedTarget = this.target._ === event.fromElement ? wrap(event.toElement) : this.target;
@@ -1970,6 +2039,7 @@ function Event_Klass(event, bound_element) {
1970
2039
  }
1971
2040
  }
1972
2041
 
2042
+
1973
2043
  /**
1974
2044
  * Private quick wrapping function, unlike `$`
1975
2045
  * it doesn't search by ID and handle double-wrapps
@@ -1979,7 +2049,7 @@ function Event_Klass(event, bound_element) {
1979
2049
  * @return Wrapper dom-wrapper
1980
2050
  */
1981
2051
  function wrap(object) {
1982
- if (object !== null && object !== undefined) {
2052
+ if (object != null) {
1983
2053
  var wrapper = UID_KEY in object ? Wrappers_Cache[object[UID_KEY]] : undefined;
1984
2054
 
1985
2055
  if (wrapper !== undefined) {
@@ -2127,8 +2197,12 @@ var Event = RightJS.Event = new Class(Wrapper, {
2127
2197
  * @return RightJS.Event this
2128
2198
  */
2129
2199
  stopPropagation: function() {
2130
- try { this._.stopPagination();
2131
- } catch(e) { this._.cancelBubble = true; }
2200
+ if (this._.stopPropagation) {
2201
+ this._.stopPropagation();
2202
+ } else {
2203
+ this._.cancelBubble = true;
2204
+ }
2205
+
2132
2206
  this.stopped = true;
2133
2207
  return this;
2134
2208
  },
@@ -2139,8 +2213,12 @@ var Event = RightJS.Event = new Class(Wrapper, {
2139
2213
  * @return RightJS.Event this
2140
2214
  */
2141
2215
  preventDefault: function() {
2142
- try { this._.preventDefault();
2143
- } catch(e) { this._.returnValue = false; }
2216
+ if (this._.preventDefault) {
2217
+ this._.preventDefault();
2218
+ } else {
2219
+ this._.returnValue = false;
2220
+ }
2221
+
2144
2222
  return this;
2145
2223
  },
2146
2224
 
@@ -2165,15 +2243,20 @@ var Event = RightJS.Event = new Class(Wrapper, {
2165
2243
  /**
2166
2244
  * Returns the event's offset relative to the target element
2167
2245
  *
2168
- * @return Object {x: ..., y: ...}
2246
+ * @return Object {x: ..., y: ...} or null
2169
2247
  */
2170
2248
  offset: function() {
2171
- var element_position = this.target.position();
2249
+ if(this.target instanceof Element) {
2250
+ var element_position = this.target.position();
2172
2251
 
2173
- return {
2174
- x: this.pageX - element_position.x,
2175
- y: this.pageY - element_position.y
2176
- };
2252
+ return {
2253
+ x: this.pageX - element_position.x,
2254
+ y: this.pageY - element_position.y
2255
+ };
2256
+ }
2257
+
2258
+ // triggered outside browser window (at toolbar etc.)
2259
+ return null;
2177
2260
  },
2178
2261
 
2179
2262
  /**
@@ -2203,10 +2286,11 @@ var Event = RightJS.Event = new Class(Wrapper, {
2203
2286
 
2204
2287
  Event_delegation_shortcuts = [];
2205
2288
 
2289
+
2206
2290
  /**
2207
2291
  * The DOM Element unit handling
2208
2292
  *
2209
- * Copyright (C) 2008-2010 Nikolay Nemshilov
2293
+ * Copyright (C) 2008-2011 Nikolay Nemshilov
2210
2294
  */
2211
2295
 
2212
2296
  var Element = RightJS.Element = new Class(Wrapper, {
@@ -2247,10 +2331,7 @@ make_element = function (tag, options) {
2247
2331
  // it doesn't place the 'checked' property correctly, plus there are some issues
2248
2332
  // with clonned SELECT objects, so we are replaceing the elements maker in here
2249
2333
  //
2250
- try {
2251
- document.createElement('<input/>'); // <- works for IE < 9 only
2252
- Browser.OLD = true; // forcing IE8 to load the olds module
2253
-
2334
+ if (IE8_OR_LESS) {
2254
2335
  make_element = function(tag, options) {
2255
2336
  if (tag === 'input' && options !== undefined) {
2256
2337
  tag = '<input name="'+ options.name +
@@ -2261,7 +2342,7 @@ try {
2261
2342
 
2262
2343
  return document.createElement(tag);
2263
2344
  };
2264
- } catch (e) {}
2345
+ }
2265
2346
 
2266
2347
  /**
2267
2348
  * Basic element's constructor
@@ -2312,7 +2393,11 @@ function Element_initialize(inst, element, options) {
2312
2393
 
2313
2394
  Element.include({
2314
2395
  parent: function(css_rule) {
2315
- return css_rule ? this.parents(css_rule)[0] : wrap(this._.parentNode || null); // <- IE6 need that || null
2396
+ var parent = this._.parentNode, parent_type = parent && parent.nodeType;
2397
+
2398
+ return css_rule ? this.parents(css_rule)[0] :
2399
+ (parent_type === 1 || parent_type === 9) ? // <- IE6 sometimes has a fragment node in there
2400
+ wrap(parent) : null;
2316
2401
  },
2317
2402
 
2318
2403
  parents: function(css_rule) {
@@ -2338,11 +2423,13 @@ Element.include({
2338
2423
  },
2339
2424
 
2340
2425
  next: function(css_rule) {
2341
- return this.nextSiblings(css_rule)[0];
2426
+ return !css_rule && this._.nextElementSibling !== undefined ?
2427
+ wrap(this._.nextElementSibling) : this.nextSiblings(css_rule)[0];
2342
2428
  },
2343
2429
 
2344
2430
  prev: function(css_rule) {
2345
- return this.prevSiblings(css_rule)[0];
2431
+ return !css_rule && this._.previousElementSibling !== undefined ?
2432
+ wrap(this._.previousElementSibling) : this.prevSiblings(css_rule)[0];
2346
2433
  },
2347
2434
 
2348
2435
  /**
@@ -2364,7 +2451,7 @@ Element.include({
2364
2451
  * The content might be one of the following data
2365
2452
  *
2366
2453
  * o) an element instance
2367
- * o) a String, which will be converted into content to insert (all the scripts will be parsed out and executed)
2454
+ * o) a String (all the scripts will be parsed out and executed)
2368
2455
  * o) a list of Elements
2369
2456
  * o) a hash like {position: content}
2370
2457
  *
@@ -2374,7 +2461,7 @@ Element.include({
2374
2461
  */
2375
2462
  insert: function(content, position) {
2376
2463
  var scripts = null, element = this._;
2377
- position = (position||'bottom').toLowerCase();
2464
+ position = position === undefined ? 'bottom' : position;
2378
2465
 
2379
2466
  if (typeof(content) !== 'object') {
2380
2467
  scripts = content = (''+content);
@@ -2382,11 +2469,12 @@ Element.include({
2382
2469
  content = content._;
2383
2470
  }
2384
2471
 
2385
- Element_insertions[position](element, content.nodeType ? content :
2386
- Element_createFragment.call(
2387
- (position === 'bottom' || position === 'top') ?
2388
- element : element.parentNode, content
2389
- )
2472
+ Element_insertions[position](element,
2473
+ content.nodeType === undefined ?
2474
+ Element_createFragment(
2475
+ (position === 'bottom' || position === 'top') ?
2476
+ element : element.parentNode, content
2477
+ ) : content
2390
2478
  );
2391
2479
 
2392
2480
  if (scripts !== null) { scripts.evalScripts(); }
@@ -2463,7 +2551,7 @@ Element.include({
2463
2551
  * @return String text content or Element this
2464
2552
  */
2465
2553
  text: function(text) {
2466
- return text === undefined ? this._.innerHTML.stripTags() :
2554
+ return text === undefined ? (this._.textContent || this._.innerText) :
2467
2555
  this.update(this.doc()._.createTextNode(text));
2468
2556
  },
2469
2557
 
@@ -2622,28 +2710,30 @@ $alias(Element_wraps, {
2622
2710
  var fragment = document.createDocumentFragment(),
2623
2711
  tmp_cont = document.createElement('DIV');
2624
2712
 
2625
- function Element_createFragment(content) {
2713
+ function Element_createFragment(context, content) {
2626
2714
  if (typeof(content) === 'string') {
2627
- var tag = this.tagName,
2715
+ var tag = context.tagName,
2628
2716
  tmp = tmp_cont,
2629
- wrap = Element_wraps[tag] || ['', '', 1],
2717
+ wrap = tag in Element_wraps ? Element_wraps[tag] : ['', '', 1],
2630
2718
  depth = wrap[2];
2631
2719
 
2632
2720
  tmp.innerHTML = wrap[0] + '<'+ tag + '>' + content + '</'+ tag + '>' + wrap[1];
2633
2721
 
2634
- while (depth-- > 0) {
2722
+ while (depth-- !== 0) {
2635
2723
  tmp = tmp.firstChild;
2636
2724
  }
2637
2725
 
2638
2726
  content = tmp.childNodes;
2639
- }
2640
2727
 
2641
- for (var i=0, length = content.length, node; i < length; i++) {
2642
- // in case of NodeList unit, the elements will be removed out of the list during the appends
2643
- // therefore if that's an array we use the 'i' variable, and if it's a collection of nodes
2644
- // then we always hit the first element of the stack
2645
- node = content[content.length === length ? i : 0];
2646
- fragment.appendChild(node instanceof Element ? node._ : node);
2728
+ while (content.length !== 0) {
2729
+ fragment.appendChild(content[0]);
2730
+ }
2731
+
2732
+ } else {
2733
+ for (var i=0, length = content.length, node; i < length; i++) {
2734
+ node = content[content.length === length ? i : 0];
2735
+ fragment.appendChild(node instanceof Element ? node._ : node);
2736
+ }
2647
2737
  }
2648
2738
 
2649
2739
  return fragment;
@@ -2689,12 +2779,8 @@ Element.include({
2689
2779
  for (key in hash) {
2690
2780
  c_key = key.indexOf('-') < 0 ? key : key.camelize();
2691
2781
 
2692
- if (key === 'opacity') {
2693
- if (Browser_IE) {
2694
- element_style.filter = 'alpha(opacity='+ hash[key] * 100 +')';
2695
- } else {
2696
- element_style.opacity = hash[key];
2697
- }
2782
+ if (IE_OPACITY && key === 'opacity') {
2783
+ element_style.filter = 'alpha(opacity='+ hash[key] * 100 +')';
2698
2784
  } else if (key === 'float') {
2699
2785
  c_key = Browser_IE ? 'styleFloat' : 'cssFloat';
2700
2786
  }
@@ -2722,10 +2808,12 @@ Element.include({
2722
2808
  *
2723
2809
  * @return Object/CSSDefinition computed styles
2724
2810
  */
2725
- computedStyles: function() {
2726
- var element = this._;
2727
- // old IE, IE8, W3C
2728
- return element.currentStyle || element.runtimeStyle || element.ownerDocument.defaultView.getComputedStyle(element, null) || {};
2811
+ computedStyles: HTML.currentStyle ? function() {
2812
+ return this._.currentStyle || {};
2813
+ } : HTML.runtimeStyle ? function() {
2814
+ return this._.runtimeStyle || {};
2815
+ } : function() {
2816
+ return this._.ownerDocument.defaultView.getComputedStyle(this._, null);
2729
2817
  },
2730
2818
 
2731
2819
  /**
@@ -2813,28 +2901,28 @@ Element.include({
2813
2901
  * @param String style-key
2814
2902
  * @return String clean style
2815
2903
  */
2816
- function clean_style(style, in_key) {
2817
- var value, key = in_key.camelize();
2818
-
2819
- switch (key) {
2820
- case 'opacity':
2821
- value = !Browser_IE ? style[key].replace(',', '.') :
2822
- ((/opacity=(\d+)/i.exec(style.filter || '') || ['', '100'])[1].toInt() / 100)+'';
2823
- break;
2904
+ function clean_style(style, key) {
2905
+ key = key.camelize();
2906
+
2907
+ if (key === 'opacity') {
2908
+ return IE_OPACITY ? (
2909
+ (/opacity=(\d+)/i.exec(style.filter || '') ||
2910
+ ['', '100'])[1].toInt() / 100
2911
+ )+'' :style[key].replace(',', '.');
2912
+ }
2824
2913
 
2825
- case 'float':
2826
- key = Browser_IE ? 'styleFloat' : 'cssFloat';
2914
+ if (key === 'float') {
2915
+ key = Browser_IE ? 'styleFloat' : 'cssFloat';
2916
+ }
2827
2917
 
2828
- default:
2829
- value = style[key];
2918
+ var value = style[key];
2830
2919
 
2831
- // Opera returns named colors with quotes
2832
- if (Browser_Opera && /color/i.test(key) && value) {
2833
- value = value.replace(/"/g, '');
2834
- }
2920
+ // Opera returns named colors with quotes
2921
+ if (Browser_Opera && /color/i.test(key) && value) {
2922
+ value = value.replace(/"/g, '');
2835
2923
  }
2836
2924
 
2837
- return value || null;
2925
+ return value;
2838
2926
  }
2839
2927
 
2840
2928
 
@@ -2950,10 +3038,21 @@ Element.include({
2950
3038
  */
2951
3039
  show: function() {
2952
3040
  if (this.hidden()) {
2953
- // setting 'block' for the divs and 'inline' for the other elements hidden on the css-level
2954
- var element = this._, value = element.tagName == 'DIV' ? 'block' : 'inline';
3041
+ var element = this._, value = this._d, dummy;
3042
+
3043
+ // trying to guess the default 'style.display' for this kind of elements
3044
+ if (!value || value === 'none') {
3045
+ dummy = $E(element.tagName).insertTo(HTML);
3046
+ value = dummy.getStyle('display');
3047
+ dummy.remove();
3048
+ }
2955
3049
 
2956
- element.style.display = this._d == 'none' ? value : this._d || value;
3050
+ // failsafe in case the user been naughty
3051
+ if (value === 'none') {
3052
+ value = 'block';
3053
+ }
3054
+
3055
+ element.style.display = value;
2957
3056
  }
2958
3057
 
2959
3058
  return this;
@@ -3214,7 +3313,7 @@ Element.include({
3214
3313
  }
3215
3314
  };
3216
3315
 
3217
- if (Browser_IE) {
3316
+ if (IE8_OR_LESS) {
3218
3317
  hash.t._.attachEvent('on'+hash.n, hash.w);
3219
3318
  } else {
3220
3319
  hash.t._.addEventListener(hash.n, hash.w, false);
@@ -3236,7 +3335,7 @@ Element.include({
3236
3335
  */
3237
3336
  stopObserving: function(event, callback) {
3238
3337
  Observer_stopObserving(this, event, callback, function(hash) {
3239
- if (Browser_IE) {
3338
+ if (IE8_OR_LESS) {
3240
3339
  hash.t._.detachEvent('on'+ hash.n, hash.w);
3241
3340
  } else {
3242
3341
  hash.t._.removeEventListener(hash.n, hash.w, false);
@@ -3264,13 +3363,15 @@ Element.include({
3264
3363
  event.currentTarget = this;
3265
3364
 
3266
3365
  (this.$listeners || []).each(function(hash) {
3267
- if (hash.e === event.type && hash.f.apply(this, (hash.r?[]:[event]).concat(hash.a)) === false) {
3366
+ if (hash.e === event.type &&
3367
+ hash.f.apply(this, (hash.r?[]:[event]).concat(hash.a)) === false
3368
+ ) {
3268
3369
  event.stop();
3269
3370
  }
3270
3371
  }, this);
3271
3372
 
3272
3373
  // manually bypassing the event to the parent one if it should bubble
3273
- if (parent && parent.fire && !(event.bubbles === false || event.stopped)) {
3374
+ if (parent && parent.fire && !event.stopped) {
3274
3375
  parent.fire(event);
3275
3376
  }
3276
3377
 
@@ -3305,7 +3406,8 @@ function Element_add_event_shortcuts(tokens) {
3305
3406
  }
3306
3407
 
3307
3408
  Element_add_event_shortcuts(
3308
- 'click rightclick contextmenu mousedown mouseup mouseover mouseout mousemove keypress keydown keyup'
3409
+ 'click rightclick contextmenu mousedown mouseup '+
3410
+ 'mouseover mouseout mousemove keypress keydown keyup'
3309
3411
  );
3310
3412
 
3311
3413
 
@@ -3327,7 +3429,10 @@ Element_add_event_shortcuts(
3327
3429
  * @return Element matching node or null
3328
3430
  */
3329
3431
  first: function(css_rule) {
3330
- return wrap(this._.querySelector(css_rule || '*'));
3432
+ return wrap(
3433
+ css_rule === undefined && this._.firstElementChild !== undefined ?
3434
+ this._.firstElementChild : this._.querySelector(css_rule || '*')
3435
+ );
3331
3436
  },
3332
3437
 
3333
3438
  /**
@@ -3545,7 +3650,9 @@ var Form = RightJS.Form = Element_wrappers.FORM = new Class(Element, {
3545
3650
  this.inputs().each(function(element) {
3546
3651
  input = element._;
3547
3652
  name = input.name;
3548
- if (!input.disabled && name && (!['checkbox', 'radio'].include(input.type) || input.checked)) {
3653
+ if (!input.disabled && name && (
3654
+ !['checkbox', 'radio'].include(input.type) || input.checked
3655
+ )) {
3549
3656
  value = element.getValue();
3550
3657
  if (name.endsWith('[]')) {
3551
3658
  value = (values[name] || []).concat([value]);
@@ -3819,7 +3926,7 @@ function focus_boobler(raw_event) {
3819
3926
  target = event.target,
3820
3927
  parent = target.parent && target.parent();
3821
3928
 
3822
- event.type = (raw_event.type === 'focusin' || raw_event.type === 'focus') ? 'focus' : 'blur';
3929
+ event.type = raw_event.type === 'focusin' || raw_event.type === 'focus' ? 'focus' : 'blur';
3823
3930
 
3824
3931
  if (parent) { parent.fire(event); }
3825
3932
  }
@@ -3830,7 +3937,7 @@ function focus_boobler(raw_event) {
3830
3937
  * manually like they were normal events
3831
3938
  *
3832
3939
  */
3833
- if (Browser_IE) {
3940
+ if (IE8_OR_LESS) {
3834
3941
  document.attachEvent('onfocusin', focus_boobler);
3835
3942
  document.attachEvent('onfocusout', focus_boobler);
3836
3943
  } else {
@@ -3859,6 +3966,7 @@ function mouse_io_fire(raw, element, uid, enter) {
3859
3966
  var event = new Event(raw);
3860
3967
  event.type = enter === true ? 'mouseenter' : 'mouseleave';
3861
3968
  event.bubbles = false;
3969
+ event.stopped = true;
3862
3970
  event.target = wrap(element);
3863
3971
 
3864
3972
  // replacing the #find method so that UJS didn't
@@ -3907,7 +4015,7 @@ function mouse_io_handler(e) {
3907
4015
  }
3908
4016
 
3909
4017
  if (from && !passed) {
3910
- while (from.nodeType === 1 && parents.indexOf(from) === -1) {
4018
+ while (from !== null && from.nodeType === 1 && parents.indexOf(from) === -1) {
3911
4019
  uid = $uid(from);
3912
4020
  if (mouse_io_index[uid] !== undefined) {
3913
4021
  mouse_io_fire(e, from, uid,
@@ -4240,7 +4348,9 @@ $w('Element Input Form').each(function(klass) {
4240
4348
  }
4241
4349
  }
4242
4350
 
4243
- return null; // don't return the string itself in here, it will screw with data-retrieving calls on empty collections
4351
+ // don't return the string itself in here,
4352
+ // it will screw with data-retrieving calls on empty collections
4353
+ return null;
4244
4354
  };
4245
4355
  }
4246
4356
  });
@@ -4310,6 +4420,11 @@ var Xhr = RightJS.Xhr = new Class(Observer, {
4310
4420
  // copying some options to the instance level attributes
4311
4421
  $ext(this.$super(options), this.options);
4312
4422
 
4423
+ // merging in the global params
4424
+ if (this.params != Xhr.Options.params) {
4425
+ this.params = this.prepareData(Xhr.Options.params, this.params);
4426
+ }
4427
+
4313
4428
  // removing the local spinner if it's the same as the global one
4314
4429
  if (Xhr.Options.spinner && $(this.spinner) === $(Xhr.Options.spinner)) {
4315
4430
  this.spinner = null;
@@ -4357,7 +4472,11 @@ var Xhr = RightJS.Xhr = new Class(Observer, {
4357
4472
  * @return Xhr self
4358
4473
  */
4359
4474
  send: function(params) {
4360
- var add_params = {}, url = this.url, method = this.method.toLowerCase(), headers = this.headers, key, xhr;
4475
+ var add_params = {},
4476
+ url = this.url,
4477
+ method = this.method.toLowerCase(),
4478
+ headers = this.headers,
4479
+ key, xhr;
4361
4480
 
4362
4481
  if (method == 'put' || method == 'delete') {
4363
4482
  add_params._method = method;
@@ -4435,12 +4554,10 @@ var Xhr = RightJS.Xhr = new Class(Observer, {
4435
4554
  return new Xhr.JSONP(this);
4436
4555
  } else if (this.form && this.form.first('input[type=file]')) {
4437
4556
  return new Xhr.IFramed(this.form);
4557
+ } else if ('ActiveXObject' in window){
4558
+ return new ActiveXObject('MSXML2.XMLHTTP');
4438
4559
  } else {
4439
- try {
4440
- return new XMLHttpRequest();
4441
- } catch(e) {
4442
- return new ActiveXObject('MSXML2.XMLHTTP');
4443
- }
4560
+ return new XMLHttpRequest();
4444
4561
  }
4445
4562
  },
4446
4563
 
@@ -4493,20 +4610,17 @@ var Xhr = RightJS.Xhr = new Class(Observer, {
4493
4610
 
4494
4611
  // sanitizes the json-response texts
4495
4612
  sanitizedJSON: function() {
4496
- try {
4497
- return JSON.parse(this.text);
4498
- } catch(e) {
4499
- // manual json consistancy check
4500
- if (window.JSON || !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(this.text.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''))) {
4501
- if (this.secureJSON) {
4502
- throw "JSON error: "+this.text;
4503
- }
4504
- return null;
4613
+ if (!(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(
4614
+ this.text.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '')
4615
+ )) {
4616
+ if (this.secureJSON) {
4617
+ throw "JSON error: "+this.text;
4505
4618
  }
4619
+ return null;
4506
4620
  }
4507
4621
 
4508
- // the fallback JSON extraction
4509
- return eval("("+this.text+")");
4622
+ return 'JSON' in window ? JSON.parse(this.text) :
4623
+ (new Function("return "+this.text))();
4510
4624
  },
4511
4625
 
4512
4626
  // initializes the request callbacks
@@ -4578,19 +4692,6 @@ $ext(Observer_create(Xhr), {
4578
4692
  *
4579
4693
  * Copyright (C) 2009-2011 Nikolay V. Nemshilov
4580
4694
  */
4581
-
4582
- /**
4583
- * Catches the form submit events and sends the form remotely
4584
- *
4585
- * @param Event submit
4586
- * @param Object xhr options
4587
- * @return void
4588
- */
4589
- function remote_send(event, options) {
4590
- event.stop();
4591
- this.send($ext({spinner: this.first('.spinner')}, options));
4592
- }
4593
-
4594
4695
  Form.include({
4595
4696
  /**
4596
4697
  * sends the form via xhr request
@@ -4602,13 +4703,31 @@ Form.include({
4602
4703
  options = options || {};
4603
4704
  options.method = options.method || this._.method || 'post';
4604
4705
 
4605
- new Xhr(this._.action || document.location.href, options)
4606
- .onComplete(this.enable.bind(this)).send(this);
4706
+ this.xhr = new Xhr(
4707
+ this._.action || document.location.href,
4708
+ $ext({spinner: this.first('.spinner')}, options)
4709
+ )
4710
+ .onComplete(this.enable.bind(this))
4711
+ .onCancel(this.enable.bind(this))
4712
+ .send(this);
4607
4713
 
4608
4714
  this.disable.bind(this).delay(1); // webkit needs this async call with iframed calls
4609
4715
  return this;
4610
4716
  },
4611
4717
 
4718
+ /**
4719
+ * Cancels current Xhr request (if there are any)
4720
+ *
4721
+ * @return Form this
4722
+ */
4723
+ cancelXhr: function() {
4724
+ if (this.xhr instanceof Xhr) {
4725
+ this.xhr.cancel();
4726
+ }
4727
+
4728
+ return this;
4729
+ },
4730
+
4612
4731
  /**
4613
4732
  * makes the form be remote by default
4614
4733
  *
@@ -4616,10 +4735,11 @@ Form.include({
4616
4735
  * @return Form this
4617
4736
  */
4618
4737
  remotize: function(options) {
4619
- if (!this.observes('submit', remote_send)) {
4620
- this.on('submit', remote_send, options);
4738
+ if (!this.remote) {
4739
+ this.on('submit', Form_remote_send, options);
4621
4740
  this.remote = true;
4622
4741
  }
4742
+
4623
4743
  return this;
4624
4744
  },
4625
4745
 
@@ -4629,13 +4749,24 @@ Form.include({
4629
4749
  * @return Form this
4630
4750
  */
4631
4751
  unremotize: function() {
4632
- this.stopObserving('submit', remote_send);
4752
+ this.stopObserving('submit', Form_remote_send);
4633
4753
  this.remote = false;
4634
-
4635
4754
  return this;
4636
4755
  }
4637
4756
  });
4638
4757
 
4758
+ /**
4759
+ * Catches the form submit events and sends the form remotely
4760
+ *
4761
+ * @param Event submit
4762
+ * @param Object xhr options
4763
+ * @return void
4764
+ */
4765
+ function Form_remote_send(event, options) {
4766
+ event.stop();
4767
+ this.send(options);
4768
+ }
4769
+
4639
4770
 
4640
4771
  /**
4641
4772
  * this module contains the Element unit XHR related extensions
@@ -4669,7 +4800,6 @@ Element.include({
4669
4800
  */
4670
4801
  Xhr.Dummy = {
4671
4802
  open: function() {},
4672
- abort: function() {},
4673
4803
  setRequestHeader: function() {},
4674
4804
  onreadystatechange: function() {}
4675
4805
  };
@@ -4679,7 +4809,7 @@ Xhr.Dummy = {
4679
4809
  * This unit presents a fake drop in replacement for the XmlHTTPRequest unit
4680
4810
  * but works with an iframe targeting in the background
4681
4811
  *
4682
- * Copyright (C) 2008-2010 Nikolay Nemshilov
4812
+ * Copyright (C) 2008-2011 Nikolay Nemshilov
4683
4813
  */
4684
4814
  Xhr.IFramed = new Class({
4685
4815
  include: Xhr.Dummy,
@@ -4694,7 +4824,7 @@ Xhr.IFramed = new Class({
4694
4824
  this.form = form;
4695
4825
  this.id = 'xhr_'+ new Date().getTime();
4696
4826
 
4697
- form.insert('<i><iframe name="'+this.id+'" id="'+this.id+
4827
+ this.form.doc().first('body').append('<i><iframe name="'+this.id+'" id="'+this.id+
4698
4828
  '" width="0" height="0" frameborder="0" src="about:blank"></iframe></i>',
4699
4829
  'after');
4700
4830
 
@@ -4708,7 +4838,7 @@ Xhr.IFramed = new Class({
4708
4838
  onLoad: function() {
4709
4839
  this.status = 200;
4710
4840
  this.readyState = 4;
4711
-
4841
+
4712
4842
  this.form.set('target', '');
4713
4843
 
4714
4844
  try {
@@ -4716,6 +4846,10 @@ Xhr.IFramed = new Class({
4716
4846
  } catch(e) { }
4717
4847
 
4718
4848
  this.onreadystatechange();
4849
+ },
4850
+
4851
+ abort: function() {
4852
+ $(this.id).set('src', 'about:blank');
4719
4853
  }
4720
4854
  });
4721
4855
 
@@ -4723,7 +4857,7 @@ Xhr.IFramed = new Class({
4723
4857
  /**
4724
4858
  * The JSONP Xhr request tonnel
4725
4859
  *
4726
- * Copyright (C) 2010 Nikolay Nemshilov
4860
+ * Copyright (C) 2010-2011 Nikolay Nemshilov
4727
4861
  */
4728
4862
  Xhr.JSONP = new Class({
4729
4863
  include: Xhr.Dummy,
@@ -4787,6 +4921,16 @@ Xhr.JSONP = new Class({
4787
4921
  this.xhr.json = this.xhr.responseJSON = data;
4788
4922
 
4789
4923
  this.onreadystatechange();
4924
+ },
4925
+
4926
+ /**
4927
+ * We can't really cancel a JSONP request
4928
+ * but we can prevent the default handler to ckick in
4929
+ *
4930
+ * @return void
4931
+ */
4932
+ abort: function() {
4933
+ window[this.name] = function() {};
4790
4934
  }
4791
4935
  });
4792
4936
 
@@ -4813,7 +4957,7 @@ var Fx = RightJS.Fx = new Class(Observer, {
4813
4957
 
4814
4958
  // default options
4815
4959
  Options: {
4816
- fps: Browser_IE ? 40 : 60,
4960
+ fps: IE8_OR_LESS ? 40 : 60,
4817
4961
  duration: 'normal',
4818
4962
  transition: 'Sin',
4819
4963
  queue: true
@@ -5387,7 +5531,7 @@ function style_keys(style) {
5387
5531
  add_variants(keys, key, directions);
5388
5532
  } else if (key.startsWith('background')) {
5389
5533
  add_variants(keys, 'background', ['Color', 'Position', 'PositionX', 'PositionY']);
5390
- } else if (key === 'opacity' && Browser_IE) {
5534
+ } else if (key === 'opacity' && IE_OPACITY) {
5391
5535
  keys.push('filter');
5392
5536
  } else {
5393
5537
  keys.push(key);
@@ -5459,7 +5603,7 @@ function clean_styles(element, before, after) {
5459
5603
  }
5460
5604
 
5461
5605
  // IE opacity filter fix
5462
- if (after.filter && !before.filter) {
5606
+ if (IE_OPACITY && after.filter && !before.filter) {
5463
5607
  before.filter = 'alpha(opacity=100)';
5464
5608
  }
5465
5609
 
@@ -5496,15 +5640,18 @@ function clean_styles(element, before, after) {
5496
5640
 
5497
5641
  // cloning the element current styles hash
5498
5642
  function clone_style(element, keys) {
5499
- for (var i=0, len = keys.length, style = element.computedStyles(), clean = {}, key; i < len; i++) {
5643
+ var i=0, len = keys.length, style = element.computedStyles(), clean = {}, key;
5644
+
5645
+ for (; i < len; i++) {
5500
5646
  key = keys[i];
5647
+
5501
5648
  if (key in style) {
5502
5649
  clean[key] = ''+ style[key];
5503
- }
5504
5650
 
5505
- // libwebkit bug fix for in case of languages pack applied
5506
- if (key === 'opacity') {
5507
- clean[key] = clean[key].replace(',', '.');
5651
+ // libwebkit bug fix for in case of languages pack applied
5652
+ if (key === 'opacity') {
5653
+ clean[key] = clean[key].replace(',', '.');
5654
+ }
5508
5655
  }
5509
5656
  }
5510
5657
 
@@ -5753,7 +5900,7 @@ Fx.Scroll = new Class(Fx.Attr, {
5753
5900
  this.$super(
5754
5901
  element instanceof Window ?
5755
5902
  element._.document[
5756
- Browser.WebKit ? 'body' : 'documentElement'
5903
+ 'body' in element._.document ? 'body' : 'documentElement'
5757
5904
  ] : element,
5758
5905
  options
5759
5906
  );
@@ -5847,8 +5994,10 @@ var Cookie = RightJS.Cookie = new Class({
5847
5994
  * @return mixed saved value or null if nothing found
5848
5995
  */
5849
5996
  get: function() {
5850
- var value = this.options.document.cookie.match('(?:^|;)\\s*' + RegExp.escape(this.name) + '=([^;]*)');
5851
- return (value) ? decodeURIComponent(value[1]) : null;
5997
+ var value = this.options.document.cookie.match(
5998
+ '(?:^|;)\\s*' + RegExp.escape(this.name) + '=([^;]*)'
5999
+ );
6000
+ return value ? decodeURIComponent(value[1]) : null;
5852
6001
  },
5853
6002
 
5854
6003
  /**
@@ -5863,30 +6012,651 @@ var Cookie = RightJS.Cookie = new Class({
5863
6012
  });
5864
6013
 
5865
6014
 
5866
- // globalizing the top-level variables
5867
- $ext(window, Object.without(RightJS, 'version', 'modules'));
6015
+ /**
6016
+ * Old IE browser hacks
6017
+ *
6018
+ * Keep them in one place so they were more compact
6019
+ *
6020
+ * Copyright (C) 2009-2011 Nikolay Nemshilov
6021
+ */
6022
+ if (RightJS.Browser.OLD && RightJS.Browser.IE) {
6023
+ // loads DOM element extensions for selected elements
6024
+ window.$ = RightJS.$ = (function(old_function) {
6025
+ return function(id) {
6026
+ var element = old_function(id);
6027
+
6028
+ // old IE browses match both, ID and NAME
6029
+ if (element && element instanceof RightJS.Element &&
6030
+ RightJS.isString(id) && element._.id !== id
6031
+ ) {
6032
+ element = RightJS.$(document).first('#'+ id);
6033
+ }
6034
+
6035
+ return element;
6036
+ };
6037
+ })(RightJS.$);
6038
+ }
6039
+
6040
+
6041
+ /**
6042
+ * Making the 'submit' and 'change' events bubble under IE browsers
6043
+ *
6044
+ * Copyright (C) 2010-2011 Nikolay Nemshilov
6045
+ */
6046
+
6047
+ /**
6048
+ * Tests if there is the event support
6049
+ *
6050
+ * @param String event name
6051
+ * @retrun Boolean check result
6052
+ */
6053
+ function event_support_for(name, tag) {
6054
+ var e = document.createElement(tag);
6055
+ e.setAttribute(name, ';');
6056
+ return isFunction(e[name]);
6057
+ }
6058
+
6059
+ if (!event_support_for('onsubmit', 'form')) {
6060
+ /**
6061
+ * Emulates the 'submit' event bubbling for IE browsers
6062
+ *
6063
+ * @param raw dom-event
6064
+ * @return void
6065
+ */
6066
+ var submit_boobler = function(raw_event) {
6067
+ var event = $(raw_event), element = event.target._,
6068
+ type = element.type, form = element.form, parent;
6069
+
6070
+ if (form && (parent = $(form).parent()) && (
6071
+ (raw_event.keyCode === 13 && (type === 'text' || type === 'password')) ||
6072
+ (raw_event.type === 'click' && (type === 'submit' || type === 'image'))
6073
+ )) {
6074
+ event.type = 'submit';
6075
+ event.target = $(form);
6076
+ parent.fire(event);
6077
+ }
6078
+ };
6079
+
6080
+ document.attachEvent('onclick', submit_boobler);
6081
+ document.attachEvent('onkeypress', submit_boobler);
6082
+ }
6083
+
6084
+ if (!event_support_for('onchange', 'input')) {
6085
+
6086
+ var get_input_value = function(target) {
6087
+ var element = target._,
6088
+ type = element.type;
6089
+
6090
+ return type === 'radio' || type === 'checkbox' ?
6091
+ element.checked : target.getValue();
6092
+ },
6093
+
6094
+ /**
6095
+ * Emulates the 'change' event bubbling
6096
+ *
6097
+ * @param Event wrapped dom-event
6098
+ * @param Input wrapped input element
6099
+ * @return void
6100
+ */
6101
+ change_boobler = function(event, target) {
6102
+ var parent = target.parent(),
6103
+ value = get_input_value(target);
6104
+
6105
+ if (parent && ''+target._prev_value !== ''+value) {
6106
+ target._prev_value = value; // saving the value so it didn't fire up again
6107
+ event.type = 'change';
6108
+ parent.fire(event);
6109
+ }
6110
+ },
6111
+
6112
+ /**
6113
+ * Catches the input field changes
6114
+ *
6115
+ * @param raw dom-event
6116
+ * @return void
6117
+ */
6118
+ catch_inputs_access = function(raw_event) {
6119
+ var event = $(raw_event),
6120
+ target = event.target,
6121
+ type = target._.type,
6122
+ tag = target._.tagName,
6123
+ input_is_radio = (type === 'radio' || type === 'checkbox');
6124
+
6125
+ if (
6126
+ (event.type === 'click' && (input_is_radio || tag === 'SELECT')) ||
6127
+ (event.type === 'keydown' && (
6128
+ (event.keyCode == 13 && (tag !== 'TEXTAREA')) ||
6129
+ type === 'select-multiple'
6130
+ ))
6131
+ ) {
6132
+ change_boobler(event, target);
6133
+ }
6134
+ },
6135
+
6136
+ /**
6137
+ * Catch inputs blur
6138
+ *
6139
+ * @param raw dom-event
6140
+ * @return void
6141
+ */
6142
+ catch_input_left = function(raw_event) {
6143
+ var event = $(raw_event),
6144
+ target = event.target;
6145
+
6146
+ if (target instanceof Input) {
6147
+ change_boobler(event, target);
6148
+ }
6149
+ };
6150
+
6151
+ document.attachEvent('onclick', catch_inputs_access);
6152
+ document.attachEvent('onkeydown', catch_inputs_access);
6153
+ document.attachEvent('onfocusout', catch_input_left);
6154
+
6155
+ /**
6156
+ * storing the input element previous value, so we could figure out
6157
+ * if it was changed later on
6158
+ */
6159
+ document.attachEvent('onbeforeactivate', function(event) {
6160
+ var element = $(event).target;
6161
+
6162
+ if (element instanceof Input) {
6163
+ element._prev_value = get_input_value(element);
6164
+ }
6165
+ });
6166
+ }
6167
+
6168
+
6169
+ /**
6170
+ * Konqueror browser fixes
6171
+ *
6172
+ * Copyright (C) 2009-2011 Nikolay V. Nemshilov
6173
+ */
6174
+
6175
+ /**
6176
+ * manual position calculator, it works for Konqueror and also
6177
+ * for old versions of Opera and FF
6178
+ */
6179
+ if (!RightJS.$E('p')._.getBoundingClientRect) {
6180
+ RightJS.Element.include({
6181
+ position: function() {
6182
+ var element = this._,
6183
+ top = element.offsetTop,
6184
+ left = element.offsetLeft,
6185
+ parent = element.offsetParent;
6186
+
6187
+ while (parent) {
6188
+ top += parent.offsetTop;
6189
+ left += parent.offsetLeft;
6190
+
6191
+ parent = parent.offsetParent;
6192
+ }
6193
+
6194
+ return {x: left, y: top};
6195
+ }
6196
+ });
6197
+ }
6198
+
5868
6199
 
5869
- return RightJS;
5870
- })(window, document, Object, Array, String, Function, Number, Math);
5871
6200
  /**
5872
- * The old browsers support patch loading script
5873
- * will be included in the core file when it's built
5874
- * with the no-olds option
6201
+ * The manual css-selector feature implementation
5875
6202
  *
5876
- * Basically it just checks all the script tags on the page
5877
- * finds the core inclusion tag and uses it's src attribute
5878
- * to dynamically load the olds patch
6203
+ * Credits:
6204
+ * - Sizzle (http://sizzlejs.org) Copyright (C) John Resig
6205
+ * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
5879
6206
  *
5880
6207
  * Copyright (C) 2009-2011 Nikolay V. Nemshilov
5881
6208
  */
5882
- if (RightJS.Browser.OLD) {
5883
- (function(d) {
5884
- var script = d.createElement('script'),
5885
- scripts = d.getElementsByTagName('script'),
5886
- rjs_spt = scripts[scripts.length - 1];
6209
+ var has_native_css_selector = !!document.querySelector,
6210
+ needs_css_engine_patch = !has_native_css_selector;
6211
+
6212
+ if (RightJS.Browser.IE8L) {
6213
+ needs_css_engine_patch = true;
6214
+ }
5887
6215
 
5888
- script.src = rjs_spt.src.replace(/(^|\/)(right)([^\/]+)$/, '$1$2-olds$3');
6216
+ if (needs_css_engine_patch) {
6217
+ /**
6218
+ * The token searchers collection
6219
+ */
6220
+ var search = {
6221
+ // search for any descendant nodes
6222
+ ' ': function(element, tag) {
6223
+ return RightJS.$A(element.getElementsByTagName(tag));
6224
+ },
6225
+
6226
+ // search for immidate descendant nodes
6227
+ '>': function(element, tag) {
6228
+ var result = [], node = element.firstChild;
6229
+ while (node) {
6230
+ if (tag === '*' || node.tagName === tag) {
6231
+ result.push(node);
6232
+ }
6233
+ node = node.nextSibling;
6234
+ }
6235
+ return result;
6236
+ },
6237
+
6238
+ // search for immiate sibling nodes
6239
+ '+': function(element, tag) {
6240
+ while ((element = element.nextSibling)) {
6241
+ if (element.tagName) {
6242
+ return (tag === '*' || element.tagName === tag) ? [element] : [];
6243
+ }
6244
+ }
6245
+ return [];
6246
+ },
6247
+
6248
+ // search for late sibling nodes
6249
+ '~': function(element, tag) {
6250
+ var result = [];
6251
+ while ((element = element.nextSibling)) {
6252
+ if (tag === '*' || element.tagName === tag) {
6253
+ result.push(element);
6254
+ }
6255
+ }
6256
+ return result;
6257
+ }
6258
+ },
6259
+
6260
+
6261
+ /**
6262
+ * Collection of pseudo selector matchers
6263
+ */
6264
+ pseudos = {
6265
+ not: function(node, css_rule) {
6266
+ return node.nodeType === 1 && !RightJS.$(node).match(css_rule);
6267
+ },
6268
+
6269
+ checked: function(node) {
6270
+ return node.checked === true;
6271
+ },
6272
+
6273
+ enabled: function(node) {
6274
+ return node.disabled === false;
6275
+ },
6276
+
6277
+ disabled: function(node) {
6278
+ return node.disabled === true;
6279
+ },
6280
+
6281
+ selected: function(node) {
6282
+ return node.selected === true;
6283
+ },
6284
+
6285
+ empty: function(node) {
6286
+ return !node.firstChild;
6287
+ },
6288
+
6289
+ 'first-child': function(node, node_name) {
6290
+ while ((node = node.previousSibling)) {
6291
+ if (node.nodeType === 1 && (node_name === null || node.nodeName === node_name)) {
6292
+ return false;
6293
+ }
6294
+ }
6295
+ return true;
6296
+ },
6297
+
6298
+ 'first-of-type': function(node) {
6299
+ return pseudos['first-child'](node, node.nodeName);
6300
+ },
6301
+
6302
+ 'last-child': function(node, node_name) {
6303
+ while ((node = node.nextSibling)) {
6304
+ if (node.nodeType === 1 && (node_name === null || node.nodeName === node_name)) {
6305
+ return false;
6306
+ }
6307
+ }
6308
+ return true;
6309
+ },
6310
+
6311
+ 'last-of-type': function(node) {
6312
+ return pseudos['last-child'](node, node.nodeName);
6313
+ },
6314
+
6315
+ 'only-child': function(node, node_name) {
6316
+ return pseudos['first-child'](node, node_name) &&
6317
+ pseudos['last-child'](node, node_name);
6318
+ },
6319
+
6320
+ 'only-of-type': function(node) {
6321
+ return pseudos['only-child'](node, node.nodeName);
6322
+ },
6323
+
6324
+ 'nth-child': function(node, number, node_name, reverse) {
6325
+ var index = 1, a = number[0], b = number[1];
6326
+
6327
+ while ((node = (reverse === true) ? node.nextSibling : node.previousSibling)) {
6328
+ if (node.nodeType === 1 && (node_name === undefined || node.nodeName === node_name)) {
6329
+ index++;
6330
+ }
6331
+ }
6332
+
6333
+ return (b === undefined ? (index === a) : ((index - b) % a === 0 && (index - b) / a >= 0));
6334
+ },
6335
+
6336
+ 'nth-of-type': function(node, number) {
6337
+ return pseudos['nth-child'](node, number, node.nodeName);
6338
+ },
6339
+
6340
+ 'nth-last-child': function(node, number) {
6341
+ return pseudos['nth-child'](node, number, undefined, true);
6342
+ },
5889
6343
 
5890
- rjs_spt.parentNode.appendChild(script);
5891
- })(document);
6344
+ 'nth-last-of-type': function(node, number) {
6345
+ return pseudos['nth-child'](node, number, node.nodeName, true);
6346
+ }
6347
+ },
6348
+
6349
+ // the regexps collection
6350
+ chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,
6351
+ id_re = /#([\w\-_]+)/,
6352
+ tag_re = /^[\w\*]+/,
6353
+ class_re = /\.([\w\-\._]+)/,
6354
+ pseudo_re = /:([\w\-]+)(\((.+?)\))*$/,
6355
+ attrs_re = /\[((?:[\w\-]*:)?[\w\-]+)\s*(?:([!\^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/,
6356
+
6357
+ ///////////////////////////////////////////////////////////////////////////////
6358
+ ///////////////////////////////////////////////////////////////////////////////
6359
+ ///////////////////////////////////////////////////////////////////////////////
6360
+
6361
+ /**
6362
+ * Builds an atom matcher
6363
+ *
6364
+ * @param String atom definition
6365
+ * @return Object atom matcher
6366
+ */
6367
+ atoms_cache = {},
6368
+ build_atom = function(in_atom) {
6369
+ if (!atoms_cache[in_atom]) {
6370
+ var id, tag, classes, classes_length, attrs, pseudo,
6371
+ values_of_pseudo, match, func, desc = {}, atom = in_atom;
6372
+
6373
+ // grabbing the attributes
6374
+ while((match = atom.match(attrs_re))) {
6375
+ attrs = attrs || {};
6376
+ attrs[match[1]] = { o: match[2] || '', v: match[5] || match[6] || '' };
6377
+ atom = atom.replace(match[0], '');
6378
+ }
6379
+
6380
+ // extracting the pseudos
6381
+ if ((match = atom.match(pseudo_re))) {
6382
+ pseudo = match[1];
6383
+ values_of_pseudo = match[3] === '' ? null : match[3];
6384
+
6385
+ if (pseudo.startsWith('nth')) {
6386
+ // preparsing the nth-child pseoudo numbers
6387
+ values_of_pseudo = values_of_pseudo.toLowerCase();
6388
+
6389
+ if (values_of_pseudo === 'n') {
6390
+ // no need in the pseudo then
6391
+ pseudo = null;
6392
+ values_of_pseudo = null;
6393
+ } else {
6394
+ if (values_of_pseudo === 'odd') { values_of_pseudo = '2n+1'; }
6395
+ if (values_of_pseudo === 'even') { values_of_pseudo = '2n'; }
6396
+
6397
+ var m = /^([+\-]?\d*)?n([+\-]?\d*)?$/.exec(values_of_pseudo);
6398
+ if (m) {
6399
+ values_of_pseudo = [
6400
+ m[1] === '-' ? -1 : parseInt(m[1], 10) || 1,
6401
+ parseInt(m[2], 10) || 0
6402
+ ];
6403
+ } else {
6404
+ values_of_pseudo = [parseInt(values_of_pseudo, 10), undefined];
6405
+ }
6406
+ }
6407
+ }
6408
+
6409
+ atom = atom.replace(match[0], '');
6410
+ }
6411
+
6412
+ // getting all the other options
6413
+ id = (atom.match(id_re) || [1, null])[1];
6414
+ tag = (atom.match(tag_re) || '*').toString().toUpperCase();
6415
+ classes = (atom.match(class_re) || [1, ''])[1].split('.').without('');
6416
+ classes_length = classes.length;
6417
+
6418
+ desc.tag = tag;
6419
+
6420
+ if (id || classes.length || attrs || pseudo) {
6421
+ // optimizing a bit the values for quiker runtime checks
6422
+ id = id || false;
6423
+ attrs = attrs || false;
6424
+ pseudo = pseudo in pseudos ? pseudos[pseudo] : false;
6425
+ classes = classes_length ? classes : false;
6426
+
6427
+ desc.filter = function(elements) {
6428
+ var node, result = [], i=0, j=0, l = elements.length, failed;
6429
+ for (; i < l; i++) {
6430
+ node = elements[i];
6431
+
6432
+ //////////////////////////////////////////////
6433
+ // ID check
6434
+ //
6435
+ if (id !== false && node.id !== id) {
6436
+ continue;
6437
+ }
6438
+
6439
+ //////////////////////////////////////////////
6440
+ // Class names check
6441
+ if (classes !== false) {
6442
+ var names = node.className.split(' '),
6443
+ names_length = names.length,
6444
+ x = 0; failed = false;
6445
+
6446
+ for (; x < classes_length; x++) {
6447
+ for (var y=0, found = false; y < names_length; y++) {
6448
+ if (classes[x] === names[y]) {
6449
+ found = true;
6450
+ break;
6451
+ }
6452
+ }
6453
+
6454
+ if (!found) {
6455
+ failed = true;
6456
+ break;
6457
+ }
6458
+ }
6459
+
6460
+ if (failed) { continue; }
6461
+ }
6462
+
6463
+ ///////////////////////////////////////////////
6464
+ // Attributes check
6465
+ if (attrs !== false) {
6466
+ var key, attr, operand, value; failed = false;
6467
+ for (key in attrs) {
6468
+ attr = key === 'class' ? node.className : (node.getAttribute(key) || '');
6469
+ operand = attrs[key].o;
6470
+ value = attrs[key].v;
6471
+
6472
+ if (
6473
+ (operand === '' && (key === 'class'|| key === 'lang' ?
6474
+ (attr === '') : (node.getAttributeNode(key) === null))) ||
6475
+ (operand === '=' && attr !== value) ||
6476
+ (operand === '*=' && attr.indexOf(value) === -1) ||
6477
+ (operand === '^=' && attr.indexOf(value) !== 0) ||
6478
+ (operand === '$=' && attr.substring(attr.length - value.length) !== value) ||
6479
+ (operand === '~=' && attr.split(' ').indexOf(value) === -1) ||
6480
+ (operand === '|=' && attr.split('-').indexOf(value) === -1)
6481
+ ) { failed = true; break; }
6482
+ }
6483
+
6484
+ if (failed) { continue; }
6485
+ }
6486
+
6487
+ ///////////////////////////////////////////////
6488
+ // Pseudo selectors check
6489
+ if (pseudo !== false) {
6490
+ if (!pseudo(node, values_of_pseudo)) {
6491
+ continue;
6492
+ }
6493
+ }
6494
+
6495
+ result[j++] = node;
6496
+ }
6497
+ return result;
6498
+ };
6499
+ }
6500
+
6501
+ atoms_cache[in_atom] = desc;
6502
+ }
6503
+
6504
+ return atoms_cache[in_atom];
6505
+ },
6506
+
6507
+ /**
6508
+ * Builds a single selector out of a simple rule chunk
6509
+ *
6510
+ * @param Array of a single rule tokens
6511
+ * @return Function selector
6512
+ */
6513
+ tokens_cache = {},
6514
+ build_selector = function(rule) {
6515
+ var rule_key = rule.join('');
6516
+ if (!tokens_cache[rule_key]) {
6517
+ for (var i=0; i < rule.length; i++) {
6518
+ rule[i][1] = build_atom(rule[i][1]);
6519
+ }
6520
+
6521
+ // creates a list of uniq nodes
6522
+ var _uid = RightJS.$uid;
6523
+ var uniq = function(elements) {
6524
+ var uniq = [], uids = [], uid;
6525
+ for (var i=0, length = elements.length; i < length; i++) {
6526
+ uid = _uid(elements[i]);
6527
+ if (!uids[uid]) {
6528
+ uniq.push(elements[i]);
6529
+ uids[uid] = true;
6530
+ }
6531
+ }
6532
+
6533
+ return uniq;
6534
+ };
6535
+
6536
+ // performs the actual search of subnodes
6537
+ var find_subnodes = function(element, atom) {
6538
+ var result = search[atom[0]](element, atom[1].tag);
6539
+ return atom[1].filter ? atom[1].filter(result) : result;
6540
+ };
6541
+
6542
+ // building the actual selector function
6543
+ tokens_cache[rule_key] = function(element) {
6544
+ var founds, sub_founds;
6545
+
6546
+ for (var i=0, i_length = rule.length; i < i_length; i++) {
6547
+ if (i === 0) {
6548
+ founds = find_subnodes(element, rule[i]);
6549
+
6550
+ } else {
6551
+ if (i > 1) { founds = uniq(founds); }
6552
+
6553
+ for (var j=0; j < founds.length; j++) {
6554
+ sub_founds = find_subnodes(founds[j], rule[i]);
6555
+
6556
+ sub_founds.unshift(1); // <- nuke the parent node out of the list
6557
+ sub_founds.unshift(j); // <- position to insert the subresult
6558
+
6559
+ founds.splice.apply(founds, sub_founds);
6560
+
6561
+ j += sub_founds.length - 3;
6562
+ }
6563
+ }
6564
+ }
6565
+
6566
+ return rule.length > 1 ? uniq(founds) : founds;
6567
+ };
6568
+ }
6569
+ return tokens_cache[rule_key];
6570
+ },
6571
+
6572
+
6573
+ /**
6574
+ * Builds the list of selectors for the css_rule
6575
+ *
6576
+ * @param String raw css-rule
6577
+ * @return Array of selectors
6578
+ */
6579
+ selectors_cache = {}, chunks_cache = {},
6580
+ split_rule_to_selectors = function(css_rule) {
6581
+ if (!selectors_cache[css_rule]) {
6582
+ chunker.lastIndex = 0;
6583
+
6584
+ var rules = [], rule = [], rel = ' ', m, token;
6585
+ while ((m = chunker.exec(css_rule))) {
6586
+ token = m[1];
6587
+
6588
+ if (token === '+' || token === '>' || token === '~') {
6589
+ rel = token;
6590
+ } else {
6591
+ rule.push([rel, token]);
6592
+ rel = ' ';
6593
+ }
6594
+
6595
+ if (m[2]) {
6596
+ rules.push(build_selector(rule));
6597
+ rule = [];
6598
+ }
6599
+ }
6600
+ rules.push(build_selector(rule));
6601
+
6602
+ selectors_cache[css_rule] = rules;
6603
+ }
6604
+ return selectors_cache[css_rule];
6605
+ },
6606
+
6607
+
6608
+ /**
6609
+ * The top level method, it just goes throught the css-rule chunks
6610
+ * collect and merge the results that's it
6611
+ *
6612
+ * @param Element context
6613
+ * @param String raw css-rule
6614
+ * @return Array search result
6615
+ */
6616
+ select_all = function(element, css_rule) {
6617
+ var selectors = split_rule_to_selectors(css_rule), result = [];
6618
+ for (var i=0, length = selectors.length; i < length; i++) {
6619
+ result = result.concat(selectors[i](element));
6620
+ }
6621
+
6622
+ return result;
6623
+ },
6624
+
6625
+
6626
+ ///////////////////////////////////////////////////////////////////////////////
6627
+ ///////////////////////////////////////////////////////////////////////////////
6628
+ ///////////////////////////////////////////////////////////////////////////////
6629
+
6630
+ // the previous dom-selection methods replacement
6631
+ dom_extension = {
6632
+ first: function(css_rule) {
6633
+ return this.find(css_rule)[0];
6634
+ },
6635
+
6636
+ find: function(css_rule, raw) {
6637
+ var result, rule = css_rule || '*', element = this._, tag = element.tagName;
6638
+
6639
+ if (has_native_css_selector) {
6640
+ try { // trying to reuse native css-engine under IE8
6641
+ result = $A(element.querySelectorAll(rule));
6642
+ } catch(e) { // if it fails use our own engine
6643
+ result = select_all(element, rule);
6644
+ }
6645
+ } else {
6646
+ result = select_all(element, rule);
6647
+ }
6648
+
6649
+ return raw === true ? result : result.map(RightJS.$);
6650
+ }
6651
+ };
6652
+
6653
+ // hooking up the rightjs wrappers with the new methods
6654
+ RightJS.$ext(RightJS.Element.prototype, dom_extension);
6655
+ RightJS.$ext(RightJS.Document.prototype, dom_extension);
5892
6656
  }
6657
+
6658
+ // globalizing the top-level variables
6659
+ $ext(window, Object.without(RightJS, 'version', 'modules'));
6660
+
6661
+ return RightJS;
6662
+ })(window, document, Object, Array, String, Function, Number, Math);