right-rails 0.3.2 → 0.4.0

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.
@@ -4,16 +4,17 @@
4
4
  * The library released under terms of the MIT license
5
5
  * Visit http://rightjs.org for more details
6
6
  *
7
+ * Custom build with options: no-olds
8
+ *
7
9
  * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St.
8
10
  */
9
-
10
11
  /**
11
12
  * The framework description object
12
13
  *
13
14
  * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
14
15
  */
15
16
  var RightJS = {
16
- version: "1.4.3",
17
+ version: "1.5.0",
17
18
  modules: ["core", "form", "cookie", "xhr", "fx"]
18
19
  };
19
20
 
@@ -156,15 +157,9 @@ function defined(value) {
156
157
  * @return boolean check result
157
158
  */
158
159
  function isHash(value) {
159
- return typeof(value) == 'object' && value !== null && value.constructor === Object;
160
+ return typeof(value) === 'object' && value !== null && value.constructor === Object;
160
161
  };
161
162
 
162
- // Konqueror 3 patch
163
- if (navigator.userAgent.indexOf('Konqueror/3') != -1) {
164
- eval(isHash.toString().replace(';', '&&!(arguments[0] instanceof HTMLElement);'));
165
- }
166
-
167
-
168
163
  /**
169
164
  * checks if the given value is a function
170
165
  *
@@ -172,7 +167,7 @@ if (navigator.userAgent.indexOf('Konqueror/3') != -1) {
172
167
  * @return boolean check result
173
168
  */
174
169
  function isFunction(value) {
175
- return typeof(value) == 'function';
170
+ return typeof(value) === 'function';
176
171
  };
177
172
 
178
173
  /**
@@ -182,7 +177,7 @@ function isFunction(value) {
182
177
  * @return boolean check result
183
178
  */
184
179
  function isString(value) {
185
- return typeof(value) == 'string';
180
+ return typeof(value) === 'string';
186
181
  };
187
182
 
188
183
  /**
@@ -202,7 +197,7 @@ function isArray(value) {
202
197
  * @return boolean check result
203
198
  */
204
199
  function isNumber(value) {
205
- return typeof(value) == 'number';
200
+ return typeof(value) === 'number';
206
201
  };
207
202
 
208
203
  /**
@@ -234,12 +229,12 @@ function isNode(value) {
234
229
  var $A = (function(slice) {
235
230
  return function (it) {
236
231
  try {
237
- var a = slice.call(it);
232
+ return slice.call(it);
238
233
  } catch(e) {
239
234
  for (var a=[], i=0, length = it.length; i < length; i++)
240
235
  a[i] = it[i];
236
+ return a;
241
237
  }
242
- return a;
243
238
  };
244
239
  })(Array.prototype.slice);
245
240
 
@@ -261,8 +256,7 @@ function $E(tag_name, options) {
261
256
  * @return Element or null
262
257
  */
263
258
  function $(element) {
264
- var element = typeof(element) == 'string' ? document.getElementById(element) : element;
265
- return Browser.OLD ? Element.prepare(element) : element;
259
+ return typeof(element) === 'string' ? document.getElementById(element) : element;
266
260
  };
267
261
 
268
262
  /**
@@ -291,13 +285,11 @@ function $w(string) {
291
285
  * @param Object object
292
286
  * @return Integer uniq id
293
287
  */
294
- var $uid = (function() {
295
- var _UID = 1;
296
-
288
+ var $uid = (function(UID) {
297
289
  return function(item) {
298
- return item.uid || (item.uid = _UID++);
290
+ return item.uid || (item.uid = UID++);
299
291
  };
300
- })();
292
+ })(1);
301
293
 
302
294
 
303
295
  /**
@@ -538,7 +530,7 @@ $ext(Array.prototype, (function(A_proto) {
538
530
 
539
531
  if (isString(callback)) {
540
532
  var attr = callback;
541
- if (array.length && isFunction(array[0][attr])) {
533
+ if (array.length !== 0 && isFunction(array[0][attr])) {
542
534
  callback = function(object) { return object[attr].apply(object, args); };
543
535
  } else {
544
536
  callback = function(object) { return object[attr]; };
@@ -733,10 +725,10 @@ return {
733
725
  arg = arguments[i];
734
726
  if (isArray(arg)) {
735
727
  for (var j=0; j < arg.length; j++) {
736
- if (copy.indexOf(arg[j]) == -1)
728
+ if (copy.indexOf(arg[j]) === -1)
737
729
  copy.push(arg[j]);
738
730
  }
739
- } else if (copy.indexOf(arg) == -1) {
731
+ } else if (copy.indexOf(arg) === -1) {
740
732
  copy.push(arg);
741
733
  }
742
734
  }
@@ -788,7 +780,7 @@ return {
788
780
  */
789
781
  includes: function() {
790
782
  for (var i=0, length = arguments.length; i < length; i++)
791
- if (this.indexOf(arguments[i]) == -1)
783
+ if (this.indexOf(arguments[i]) === -1)
792
784
  return false;
793
785
  return true;
794
786
  },
@@ -926,7 +918,7 @@ $ext(String.prototype, {
926
918
  */
927
919
  extractScripts: function() {
928
920
  var scripts = '';
929
- this.stripScripts(function(s,t) { scripts = s; });
921
+ this.stripScripts(function(s) { scripts = s; });
930
922
  return scripts;
931
923
  },
932
924
 
@@ -980,7 +972,7 @@ $ext(String.prototype, {
980
972
  * @return boolean check result
981
973
  */
982
974
  includes: function(string) {
983
- return this.indexOf(string) != -1;
975
+ return this.indexOf(string) !== -1;
984
976
  },
985
977
 
986
978
  /**
@@ -992,8 +984,8 @@ $ext(String.prototype, {
992
984
  */
993
985
  startsWith: function(string, ignorecase) {
994
986
  var start_str = this.substr(0, string.length);
995
- return ignorecase ? start_str.toLowerCase() == string.toLowerCase() :
996
- start_str == string;
987
+ return ignorecase ? start_str.toLowerCase() === string.toLowerCase() :
988
+ start_str === string;
997
989
  },
998
990
 
999
991
  /**
@@ -1005,8 +997,8 @@ $ext(String.prototype, {
1005
997
  */
1006
998
  endsWith: function(string, ignorecase) {
1007
999
  var end_str = this.substring(this.length - string.length);
1008
- return ignorecase ? end_str.toLowerCase() == string.toLowerCase() :
1009
- end_str == string;
1000
+ return ignorecase ? end_str.toLowerCase() === string.toLowerCase() :
1001
+ end_str === string;
1010
1002
  },
1011
1003
 
1012
1004
  /**
@@ -1040,7 +1032,11 @@ $alias(String.prototype, {include: 'includes'});
1040
1032
  *
1041
1033
  * Copyright (C) 2008 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
1042
1034
  */
1043
- $ext(Function.prototype, {
1035
+ $ext(Function.prototype, (function() {
1036
+ // creating a local reference to the method for a faster access
1037
+ var _A = Array.prototype.slice;
1038
+
1039
+ return {
1044
1040
  /**
1045
1041
  * binds the function to be executed in the given scope
1046
1042
  *
@@ -1050,14 +1046,14 @@ $ext(Function.prototype, {
1050
1046
  * @return Function binded function
1051
1047
  */
1052
1048
  bind: function() {
1053
- if (arguments.length < 2 && !defined(arguments[0])) return this;
1054
-
1055
- var _method = this, args = $A(arguments), scope = args.shift();
1049
+ if (arguments.length < 2 && !arguments[0]) return this;
1050
+
1051
+ var slice = _A, args = slice.call(arguments), scope = args.shift(), func = this;
1056
1052
  return function() {
1057
- return _method.apply(scope, args.concat($A(arguments)));
1053
+ return func.apply(scope, (args.length !== 0 || arguments.length !== 0) ? args.concat(slice.call(arguments)) : args);
1058
1054
  };
1059
1055
  },
1060
-
1056
+
1061
1057
  /**
1062
1058
  * binds the function as an event listener to the given scope object
1063
1059
  *
@@ -1067,23 +1063,37 @@ $ext(Function.prototype, {
1067
1063
  * @return Function binded function
1068
1064
  */
1069
1065
  bindAsEventListener: function() {
1070
- var _method = this, args = $A(arguments), scope = args.shift();
1066
+ var slice = _A, args = slice.call(arguments), scope = args.shift(), func = this;
1071
1067
  return function(event) {
1072
- return _method.apply(scope, [event || window.event].concat(args).concat($A(arguments)));
1068
+ return func.apply(scope, [event || window.event].concat(args).concat(slice.call(arguments)));
1073
1069
  };
1074
1070
  },
1075
-
1071
+
1076
1072
  /**
1077
1073
  * allows you to put some curry in your cookery
1078
1074
  *
1079
1075
  * @param mixed value to curry
1080
1076
  * ....
1081
- * @return Function carried function
1077
+ * @return Function curried function
1082
1078
  */
1083
1079
  curry: function() {
1084
- return this.bind.apply(this, [this].concat($A(arguments)));
1080
+ return this.bind.apply(this, [this].concat(_A.call(arguments)));
1085
1081
  },
1086
1082
 
1083
+ /**
1084
+ * The right side curry feature
1085
+ *
1086
+ * @param mixed value to curry
1087
+ * ....
1088
+ * @return Function curried function
1089
+ */
1090
+ rcurry: function() {
1091
+ var curry = _A.call(arguments), func = this;
1092
+ return function() {
1093
+ return func.apply(func, _A.call(arguments).concat(curry));
1094
+ }
1095
+ },
1096
+
1087
1097
  /**
1088
1098
  * delays the function execution
1089
1099
  *
@@ -1093,14 +1103,14 @@ $ext(Function.prototype, {
1093
1103
  * @return Integer timeout marker
1094
1104
  */
1095
1105
  delay: function() {
1096
- var args = $A(arguments), timeout = args.shift();
1106
+ var args = _A.call(arguments), timeout = args.shift();
1097
1107
  var timer = new Number(window.setTimeout(this.bind.apply(this, [this].concat(args)), timeout));
1098
-
1099
- timer['cancel'] = function() { window.clearTimeout(this); };
1100
-
1108
+
1109
+ timer.cancel = function() { window.clearTimeout(this); };
1110
+
1101
1111
  return timer;
1102
1112
  },
1103
-
1113
+
1104
1114
  /**
1105
1115
  * creates a periodical execution of the function with the given timeout
1106
1116
  *
@@ -1110,14 +1120,31 @@ $ext(Function.prototype, {
1110
1120
  * @return Ineger interval marker
1111
1121
  */
1112
1122
  periodical: function() {
1113
- var args = $A(arguments), timeout = args.shift();
1123
+ var args = _A.call(arguments), timeout = args.shift();
1114
1124
  var timer = new Number(window.setInterval(this.bind.apply(this, [this].concat(args)), timeout));
1115
-
1116
- timer['stop'] = function() { window.clearInterval(this); };
1117
-
1125
+
1126
+ timer.stop = function() { window.clearInterval(this); };
1127
+
1118
1128
  return timer;
1129
+ },
1130
+
1131
+ /**
1132
+ * Chains the given function after the current one
1133
+ *
1134
+ * @param Function the next function
1135
+ * @param mixed optional value to curry
1136
+ * ......
1137
+ * @return Function chained function
1138
+ */
1139
+ chain: function() {
1140
+ var args = _A.call(arguments), func = args.shift(), current = this;
1141
+ return function() {
1142
+ var result = current.apply(current, arguments);
1143
+ func.apply(func, args);
1144
+ return result;
1145
+ };
1119
1146
  }
1120
- });
1147
+ }})());
1121
1148
 
1122
1149
  /**
1123
1150
  * The Number class extentions
@@ -1158,8 +1185,13 @@ $ext(Number.prototype, {
1158
1185
  return Math.abs(this);
1159
1186
  },
1160
1187
 
1161
- round: function() {
1162
- return Math.round(this);
1188
+ round: function(base) {
1189
+ if (base) {
1190
+ var base = Math.pow(10, base);
1191
+ return Math.round(this * base) / base;
1192
+ } else {
1193
+ return Math.round(this);
1194
+ }
1163
1195
  },
1164
1196
 
1165
1197
  ceil: function() {
@@ -1205,102 +1237,94 @@ $ext(RegExp, {
1205
1237
  */
1206
1238
  var Class = function() {
1207
1239
  var args = $A(arguments), properties = args.pop() || {}, parent = args.pop();
1208
-
1240
+
1209
1241
  // if only the parent class has been specified
1210
- if (arguments.length == 1 && isFunction(properties)) {
1242
+ if (!args.length && !isHash(properties)) {
1211
1243
  parent = properties; properties = {};
1212
1244
  }
1213
-
1245
+
1214
1246
  // basic class object definition
1215
1247
  var klass = function() {
1216
1248
  return this.initialize ? this.initialize.apply(this, arguments) : this;
1217
1249
  };
1218
-
1250
+
1219
1251
  // attaching main class-level methods
1220
- $ext(klass, Class.Methods);
1221
-
1222
- // handling the parent class assign
1223
- Class.Util.catchSuper(klass, parent);
1224
- klass.prototype.constructor = klass; // <- don't put it lower
1225
-
1226
- // handling the inlinde extends and includes
1227
- Class.Util.catchExtends(klass, properties);
1228
- Class.Util.catchIncludes(klass, properties);
1229
-
1230
- klass.include(properties);
1252
+ $ext(klass, Class.Methods).inherit(parent);
1253
+
1254
+ // catching the injections
1255
+ $w('extend include').each(function(name) {
1256
+ if (properties[name]) {
1257
+ var modules = properties[name];
1258
+ klass[name].apply(klass, isArray(modules) ? modules : [modules]);
1259
+ delete(properties[name]);
1260
+ }
1261
+ });
1231
1262
 
1232
- return klass;
1263
+ return klass.include(properties);
1233
1264
  };
1234
1265
 
1235
1266
  /**
1236
- * This module contains some utils which hepls handling new classes definition
1267
+ * This method gets through a list of the object its class and all the ancestors
1268
+ * and finds a hash named after property, used for configuration purposes with
1269
+ * the Observer and Options modules
1237
1270
  *
1238
- * Copyright (C) 2008 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
1271
+ * NOTE: this method will look for capitalized and uppercased versions of the
1272
+ * property name
1273
+ *
1274
+ * @param Object a class instance
1275
+ * @param String property name
1276
+ * @return Object hash or null if nothing found
1277
+ */
1278
+ Class.findSet = function(object, property) {
1279
+ var upcased = property.toUpperCase(), capcased = property.capitalize(),
1280
+ candidates = [object, object.constructor].concat(object.constructor.ancestors),
1281
+ holder = candidates.first(function(o) { return o[upcased] || o[capcased]});
1282
+
1283
+ return holder ? holder[upcased] || holder[capcased] : null;
1284
+ };
1285
+
1286
+ /**
1287
+ * This module contains the methods by which the Class instances
1288
+ * will be extended. It provides basic and standard way to work
1289
+ * with the classes.
1290
+ *
1291
+ * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
1239
1292
  */
1240
- Class.Util = {
1293
+ Class.Methods = (function() {
1294
+ var commons = $w('selfExtended self_extended selfIncluded self_included');
1295
+ var extend = commons.concat($w('prototype parent extend include'));
1296
+ var include = commons.concat(['constructor']);
1297
+
1298
+ var clean_module = function(module, what) {
1299
+ return Object.without.apply(Object, [module].concat(what == 'e' ? extend : include));
1300
+ };
1301
+
1302
+ return {
1241
1303
  /**
1242
- * handles the class superclass catching up
1304
+ * Makes the class get inherited from another one
1243
1305
  *
1244
- * @param Function class
1245
- * @param Class superclass
1246
- * @return void
1306
+ * @param Object another class
1307
+ * @return Class this
1247
1308
  */
1248
- catchSuper: function(klass, parent) {
1249
- if (parent && defined(parent.prototype)) {
1250
- klass.parent = parent;
1309
+ inherit: function(parent) {
1310
+ // handling the parent class assign
1311
+ if (parent && parent.prototype) {
1251
1312
  var s_klass = function() {};
1252
1313
  s_klass.prototype = parent.prototype;
1253
- klass.prototype = new s_klass;
1314
+ this.prototype = new s_klass;
1315
+ this.parent = parent;
1254
1316
  }
1255
-
1256
- klass.ancestors = [];
1317
+
1318
+ // collecting the list of ancestors
1319
+ this.ancestors = [];
1257
1320
  while (parent) {
1258
- klass.ancestors.push(parent);
1321
+ this.ancestors.push(parent);
1259
1322
  parent = parent.parent;
1260
1323
  }
1261
- },
1262
-
1263
- /**
1264
- * handles the inline extendings on class definitions
1265
- *
1266
- * @param Function class
1267
- * @param Object user's properties
1268
- * @return void
1269
- */
1270
- catchExtends: function(klass, properties) {
1271
- if (properties['extend']) {
1272
- var exts = properties['extend'];
1273
-
1274
- klass.extend.apply(klass, isArray(exts) ? exts : [exts]);
1275
- delete(properties['extend']);
1276
- }
1277
- },
1278
-
1279
- /**
1280
- * handles the inline includes of the class definitions
1281
- *
1282
- * @param Function class
1283
- * @param Object user's properties
1284
- * @return void
1285
- */
1286
- catchIncludes: function(klass, properties) {
1287
- if (properties['include']) {
1288
- var includes = properties['include'];
1289
1324
 
1290
- klass.include.apply(klass, isArray(includes) ? includes : [includes]);
1291
- delete(properties['include']);
1292
- }
1293
- }
1294
- };
1325
+ return this.prototype.constructor = this;
1326
+ },
1295
1327
 
1296
- /**
1297
- * This module contains the methods by which the Class instances
1298
- * will be extended. It provides basic and standard way to work
1299
- * with the classes.
1300
- *
1301
- * Copyright (C) 2008 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
1302
- */
1303
- Class.Methods = {
1304
1328
  /**
1305
1329
  * this method will extend the class-level with the given objects
1306
1330
  *
@@ -1316,20 +1340,17 @@ Class.Methods = {
1316
1340
  * @return Class the klass
1317
1341
  */
1318
1342
  extend: function() {
1319
- var filter = ['prototype', 'name', 'parent', 'extend', 'include'];
1320
- for (var i=0; i < arguments.length; i++) {
1321
- if (isHash(arguments[i])) {
1322
- for (var key in arguments[i]) {
1323
- if (!filter.includes(key)) {
1324
- this[key] = arguments[i][key];
1325
- }
1326
- }
1327
- }
1328
- }
1329
-
1343
+ $A(arguments).filter(isHash).each(function(module) {
1344
+ var callback = module.selfExtended || module.self_extended;
1345
+
1346
+ $ext(this, clean_module(module, 'e'));
1347
+
1348
+ if (callback) callback.call(module, this);
1349
+ }, this);
1350
+
1330
1351
  return this;
1331
1352
  },
1332
-
1353
+
1333
1354
  /**
1334
1355
  * extends the class prototype with the given objects
1335
1356
  * NOTE: this method _WILL_OVERWRITE_ the existing itercecting entries
@@ -1340,33 +1361,31 @@ Class.Methods = {
1340
1361
  * @return Class the klass
1341
1362
  */
1342
1363
  include: function() {
1343
- for (var i=0; i < arguments.length; i++) {
1344
- if (isHash(arguments[i])) {
1345
- for (var key in arguments[i]) {
1346
- if (key != 'klass' && key != 'constructor') {
1347
-
1348
- // handling the super methods
1349
- var ancestor = this.ancestors.first(function(klass) { return isFunction(klass.prototype[key]); });
1350
-
1351
- if (ancestor) {
1352
- (function(name, method, $super) {
1353
- this.prototype[name] = function() {
1354
- this.$super = $super;
1355
-
1356
- return method.apply(this, arguments);
1357
- };
1358
- }).call(this, key, arguments[i][key], ancestor.prototype[key]);
1359
- } else {
1360
- this.prototype[key] = arguments[i][key];
1361
- }
1362
-
1363
- }
1364
- }
1364
+ var ancestors = this.ancestors.map('prototype'), ancestor;
1365
+
1366
+ $A(arguments).filter(isHash).each(function(module) {
1367
+ var callback = module.selfIncluded || module.self_included;
1368
+ module = clean_module(module, 'i');
1369
+
1370
+ for (var key in module) {
1371
+ ancestor = ancestors.first(function(proto) { return isFunction(proto[key]); });
1372
+
1373
+ this.prototype[key] = !ancestor ? module[key] :
1374
+ (function(name, method, super_method) {
1375
+ return function() {
1376
+ this.$super = super_method;
1377
+
1378
+ return method.apply(this, arguments);
1379
+ };
1380
+ })(key, module[key], ancestor[key]);
1365
1381
  }
1366
- }
1382
+
1383
+ if (callback) callback.call(module, this);
1384
+ }, this);
1385
+
1367
1386
  return this;
1368
1387
  }
1369
- };
1388
+ }})();
1370
1389
 
1371
1390
  /**
1372
1391
  * This is a simple mix-in module to be included in other classes
@@ -1388,26 +1407,34 @@ var Options = {
1388
1407
  * @return Object current instance
1389
1408
  */
1390
1409
  setOptions: function(options) {
1391
- var names = $w('OPTIONS Options options'),
1392
- objects = [this, this.constructor].concat(this.constructor.ancestors),
1393
- OPTIONS = objects.map(function(object) {
1394
- return names.map(function(name) { return object[name]; });
1395
- }).flatten().first(function(i) { return !!i; });
1396
-
1397
- this.options = Object.merge({}, OPTIONS, options);
1410
+ var options = this.options = Object.merge(Class.findSet(this, 'options'), options);
1398
1411
 
1399
1412
  // hooking up the observer options
1400
1413
  if (isFunction(this.on)) {
1401
1414
  var match;
1402
- for (var key in this.options) {
1403
- if (match = key.match(/on([A-Z][a-z]+)/)) {
1404
- this.on(match[1].toLowerCase(), this.options[key]);
1405
- delete(this.options[key]);
1415
+ for (var key in options) {
1416
+ if (match = key.match(/on([A-Z][A-Za-z]+)/)) {
1417
+ this.on(match[1].toLowerCase(), options[key]);
1418
+ delete(options[key]);
1406
1419
  }
1407
1420
  }
1408
1421
  }
1409
1422
 
1410
1423
  return this;
1424
+ },
1425
+
1426
+ /**
1427
+ * Cuts of an options hash from the end of the arguments list
1428
+ * assigns them using the #setOptions method and then
1429
+ * returns the list of other arguments as an Array instance
1430
+ *
1431
+ * @param mixed iterable
1432
+ * @return Array of the arguments
1433
+ */
1434
+ cutOptions: function(args) {
1435
+ var args = $A(args);
1436
+ this.setOptions(isHash(args.last()) ? args.pop() : {});
1437
+ return args;
1411
1438
  }
1412
1439
  };
1413
1440
 
@@ -1431,14 +1458,8 @@ var Observer = new Class({
1431
1458
  * @param Object options
1432
1459
  */
1433
1460
  initialize: function(options) {
1434
- this.setOptions(options);
1435
-
1436
- // catching up the event shortucts
1437
- var ancestor, shorts = this.EVENTS || this.constructor.EVENTS ||
1438
- ((ancestor = this.constructor.ancestors.first('EVENTS')) ?
1439
- ancestor.EVENTS : null);
1440
-
1441
- Observer.createShortcuts(this, shorts);
1461
+ this.setOptions(options);
1462
+ Observer.createShortcuts(this, Class.findSet(this, 'events'));
1442
1463
  },
1443
1464
 
1444
1465
  /**
@@ -1452,9 +1473,33 @@ var Observer = new Class({
1452
1473
  * @return Observer self
1453
1474
  */
1454
1475
  observe: function() {
1455
- var args = $A(arguments), event = args.shift();
1456
-
1457
- if (!event.trim) { // <- not a string
1476
+ var args = Array.prototype.slice.call(arguments), event = args.shift();
1477
+
1478
+ if (typeof(event) === 'string') {
1479
+ if (this.$listeners === undefined) this.$listeners = [];
1480
+
1481
+ var callback = args.shift();
1482
+ switch (typeof callback) {
1483
+ case "string":
1484
+ callback = this[callback];
1485
+
1486
+ case "function":
1487
+ var hash = { e: event, f: callback, a: args };
1488
+ this.$listeners.push(hash);
1489
+ break;
1490
+
1491
+ default:
1492
+ if (isArray(callback)) {
1493
+ callback.each(function(params) {
1494
+ this.observe.apply(this, [event].concat(
1495
+ isArray(params) ? params : [params]
1496
+ ).concat(args));
1497
+ }, this);
1498
+ }
1499
+ }
1500
+
1501
+ } else {
1502
+ // assuming it's a hash of key-value pairs
1458
1503
  for (var name in event) {
1459
1504
  this.observe.apply(this, [name].concat(
1460
1505
  isArray(event[name]) ? event[name] : [event[name]]
@@ -1462,30 +1507,7 @@ var Observer = new Class({
1462
1507
  }
1463
1508
  }
1464
1509
 
1465
- if (!this.$listeners) this.$listeners = [];
1466
1510
 
1467
- var callback = args.shift();
1468
- switch (typeof callback) {
1469
- case "string":
1470
- callback = this[callback];
1471
-
1472
- case "function":
1473
- var hash = { e: event, f: callback, a: args };
1474
- this.$listeners.push(hash);
1475
-
1476
- if (this.$o && this.$o.add) this.$o.add.call(this, hash);
1477
-
1478
- break;
1479
-
1480
- default:
1481
- if (isArray(callback)) {
1482
- callback.each(function(params) {
1483
- this.observe.apply(this, [event].concat(
1484
- isArray(params) ? params : [params]
1485
- ).concat(args));
1486
- }, this);
1487
- }
1488
- }
1489
1511
 
1490
1512
  return this;
1491
1513
  },
@@ -1530,12 +1552,8 @@ var Observer = new Class({
1530
1552
  if (isString(callback)) callback = this[callback];
1531
1553
 
1532
1554
  this.$listeners = this.$listeners.filter(function(i) {
1533
- var result = (event && callback) ? (i.e != event || i.f != callback) :
1534
- (event ? i.e != event : i.f != callback);
1535
-
1536
- if (!result && this.$o && this.$o.remove) this.$o.remove.call(this, i);
1537
-
1538
- return result;
1555
+ return (event && callback) ? (i.e !== event || i.f !== callback) :
1556
+ (event ? i.e !== event : i.f !== callback);
1539
1557
  }, this);
1540
1558
  }
1541
1559
 
@@ -1553,7 +1571,7 @@ var Observer = new Class({
1553
1571
  */
1554
1572
  listeners: function(event) {
1555
1573
  return (this.$listeners || []).filter(function(i) {
1556
- return !event || i.e == event;
1574
+ return !event || i.e === event;
1557
1575
  }).map(function(i) { return i.f; }).uniq();
1558
1576
  },
1559
1577
 
@@ -1569,10 +1587,7 @@ var Observer = new Class({
1569
1587
  var args = $A(arguments), event = args.shift();
1570
1588
 
1571
1589
  (this.$listeners || []).each(function(i) {
1572
- if (i.e == event) {
1573
- (this.$o && this.$o.fire) ? this.$o.fire.call(this, event, args, i) :
1574
- i.f.apply(this, i.a.concat(args));
1575
- }
1590
+ if (i.e === event) i.f.apply(this, i.a.concat(args));
1576
1591
  }, this);
1577
1592
 
1578
1593
  return this;
@@ -1588,7 +1603,7 @@ var Observer = new Class({
1588
1603
  */
1589
1604
  create: function(object, events) {
1590
1605
  $ext(object, Object.without(this.prototype, 'initialize', 'setOptions'), true);
1591
- return this.createShortcuts(object, events || object['EVENTS']);
1606
+ return this.createShortcuts(object, events || Class.findSet(object, 'events'));
1592
1607
  },
1593
1608
 
1594
1609
  /**
@@ -1690,8 +1705,8 @@ var Event = new Class(Event, {
1690
1705
  */
1691
1706
  cleanName: function(name) {
1692
1707
  name = name.toLowerCase();
1693
- name = name.startsWith('on') ? name.slice(2) : name;
1694
- name = name == 'rightclick' ? 'contextmenu' : name;
1708
+ name = name.substr(0,2) === 'on' ? name.slice(2) : name;
1709
+ name = name === 'rightclick' ? 'contextmenu' : name;
1695
1710
  return name;
1696
1711
  },
1697
1712
 
@@ -1702,8 +1717,8 @@ var Event = new Class(Event, {
1702
1717
  * @return String real name
1703
1718
  */
1704
1719
  realName: function(name) {
1705
- if (Browser.Gecko && name == 'mousewheel') name = 'DOMMouseScroll';
1706
- if (Browser.Konqueror && name == 'contextmenu') name = 'rightclick';
1720
+ if (Browser.Gecko && name === 'mousewheel') name = 'DOMMouseScroll';
1721
+ if (Browser.Konqueror && name === 'contextmenu') name = 'rightclick';
1707
1722
  return name;
1708
1723
  },
1709
1724
 
@@ -1784,96 +1799,78 @@ Event.Custom = new Class({
1784
1799
  /**
1785
1800
  * The DOM Element unit handling
1786
1801
  *
1787
- * Credits:
1788
- * The basic principles of the elements extending are originated from
1789
- * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
1790
- *
1791
1802
  * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
1792
1803
  */
1793
- window.Element = new Class(window.Element, {
1804
+ self.Element = (function(old_Element) {
1805
+
1806
+ var new_Element = function(tag, options) {
1807
+ var element = document.createElement(tag), options = options || {};
1808
+
1809
+ if (options.id) { element.id = options.id; delete(options.id); }
1810
+ if (options.html) { element.innerHTML = options.html; delete(options.html); }
1811
+ if (options['class']) { element.className = options['class']; delete(options['class']); }
1812
+ if (options.style) { element.setStyle(options.style); delete(options.style); }
1813
+ if (options.observe) { element.observe(options.observe); delete(options.observe); }
1814
+
1815
+ for (var key in options) // a filter in case there is no keys in the options left
1816
+ return element.set(options);
1817
+ return element;
1818
+ };
1819
+
1820
+
1821
+ if (Browser.IE) {
1822
+ //
1823
+ // IE browsers have a bug with checked input elements
1824
+ // and we kinda hacking the Element constructor so that
1825
+ // it affected IE browsers only
1826
+ //
1827
+ new_Element = eval('({f:'+new_Element.toString().replace(/(\((\w+), (\w+)\) \{)/,
1828
+ '$1if($2=="input"&&$3&&$3.checked)$2="<input checked=true/>";'
1829
+ )+'})').f;
1830
+ }
1831
+
1832
+ // connecting the old Element instance to the new one for IE browsers
1833
+ if (old_Element) {
1834
+ $ext(new_Element, old_Element);
1835
+ new_Element.parent = old_Element;
1836
+ }
1837
+
1838
+ return new_Element;
1839
+ })(self.Element);
1840
+
1841
+
1842
+ $ext(Element, {
1794
1843
  /**
1795
- * basic constructor
1844
+ * registeres the methods on the custom element methods list
1845
+ * will add them to prototype and will generate a non extensive static mirror
1846
+ *
1847
+ * USAGE:
1848
+ * Element.addMethods({
1849
+ * foo: function(bar) {}
1850
+ * });
1796
1851
  *
1797
- * @param String tag name
1798
- * @param Object new element options
1799
- * @return Element object
1852
+ * $(element).foo(bar);
1853
+ * Element.foo(element, bar);
1854
+ *
1855
+ * @param Object new methods list
1856
+ * @param Boolean flag if the method should keep the existing methods alive
1857
+ * @return Element the global Element object
1800
1858
  */
1801
- initialize: function(tag_name, options) {
1802
- if (Browser.IE && tag_name == 'input' && options && options.checked) {
1803
- tag_name = '<input checked="true"/>';
1804
- }
1859
+ addMethods: function(methods, dont_overwrite) {
1860
+ $ext(this.Methods, methods, dont_overwrite);
1805
1861
 
1806
- var element = $(document.createElement(tag_name)), options = options || {};
1807
-
1808
- if (options['html']) { element.innerHTML = options['html']; delete(options['html']); }
1809
- if (options['class']) { element.className = options['class']; delete(options['class']); }
1810
- if (options['style']) { element.setStyle(options['style']); delete(options['style']); }
1811
- if (options['observe']) { element.observe(options['observe']); delete(options['observe']); }
1862
+ try { // busting up the basic element prototypes
1863
+ $ext(HTMLElement.prototype, methods, dont_overwrite);
1864
+ } catch(e) {
1865
+ try { // IE8 native element extension
1866
+ $ext(this.parent.prototype, methods, dont_overwrite);
1867
+ } catch(e) {}
1868
+ }
1812
1869
 
1813
- return element.set(options);
1870
+ return this;
1814
1871
  },
1815
1872
 
1816
- extend: {
1817
- Methods: {}, // DO NOT Extend this object manually unless you need it, use Element#addMethods
1818
-
1819
- /**
1820
- * IE browsers manual elements extending
1821
- *
1822
- * @param Element
1823
- * @return Element
1824
- */
1825
- prepare: function(element) {
1826
- if (element && element.tagName && !element.set) {
1827
- $ext(element, Element.Methods, true);
1828
-
1829
- if (self['Form']) {
1830
- switch(element.tagName) {
1831
- case 'FORM':
1832
- Form.ext(element);
1833
- break;
1834
-
1835
- case 'INPUT':
1836
- case 'SELECT':
1837
- case 'BUTTON':
1838
- case 'TEXTAREA':
1839
- Form.Element.ext(element);
1840
- break;
1841
- }
1842
- }
1843
- }
1844
- return element;
1845
- },
1846
-
1847
- /**
1848
- * registeres the methods on the custom element methods list
1849
- * will add them to prototype and will generate a non extensive static mirror
1850
- *
1851
- * USAGE:
1852
- * Element.addMethods({
1853
- * foo: function(bar) {}
1854
- * });
1855
- *
1856
- * $(element).foo(bar);
1857
- * Element.foo(element, bar);
1858
- *
1859
- * @param Object new methods list
1860
- * @param Boolean flag if the method should keep the existing methods alive
1861
- * @return Element the global Element object
1862
- */
1863
- addMethods: function(methods, dont_overwrite) {
1864
- $ext(this.Methods, methods, dont_overwrite);
1865
-
1866
- try { // busting up the basic element prototypes
1867
- $ext(HTMLElement.prototype, methods, dont_overwrite);
1868
- } catch(e) {
1869
- try { // IE8 native element extension
1870
- $ext(this.parent.prototype, methods, dont_overwrite);
1871
- } catch(e) {}
1872
- }
1873
-
1874
- return this;
1875
- }
1876
- }
1873
+ Methods: {} // DO NOT Extend this object manually unless you really need it, use Element#addMethods
1877
1874
  });
1878
1875
 
1879
1876
  /**
@@ -1929,14 +1926,6 @@ Element.addMethods({
1929
1926
  return this.prevSiblings(css_rule).first();
1930
1927
  },
1931
1928
 
1932
- // those two are moved to the Selector unit definition
1933
- // first: Element.Methods.querySelector,
1934
- // select: Element.Methods.querySelectorAll,
1935
-
1936
- match: function(css_rule) {
1937
- return new Selector(css_rule).match(this);
1938
- },
1939
-
1940
1929
  /**
1941
1930
  * removes the elemnt out of this parent node
1942
1931
  *
@@ -1973,7 +1962,7 @@ Element.addMethods({
1973
1962
  position = isString(position) ? position.toLowerCase() : 'bottom';
1974
1963
 
1975
1964
  if (isString(content)) {
1976
- content = content.stripScripts(function(s, h) { scripts = s; });
1965
+ content = content.stripScripts(function(s) { scripts = s; });
1977
1966
  }
1978
1967
 
1979
1968
  Element.insertions[position](this, content.tagName ? content :
@@ -1982,11 +1971,18 @@ Element.addMethods({
1982
1971
  this : this.parentNode, content
1983
1972
  )
1984
1973
  );
1985
- $eval(scripts);
1974
+ if (scripts) $eval(scripts);
1986
1975
  }
1987
1976
  return this;
1988
1977
  },
1989
1978
 
1979
+ /**
1980
+ * Inserts the element inside the given one at the given position
1981
+ *
1982
+ * @param mixed destination element reference
1983
+ * @param String optional position
1984
+ * @return Element this
1985
+ */
1990
1986
  insertTo: function(element, position) {
1991
1987
  $(element).insert(this, position);
1992
1988
  return this;
@@ -2010,8 +2006,9 @@ Element.addMethods({
2010
2006
  */
2011
2007
  update: function(content) {
2012
2008
  if (isString(content)) {
2013
- this.innerHTML = content.stripScripts();
2014
- content.evalScripts();
2009
+ var scripts = '';
2010
+ this.innerHTML = content.stripScripts(function(s) { scripts = s; });
2011
+ if (scripts) $eval(scripts);
2015
2012
  } else {
2016
2013
  this.clean().insert(content);
2017
2014
  }
@@ -2062,15 +2059,15 @@ Element.addMethods({
2062
2059
  * @return Array found elements
2063
2060
  */
2064
2061
  rCollect: function(attr, css_rule) {
2065
- var node = this, nodes = [];
2062
+ var node = this, result = [];
2066
2063
 
2067
2064
  while ((node = node[attr])) {
2068
- if (node.tagName && (!css_rule || new Selector(css_rule).match(node))) {
2069
- nodes.push(Browser.OLD ? Element.prepare(node) : node);
2065
+ if (node.tagName && (!css_rule || $(node).match(css_rule))) {
2066
+ result.push(node);
2070
2067
  }
2071
2068
  }
2072
-
2073
- return nodes;
2069
+ if (Browser.OLD) result.forEach(Element.prepare);
2070
+ return result;
2074
2071
  }
2075
2072
  });
2076
2073
 
@@ -2191,9 +2188,9 @@ Element.addMethods({
2191
2188
  for (var key in hash) {
2192
2189
  c_key = key.indexOf('-') != -1 ? key.camelize() : key;
2193
2190
 
2194
- if (key == 'opacity') {
2191
+ if (key === 'opacity') {
2195
2192
  this.setOpacity(hash[key]);
2196
- } else if (key == 'float') {
2193
+ } else if (key === 'float') {
2197
2194
  c_key = Browser.IE ? 'styleFloat' : 'cssFloat';
2198
2195
  }
2199
2196
 
@@ -2209,13 +2206,11 @@ Element.addMethods({
2209
2206
  * @param Float opacity value between 0 and 1
2210
2207
  * @return Element self
2211
2208
  */
2212
- setOpacity: function(value) {
2213
- var key = 'opacity';
2214
- if (Browser.IE) {
2215
- key = 'filter';
2216
- value = 'alpha(opacity='+ value * 100 +')';
2217
- }
2218
- this.style[key] = value;
2209
+ setOpacity: Browser.IE ? function(value) {
2210
+ this.style.filter = 'alpha(opacity='+ value * 100 +')';
2211
+ return this;
2212
+ } : function(value) {
2213
+ this.style.opacity = value;
2219
2214
  return this;
2220
2215
  },
2221
2216
 
@@ -2248,30 +2243,18 @@ Element.addMethods({
2248
2243
  switch (key) {
2249
2244
  case 'opacity':
2250
2245
  value = !Browser.IE ? style[key] :
2251
- (((style['filter'] || '').match(/opacity=(\d+)/i) || ['', '100'])[1].toInt() / 100)+'';
2246
+ ((/opacity=(\d+)/i.exec(style.filter || '') || ['', '100'])[1].toInt() / 100)+'';
2252
2247
  break;
2253
2248
 
2254
2249
  case 'float':
2255
- key = Browser.IE ? 'styleFloat' : 'cssFloat';
2250
+ key = Browser.IE ? 'styleFloat' : 'cssFloat';
2256
2251
 
2257
2252
  default:
2258
- if (style[key]) {
2259
- value = style[key];
2260
- } else {
2261
- var values = $w('top right bottom left').map(function(name) {
2262
- var tokens = key.underscored().split('_'); tokens.splice(1, 0, name);
2263
- return style[tokens.join('_').camelize()];
2264
- }).uniq();
2265
-
2266
- if (values.length == 1) {
2267
- value = values[0];
2268
- }
2269
- }
2253
+ value = style[key];
2270
2254
 
2271
2255
  // Opera returns named colors with quotes
2272
- if (value && Browser.Opera && /color/.test(key)) {
2273
- var match = value.match(/"(.+?)"/);
2274
- value = match ? match[1] : value;
2256
+ if (Browser.Opera && /color/i.test(key) && value) {
2257
+ value = value.replace(/"/g, '');
2275
2258
  }
2276
2259
  }
2277
2260
 
@@ -2285,7 +2268,7 @@ Element.addMethods({
2285
2268
  * @return boolean check result
2286
2269
  */
2287
2270
  hasClass: function(name) {
2288
- return (' '+this.className+' ').indexOf(' '+name+' ') != -1;
2271
+ return (' '+this.className+' ').indexOf(' '+name+' ') !== -1;
2289
2272
  },
2290
2273
 
2291
2274
  /**
@@ -2306,8 +2289,9 @@ Element.addMethods({
2306
2289
  * @return Element self
2307
2290
  */
2308
2291
  addClass: function(name) {
2309
- if ((' '+this.className+' ').indexOf(' '+name+' ') == -1) {
2310
- this.className += (this.className ? ' ' : '') + name;
2292
+ var testee = ' '+this.className+' ';
2293
+ if (testee.indexOf(' '+name+' ') === -1) {
2294
+ this.className += (testee === ' ' ? '' : ' ') + name;
2311
2295
  }
2312
2296
  return this;
2313
2297
  },
@@ -2365,9 +2349,14 @@ Element.addMethods({
2365
2349
  */
2366
2350
  set: function(hash, value) {
2367
2351
  if (value) { var val = {}; val[hash] = value; hash = val; }
2368
-
2369
- for (var key in hash)
2352
+
2353
+ for (var key in hash) {
2354
+ // some attributes are not available as properties
2355
+ if (this[key] === undefined) {
2356
+ this.setAttribute(key, ''+hash[key]);
2357
+ }
2370
2358
  this[key] = hash[key];
2359
+ }
2371
2360
 
2372
2361
  return this;
2373
2362
  },
@@ -2379,7 +2368,7 @@ Element.addMethods({
2379
2368
  * @return mixed value
2380
2369
  */
2381
2370
  get: function(name) {
2382
- var value = this.getAttribute(name) || this[name];
2371
+ var value = this[name] || this.getAttribute(name);
2383
2372
  return value == '' ? null : value;
2384
2373
  },
2385
2374
 
@@ -2482,16 +2471,36 @@ Element.addMethods({
2482
2471
  * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
2483
2472
  */
2484
2473
  Element.addMethods({
2485
-
2474
+ /**
2475
+ * Returns the element sizes as a hash
2476
+ *
2477
+ * @return Object {x: NNN, y: NNN}
2478
+ */
2486
2479
  sizes: function() {
2487
2480
  return { x: this.offsetWidth, y: this.offsetHeight };
2488
2481
  },
2489
2482
 
2483
+ /**
2484
+ * Returns the element absolute position
2485
+ *
2486
+ * NOTE: see the konq.js file for the manual version of the method
2487
+ *
2488
+ * @return Object {x: NNN, y: NNN}
2489
+ */
2490
2490
  position: function() {
2491
- var dims = this.dimensions();
2492
- return { x: dims.left, y: dims.top };
2491
+ var rect = this.getBoundingClientRect(), doc = this.ownerDocument.documentElement, scrolls = window.scrolls();
2492
+
2493
+ return {
2494
+ x: rect.left + scrolls.x - doc.clientLeft,
2495
+ y: rect.top + scrolls.y - doc.clientTop
2496
+ };
2493
2497
  },
2494
2498
 
2499
+ /**
2500
+ * Returns the element scrolls
2501
+ *
2502
+ * @return Object {x: NNN, y: NNN}
2503
+ */
2495
2504
  scrolls: function() {
2496
2505
  return { x: this.scrollLeft, y: this.scrollTop };
2497
2506
  },
@@ -2502,33 +2511,17 @@ Element.addMethods({
2502
2511
  * @return Object dimensions (top, left, width, height, scrollLeft, scrollTop)
2503
2512
  */
2504
2513
  dimensions: function() {
2505
- var left = 0, top = 0;
2506
-
2507
- if (this.getBoundingClientRect) {
2508
- var rect = this.getBoundingClientRect(), doc = this.ownerDocument.documentElement, scrolls = window.scrolls();
2509
-
2510
- left = rect.left + scrolls.x - doc.clientLeft;
2511
- top = rect.top + scrolls.y - doc.clientTop;
2512
- } else {
2513
- // Manual version
2514
- left = this.offsetLeft;
2515
- top = this.offsetTop;
2516
-
2517
- if (this.getStyle('position') != 'absolute') {
2518
- var body = this.ownerDocument.body, html = body.parentNode;
2519
-
2520
- left += body.offsetLeft + html.offsetLeft;
2521
- top += body.offsetTop + html.offsetTop;
2522
- }
2523
- }
2514
+ var sizes = this.sizes();
2515
+ var scrolls = this.scrolls();
2516
+ var position = this.position();
2524
2517
 
2525
2518
  return {
2526
- top: top,
2527
- left: left,
2528
- width: this.sizes().x,
2529
- height: this.sizes().y,
2530
- scrollLeft: this.scrolls().x,
2531
- scrollTop: this.scrolls().y
2519
+ top: position.y,
2520
+ left: position.x,
2521
+ width: sizes.x,
2522
+ height: sizes.y,
2523
+ scrollLeft: scrolls.x,
2524
+ scrollTop: scrolls.y
2532
2525
  };
2533
2526
  },
2534
2527
 
@@ -2641,38 +2634,41 @@ Element.addMethods((function() {
2641
2634
  $w('click rightclick contextmenu mousedown mouseup mouseover mouseout mousemove keypress keydown keyup')
2642
2635
  );
2643
2636
 
2644
- observer.$o = {
2645
- add: function(hash) {
2646
- var callback = hash.f, args = hash.a;
2647
- hash.e = Event.cleanName(hash.e);
2648
- hash.n = Event.realName(hash.e);
2637
+ //
2638
+ // HACK HACK HACK
2639
+ //
2640
+ // I'm kinda patching the observer methods manually in here
2641
+ // the reason is in building flat and fast functions
2642
+ //
2643
+ observer.observe = observer.on = eval('({f:'+
2644
+ observer.observe.toString().replace(/(\$listeners\.push\((\w+?)\);)/, '$1'+
2645
+ '$2.e=Event.cleanName($2.e);$2.n=Event.realName($2.e);'+
2649
2646
 
2650
- hash.w = function() {
2651
- Event.ext(arguments[0]);
2652
- return callback.apply(this, $A(arguments).concat(args));
2653
- };
2647
+ '$2.w=function(){Event.ext(arguments[0]);'+
2648
+ 'return $2.f.apply(this,$A(arguments).concat($2.a));};'+(
2654
2649
 
2655
- if (this.addEventListener) {
2656
- this.addEventListener(hash.n, hash.w, false);
2657
- } else {
2658
- hash.w = hash.w.bind(this);
2659
- this.attachEvent('on'+ hash.n, hash.w);
2660
- }
2661
- },
2662
-
2663
- remove: function(hash) {
2664
- if (this.removeEventListener) {
2665
- this.removeEventListener(hash.n, hash.w, false);
2666
- } else {
2667
- this.detachEvent('on'+ hash.n, hash.w);
2668
- }
2669
- },
2670
-
2671
- fire: function(name, args, hash) {
2672
- var event = new Event(name, args.shift());
2673
- hash.f.apply(this, [event].concat(hash.a).concat(args));
2674
- }
2675
- };
2650
+ self.attachEvent ?
2651
+ '$2.w=$2.w.bind(this);this.attachEvent("on"+$2.n,$2.w);' :
2652
+ 'this.addEventListener($2.n,$2.w,false);'
2653
+ )
2654
+ )+
2655
+ '})').f;
2656
+
2657
+ observer.stopObserving = eval('({f:'+
2658
+ observer.stopObserving.toString().replace(/(function\s*\((\w+)\)\s*\{\s*)(return\s*)([^}]+)/m,
2659
+ '$1var r=$4;'+
2660
+ 'if(!r)' + (self.attachEvent ?
2661
+ 'this.detachEvent("on"+$2.n,$2.w);' :
2662
+ 'this.removeEventListener($2.n,$2.w,false);'
2663
+ )+'$3 r')+
2664
+ '})').f;
2665
+
2666
+
2667
+ observer.fire = eval('({f:'+
2668
+ observer.fire.toString().replace(/(\w+)\.f\.apply.*?\.concat\((\w+)\)[^}]/,
2669
+ '$1.f.apply(this,[new Event($1.e,$2.shift())].concat($1.a).concat($2))'
2670
+ )+
2671
+ '})').f;
2676
2672
 
2677
2673
  // a simple events terminator method to be hooked like
2678
2674
  // this.onClick('stopEvent');
@@ -2686,599 +2682,76 @@ Element.addMethods((function() {
2686
2682
 
2687
2683
 
2688
2684
  /**
2689
- * The DOM elements selection handling class
2685
+ * The DOM elements selection handling
2690
2686
  *
2691
- * Credits:
2692
- * The naming principles of the unit are inspired by
2693
- * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
2687
+ * NOTE: this module is just a wrap over the native CSS-selectors feature
2688
+ * see the olds/css.js file for the manual selector code
2694
2689
  *
2695
2690
  * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
2696
2691
  */
2697
-
2698
- // checking, monkeying and hooking the native css-selectors interface
2699
- // IE8 W3C
2700
- [document, (Element.parent || self['HTMLElement'] || {}.constructor).prototype].each(function(object, i) {
2701
- var old_selector = object.querySelector;
2702
- var old_selector_all = object.querySelectorAll;
2703
-
2704
- // the native selectors checking/monkeying
2705
- var selectors = {};
2706
- if (!old_selector) selectors.querySelector = function(css_rule) {
2707
- return new Selector(css_rule).first(this);
2708
- };
2709
- if (!old_selector_all) selectors.querySelectorAll = function(css_rule) {
2710
- return new Selector(css_rule).select(this);
2711
- };
2712
-
2713
- // RightJS version of the selectors
2714
- selectors.first = old_selector ? i ? function(css_rule) {
2715
- return this.querySelector(this.tagName + ' ' + (css_rule || '*'));
2716
- } : function(css_rule) {
2717
- return this.querySelector(css_rule || '*');
2718
- } : selectors.querySelector;
2719
-
2720
- selectors.select = old_selector_all ? i ? function(css_rule) {
2721
- return $A(this.querySelectorAll(this.tagName + ' ' + (css_rule || '*')));
2722
- } : function(css_rule) {
2723
- return $A(this.querySelectorAll(css_rule || '*'));
2724
- } : selectors.querySelectorAll;
2725
-
2726
- return i ? Element.addMethods(selectors) : $ext(object, selectors);
2727
- });
2728
-
2729
-
2730
- var Selector = new Class({
2731
- extend: {
2732
- cache: {}
2733
- },
2734
-
2692
+ Element.addMethods((function() {
2735
2693
  /**
2736
- * constructor
2737
- *
2738
- * @param String css rule definition
2739
- * @return void
2694
+ * Native css-selectors include the current element into the search context
2695
+ * and as we actually search only inside of the element we add it's tag
2696
+ * as a scope for the search
2740
2697
  */
2741
- initialize: function(css_rule) {
2742
- var cached = isString(css_rule) ? Selector.cache[css_rule] : css_rule;
2743
- if (cached) return cached;
2744
- Selector.cache[css_rule] = this;
2745
-
2746
- this.cssRule = css_rule || '*';
2747
-
2748
- var strategy = 'Manual';
2749
- if (this.cssRule.includes(',')) {
2750
- strategy = 'Multiple';
2751
- }
2752
-
2753
- this.strategy = new Selector[strategy](this.cssRule);
2754
- },
2698
+ var stub_rule = function(css_rule, tag) {
2699
+ return css_rule ? css_rule.replace(/(^|,)/g, '$1'+ tag + ' ') : '*';
2700
+ };
2755
2701
 
2702
+ return {
2756
2703
  /**
2757
- * selects the first matching element which is a sub node of the given element
2758
- * and matches the selector's css-rule
2704
+ * Extracts the first element matching the css-rule,
2705
+ * or just any first element if no css-rule was specified
2759
2706
  *
2760
- * @param Element element
2761
- * @return Element matching element or null if nothing found
2707
+ * @param String css-rule
2708
+ * @return Element matching node or null
2762
2709
  */
2763
- first: Browser.OLD ? function(element) {
2764
- var element = this.strategy.first(element);
2765
- return element ? $(element) : null;
2766
- } : function(element) {
2767
- return this.strategy.first(element);
2710
+ first: function(css_rule) {
2711
+ return this.querySelector(stub_rule(css_rule, this.tagName));
2768
2712
  },
2769
2713
 
2770
2714
  /**
2771
- * select all the subnodes of the element which are matching the rule
2715
+ * Selects a list of matching nodes, or all the descendant nodes if no css-rule provided
2772
2716
  *
2773
- * @param Element element
2774
- * @return Array list of found nodes
2717
+ * @param String css-rule
2718
+ * @return Array of elements
2775
2719
  */
2776
- select: Browser.OLD ? function(element) {
2777
- return this.strategy.select(element).map(Element.prepare);
2778
- } : function(element) {
2779
- return this.strategy.select(element);
2720
+ select: function(css_rule) {
2721
+ return $A(this.querySelectorAll(stub_rule(css_rule, this.tagName)));
2780
2722
  },
2781
2723
 
2782
2724
  /**
2783
- * checks if the element matches the rule
2725
+ * checks if the element matches this css-rule
2784
2726
  *
2785
- * @param Element element
2786
- * @return Boolean check result
2787
- */
2788
- match: function(element) {
2789
- return this.strategy.match(element);
2790
- }
2791
- });
2792
-
2793
-
2794
- /**
2795
- * this class represent a simple css-definition atom unit
2796
- *
2797
- * the main purpose is to organize the simpliest case of css-rule match for the manual matcher.
2798
- *
2799
- * Credits:
2800
- * Some functionality and principles are inspired by css-selectors in
2801
- * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
2802
- *
2803
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
2804
- */
2805
- Selector.Atom = new Class({
2806
- id: null,
2807
- tag: '*',
2808
- classes: [],
2809
- pseudo: null,
2810
- pseudoValue: null,
2811
- attrs: {},
2812
-
2813
- rel: ' ', // relations with the previous atom
2814
-
2815
- ID_RE: /#([\w\-_]+)/,
2816
- TAG_RE: /^[\w\*]+/,
2817
- CLASS_RE: /\.([\w\-\._]+)/,
2818
- PSEUDO_RE: /:([\w\-]+)(\((.+?)\))*$/,
2819
- ATTRS_RE: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/,
2820
-
2821
- /**
2822
- * constructor
2823
- *
2824
- * @param String css-definition
2825
- * @param String relation with the previous atom
2826
- * @return void
2827
- */
2828
- initialize: function(css_rule, rel) {
2829
- css_rule = css_rule.trim();
2830
- this.rel = rel || ' ';
2831
- this.hasNonTagMatcher = !/^[a-z\*]+$/.test(css_rule);
2832
-
2833
- // NOTE! dont change the order of the atom parsing, there might be collisions
2834
- this.attrs = {};
2835
- while((m = css_rule.match(this.ATTRS_RE))) {
2836
- this.attrs[m[1]] = { op: m[2], value: m[5] || m[6] };
2837
- css_rule = css_rule.replace(m[0], '');
2838
- }
2839
-
2840
- if ((m = css_rule.match(this.PSEUDO_RE))) {
2841
- this.pseudo = m[1];
2842
- this.pseudoValue = m[3] == '' ? null : m[3];
2843
- css_rule = css_rule.replace(m[0], '');
2844
- } else {
2845
- this.pseudo = null;
2846
- this.pseudoValue = null;
2847
- }
2848
-
2849
- this.id = (css_rule.match(this.ID_RE) || [1, null])[1];
2850
- this.tag = (css_rule.match(this.TAG_RE) || '*').toString().toUpperCase();
2851
- this.classes = (css_rule.match(this.CLASS_RE) || [1, ''])[1].split('.').without('');
2852
-
2853
- this.buildMatch();
2854
- },
2855
-
2856
- /**
2857
- * cecks if the node matches the atom
2858
- *
2859
- * @param Element element
2727
+ * @param String css-rule
2860
2728
  * @return Boolean check result
2861
2729
  */
2862
- match: null, // this method is dinamically generated depend on the situation
2863
-
2864
- // protected
2865
-
2866
- // building the match method for the particular case
2867
- buildMatch: function() {
2868
- var matchers = [];
2869
-
2870
- if (this.id) matchers.push('matchId');
2871
- if (this.tag != '*') matchers.push('matchTag');
2872
- if (this.classes.length) matchers.push('matchClass');
2873
- if (!Object.empty(this.attrs)) matchers.push('matchAttrs');
2874
- if (this.pseudo) matchers.push('matchPseudo');
2875
-
2876
- if (matchers.length == 1) {
2877
- this.match = this[matchers[0]];
2878
- } else if (matchers.length) {
2879
- var length = matchers.length;
2880
- this.match = function(element) {
2881
- for (var i=0; i < length; i++)
2882
- if (!this[matchers[i]](element))
2883
- return false;
2884
- return true;
2885
- }
2886
- } else {
2887
- this.match = function() { return true; }
2888
- }
2889
- },
2890
-
2891
- matchId: function(element) {
2892
- return element.id == this.id;
2893
- },
2894
-
2895
- matchTag: function(element) {
2896
- return element.tagName == this.tag;
2897
- },
2898
-
2899
- matchClass: function(element) {
2900
- if (element.className) {
2901
- var names = element.className.split(' ');
2902
- if (names.length == 1) {
2903
- return this.classes.indexOf(names[0]) != -1;
2904
- } else {
2905
- for (var i=0, length = this.classes.length; i < length; i++)
2906
- if (names.indexOf(this.classes[i]) == -1)
2907
- return false;
2908
-
2909
- return true;
2910
- }
2911
- }
2912
- return false;
2913
- },
2914
-
2915
- matchAttrs: function(element) {
2916
- var matches = true;
2917
- for (var key in this.attrs) {
2918
- matches &= this.matchAttr(element, key, this.attrs[key]['op'], this.attrs[key]['value']);
2919
- }
2920
- return matches;
2921
- },
2922
-
2923
- matchAttr: function(element, name, operator, value) {
2924
- var attr = element.getAttribute(name) || '';
2925
- switch(operator) {
2926
- case '=': return attr == value;
2927
- case '*=': return attr.includes(value);
2928
- case '^=': return attr.startsWith(value);
2929
- case '$=': return attr.endsWith(value);
2930
- case '~=': return attr.split(' ').includes(value);
2931
- case '|=': return attr.split('-').includes(value);
2932
- default: return attr != '';
2933
- }
2934
- return false;
2935
- },
2936
-
2937
- matchPseudo: function(element) {
2938
- return this.pseudoMatchers[this.pseudo].call(element, this.pseudoValue, this.pseudoMatchers);
2939
- },
2940
-
2941
- /**
2942
- * W3C pseudo matchers
2943
- *
2944
- * NOTE: methods of the module will be called in a context of an element
2945
- */
2946
- pseudoMatchers: {
2947
- checked: function() {
2948
- return this.checked;
2949
- },
2950
-
2951
- disabled: function() {
2952
- return this.disabled;
2953
- },
2954
-
2955
- empty: function() {
2956
- return !(this.innerText || this.innerHTML || this.textContent || '').length;
2957
- },
2958
-
2959
- 'first-child': function(tag_name) {
2960
- var node = this;
2961
- while ((node = node.previousSibling)) {
2962
- if (node.tagName && (!tag_name || node.tagName == tag_name)) {
2963
- return false;
2964
- }
2965
- }
2966
- return true;
2967
- },
2968
-
2969
- 'first-of-type': function() {
2970
- return arguments[1]['first-child'].call(this, this.tagName);
2971
- },
2972
-
2973
- 'last-child': function(tag_name) {
2974
- var node = this;
2975
- while ((node = node.nextSibling)) {
2976
- if (node.tagName && (!tag_name || node.tagName == tag_name)) {
2977
- return false;
2978
- }
2979
- }
2980
- return true;
2981
- },
2730
+ match: function(css_rule) {
2731
+ if (!css_rule || css_rule == '*') return true;
2982
2732
 
2983
- 'last-of-type': function() {
2984
- return arguments[1]['last-child'].call(this, this.tagName);
2985
- },
2986
-
2987
- 'only-child': function(tag_name, matchers) {
2988
- return matchers['first-child'].call(this, tag_name)
2989
- && matchers['last-child'].call(this, tag_name);
2990
- },
2733
+ var fake, result, parent, parents = this.parents();
2991
2734
 
2992
- 'only-of-type': function() {
2993
- return arguments[1]['only-child'].call(this, this.tagName, arguments[1]);
2994
- },
2995
-
2996
- 'nth-child': function(number, matchers, tag_name) {
2997
- if (!matchers.hasParent(this)) return false;
2998
- number = number.toLowerCase();
2999
-
3000
- if (number == 'n') return true;
3001
-
3002
- if (number.includes('n')) {
3003
- // parsing out the matching expression
3004
- var a = b = 0;
3005
- if (m = number.match(/^([+-]?\d*)?n([+-]?\d*)?$/)) {
3006
- a = m[1] == '-' ? -1 : parseInt(m[1], 10) || 1;
3007
- b = parseInt(m[2], 10) || 0;
3008
- }
3009
-
3010
- // getting the element index
3011
- var index = 1, node = this;
3012
- while ((node = node.previousSibling)) {
3013
- if (node.tagName && (!tag_name || node.tagName == tag_name)) index++;
3014
- }
3015
-
3016
- return (index - b) % a == 0 && (index - b) / a >= 0;
3017
-
3018
- } else {
3019
- return matchers['index'].call(this, number.toInt() - 1, matchers, tag_name);
3020
- }
3021
- },
2735
+ parent = parents.length ? parents.last() : fake = $E('div').insert(this);
2736
+ result = parent.select(css_rule).include(this);
3022
2737
 
3023
- 'nth-of-type': function(number) {
3024
- return arguments[1]['nth-child'].call(this, number, arguments[1], this.tagName);
3025
- },
2738
+ if (fake) { this.remove(); }
3026
2739
 
3027
- // protected
3028
- index: function(number, matchers, tag_name) {
3029
- number = isString(number) ? number.toInt() : number;
3030
- var node = this, count = 0;
3031
- while ((node = node.previousSibling)) {
3032
- if (node.tagName && (!tag_name || node.tagName == tag_name) && ++count > number) return false;
3033
- }
3034
- return count == number;
3035
- },
3036
-
3037
- // checking if the element has a parent node
3038
- // the '-----fake' parent is a temporary context for the element
3039
- // just of the matching process
3040
- hasParent: function(element) {
3041
- return element.parentNode && element.parentNode.id != '-----fake';
3042
- }
2740
+ return result;
3043
2741
  }
3044
- });
2742
+ }})());
3045
2743
 
3046
- /**
3047
- * represents a manual (virtual) selector strategy
3048
- *
3049
- * Credits:
3050
- * Some principles were inspired by
3051
- * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
3052
- * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
3053
- *
3054
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
3055
- */
3056
- Selector.Manual = new Class({
3057
- ATOMS_SPLIT_RE: /(\s*([~>+ ])\s*)(?![^\s\)\]]*(\)|\]))/,
3058
-
3059
- /**
3060
- * constructor
3061
- *
3062
- * @param String css-rule
3063
- */
3064
- initialize: function(css_rule) {
3065
- var css_rule = css_rule.trim();
3066
- this.cssRule = css_rule;
3067
-
3068
- this.atoms = [];
3069
-
3070
- var relation = null, match = null;
3071
-
3072
- while (match = css_rule.match(this.ATOMS_SPLIT_RE)) {
3073
- separator_pos = css_rule.indexOf(match[0]);
3074
- this.atoms.push(new Selector.Atom(css_rule.substring(0, separator_pos), relation));
3075
-
3076
- relation = match[2]; // <- puts the current relation to the next atom
3077
-
3078
- // chopping off the first atom of the rule
3079
- css_rule = css_rule.substr(separator_pos+(match[1].length==1 ? 1 : match[1].length-1)).trim();
3080
- }
3081
- this.atoms.push(new Selector.Atom(css_rule, relation));
3082
- },
3083
-
3084
- /**
3085
- * searches for the first matching subnode
3086
- *
3087
- * @param Element base node
3088
- * @return Element matching element or null if nothing found
3089
- */
3090
- first: function(node) {
3091
- return this.select(node).first();
3092
- },
3093
-
3094
- /**
3095
- * selects all the matching subnodes
3096
- *
3097
- * @param Element base node
3098
- * @return Array found nodes
3099
- */
3100
- select: function(node) {
3101
- var founds, atom, index, sub_founds;
3102
-
3103
- for (var i=0, i_length = this.atoms.length; i < i_length; i++) {
3104
- atom = this.atoms[i];
3105
- if (i == 0) {
3106
- founds = this.find[atom.rel](node, atom);
3107
-
3108
- } else {
3109
- if (i > 1) founds = this.uniq(founds);
3110
-
3111
- for (var j=0; j < founds.length; j++) {
3112
- sub_founds = this.find[atom.rel](founds[j], atom);
3113
-
3114
- sub_founds.unshift(1); // <- nuke the parent node out of the list
3115
- sub_founds.unshift(j); // <- position to insert the subresult
3116
-
3117
- founds.splice.apply(founds, sub_founds);
3118
-
3119
- j += sub_founds.length - 3;
3120
- }
3121
- }
3122
- }
3123
-
3124
- return this.atoms.length > 1 ? this.uniq(founds) : founds;
3125
- },
3126
-
3127
- /**
3128
- * checks if the node matches the rule
3129
- *
3130
- * @param Element node to check
3131
- * @return boolean check result
3132
- */
3133
- match: function(element) {
3134
- // if there's more than one atom, we match the element in a context
3135
- if (!this.atoms || this.atoms.length > 1) {
3136
- if (element.parentNode) {
3137
- // searching for the top parent node
3138
- // NOTE: don't use the Element.parents in here to avoid annecessary elements extending
3139
- var p = element, parent;
3140
- while ((p = p.parentNode)) parent = p;
3141
- } else {
3142
- // putting the element in a temporary context so we could test it
3143
- var parent = document.createElement('div'), parent_is_fake = true;
3144
- parent.id = '-----fake'; // <- this id is used in the manual 'match' method,
3145
- // to determine if the element originally had no parent node
3146
- parent.appendChild(element);
3147
- }
3148
-
3149
- var match = this.select(parent).includes(element);
3150
- if (parent_is_fake) parent.removeChild(element);
3151
- } else {
3152
- // if there's just one atom, we simple match against it.
3153
- var match = this.atoms[0].match(element);
3154
- }
3155
-
3156
- return match;
3157
- },
3158
-
3159
- // protected
3160
- uniq: function(elements) {
3161
- var uniq = [], uids = [], uid;
3162
- for (var i=0, length = elements.length; i < length; i++) {
3163
- uid = $uid(elements[i]);
3164
- if (!uids[uid]) {
3165
- uniq.push(elements[i]);
3166
- uids[uid] = true;
3167
- }
3168
- }
3169
-
3170
- return uniq;
2744
+ // document-level hooks
2745
+ $ext(document, {
2746
+ first: function(css_rule) {
2747
+ return this.querySelector(css_rule || '*');
3171
2748
  },
3172
-
3173
- find: {
3174
- /**
3175
- * search for any descendant nodes
3176
- */
3177
- ' ': function(element, atom) {
3178
- var founds = $A(element.getElementsByTagName(atom.tag));
3179
- if (atom.hasNonTagMatcher) {
3180
- var matching = [];
3181
- for (var i=0, length = founds.length; i < length; i++) {
3182
- if (atom.match(founds[i]))
3183
- matching.push(founds[i]);
3184
- }
3185
- return matching;
3186
- }
3187
- return founds;
3188
- },
3189
-
3190
- /**
3191
- * search for immidate descendant nodes
3192
- */
3193
- '>': function(element, atom) {
3194
- var node = element.firstChild, matched = [];
3195
- while (node) {
3196
- if (atom.match(node)) {
3197
- matched.push(node);
3198
- }
3199
- node = node.nextSibling;
3200
- }
3201
- return matched;
3202
- },
3203
-
3204
- /**
3205
- * search for immiate sibling nodes
3206
- */
3207
- '+': function(element, atom) {
3208
- while ((element = element.nextSibling)) {
3209
- if (element.tagName) {
3210
- return atom.match(element) ? [element] : [];
3211
- }
3212
- }
3213
- return [];
3214
- },
3215
-
3216
- /**
3217
- * search for late sibling nodes
3218
- */
3219
- '~': function(element, atom) {
3220
- var founds = [];
3221
- while ((element = element.nextSibling)) {
3222
- if (atom.match(element))
3223
- founds.push(element);
3224
- }
3225
- return founds;
3226
- }
3227
- }
3228
-
3229
- });
3230
-
3231
- /**
3232
- * represents a complex, multi ruled select strategy
3233
- *
3234
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
3235
- */
3236
- Selector.Multiple = new Class({
3237
2749
 
3238
- /**
3239
- * constructor
3240
- *
3241
- * @param String css-rule
3242
- */
3243
- initialize: function(css_rule) {
3244
- this.cssRule = css_rule;
3245
- this.selectors = css_rule.split(',').map(function(rule) {
3246
- return rule.blank() ? null : new Selector.Manual(rule);
3247
- }).compact();
3248
- },
3249
-
3250
- /**
3251
- * searches for the first matching subnode
3252
- *
3253
- * @param Element base node
3254
- * @return Element matching element or null if nothing found
3255
- */
3256
- first: function(node) {
3257
- return this.selectors.map('first', node).first(function(i) { return !!i;});
3258
- },
3259
-
3260
- /**
3261
- * selects all the matching subnodes
3262
- *
3263
- * @param Element base node
3264
- * @return Array found nodes
3265
- */
3266
- select: function(node) {
3267
- return this.selectors.map('select', node, null).flatten().uniq();
3268
- },
3269
-
3270
- /**
3271
- * checks if the node matches the rule
3272
- *
3273
- * @param Element node to check
3274
- * @return boolean check result
3275
- */
3276
- match: function(node) {
3277
- return this.selectors.some('match', node) || !this.selectors.length;
2750
+ select: function(css_rule) {
2751
+ return $A(this.querySelectorAll(css_rule || '*'));
3278
2752
  }
3279
2753
  });
3280
2754
 
3281
-
3282
2755
  /**
3283
2756
  * the window object extensions
3284
2757
  *
@@ -3348,20 +2821,10 @@ return {
3348
2821
  Observer.createShortcuts(object, ['ready']);
3349
2822
  var ready = object.ready.bind(object);
3350
2823
 
3351
- if (Browser.IE) {
3352
- var tmp = $E('div');
2824
+ // IE and Konqueror browsers
2825
+ if (document.readyState !== undefined) {
3353
2826
  (function() {
3354
- var loaded = false;
3355
- try {
3356
- document.body.appendChild(tmp);
3357
- tmp.remove();
3358
- loaded = true;
3359
- } catch(e) { arguments.callee.delay(50);}
3360
- if (loaded) ready();
3361
- })();
3362
- } else if (document['readyState'] !== undefined) {
3363
- (function() {
3364
- $w('loaded complete').includes(document.readyState) ? ready() : arguments.callee.delay(50);
2827
+ ['loaded','complete'].includes(document.readyState) ? ready() : arguments.callee.delay(50);
3365
2828
  })();
3366
2829
  } else {
3367
2830
  document.addEventListener('DOMContentLoaded', ready, false);
@@ -3378,47 +2841,40 @@ return {
3378
2841
  *
3379
2842
  * Copyright (C) 2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
3380
2843
  */
3381
- var Form = new Class(Element, {
2844
+ var Form = function(options) {
2845
+ var options = options || {}, remote = options['remote'],
2846
+ form = new Element('form', Object.without(options, 'remote'));
2847
+
2848
+ if (remote) form.remotize();
2849
+
2850
+ return form;
2851
+ };
2852
+
2853
+ $ext(Form, {
3382
2854
  /**
3383
- * generic forms creation constructor
2855
+ * IE browsers manual elements extending
3384
2856
  *
3385
- * @param Object form options
2857
+ * @param Element form
2858
+ * @return Form element
3386
2859
  */
3387
- initialize: function(options) {
3388
- var options = options || {}, remote = options['remote'],
3389
- form = this.$super('form', Object.without(options, 'remote'));
3390
-
3391
- if (remote) form.remotize();
3392
-
3393
- return form;
2860
+ ext: function(element) {
2861
+ return $ext(element, this.Methods);
3394
2862
  },
3395
2863
 
3396
- extend: {
3397
- /**
3398
- * IE browsers manual elements extending
3399
- *
3400
- * @param Element form
3401
- * @return Form element
3402
- */
3403
- ext: function(element) {
3404
- return $ext(element, this.Methods);
3405
- },
3406
-
3407
- Methods: {},
2864
+ Methods: {},
2865
+
2866
+ /**
2867
+ * Extends the form functionality
2868
+ *
2869
+ * @param Object methods hash
2870
+ * @return void
2871
+ */
2872
+ addMethods: function(methods, dont_overwrite) {
2873
+ $ext(Form.Methods, methods, dont_overwrite);
3408
2874
 
3409
- /**
3410
- * Extends the form functionality
3411
- *
3412
- * @param Object methods hash
3413
- * @return void
3414
- */
3415
- addMethods: function(methods, dont_overwrite) {
3416
- $ext(Form.Methods, methods, dont_overwrite);
3417
-
3418
- try { // trying to extend the form element prototype
3419
- $ext(HTMLFormElement.prototype, methods, dont_overwrite);
3420
- } catch(e) {}
3421
- }
2875
+ try { // trying to extend the form element prototype
2876
+ $ext(HTMLFormElement.prototype, methods, dont_overwrite);
2877
+ } catch(e) {}
3422
2878
  }
3423
2879
  });
3424
2880
 
@@ -3781,7 +3237,7 @@ var Xhr = new Class(Observer, {
3781
3237
  Options: {
3782
3238
  headers: {
3783
3239
  'X-Requested-With': 'XMLHttpRequest',
3784
- 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
3240
+ 'Accept': 'text/javascript,text/html,application/xml,text/xml,*/*'
3785
3241
  },
3786
3242
  method: 'post',
3787
3243
  encoding: 'utf-8',
@@ -3793,7 +3249,8 @@ var Xhr = new Class(Observer, {
3793
3249
  urlEncoded: true,
3794
3250
  spinner: null,
3795
3251
  spinnerFx: 'fade',
3796
- params: null
3252
+ params: null,
3253
+ iframed: false
3797
3254
  },
3798
3255
 
3799
3256
  /**
@@ -3866,21 +3323,20 @@ var Xhr = new Class(Observer, {
3866
3323
  * @return Xhr self
3867
3324
  */
3868
3325
  send: function(params) {
3869
- var add_params = {}, url = this.url;
3326
+ var add_params = {}, url = this.url, method = this.method.toLowerCase();
3870
3327
 
3871
- var method = this.method.toUpperCase();
3872
- if (['PUT', 'DELETE'].includes(method)) {
3873
- add_params['_method'] = method.toLowerCase();
3874
- method = 'POST';
3328
+ if (method == 'put' || method == 'delete') {
3329
+ add_params['_method'] = method;
3330
+ method = 'post';
3875
3331
  }
3876
3332
 
3877
3333
  var data = this.prepareData(this.params, this.prepareParams(params), add_params);
3878
3334
 
3879
- if (this.urlEncoded && method == 'POST' && !this.headers['Content-type']) {
3880
- this.setHeader('Content-type', 'application/x-www-form-urlencoded; charset='+this.encoding);
3335
+ if (this.urlEncoded && method == 'post' && !this.headers['Content-type']) {
3336
+ this.setHeader('Content-type', 'application/x-www-form-urlencoded;charset='+this.encoding);
3881
3337
  }
3882
3338
 
3883
- if (method == 'GET') {
3339
+ if (method == 'get') {
3884
3340
  url += (url.includes('?') ? '&' : '?') + data;
3885
3341
  data = null;
3886
3342
  }
@@ -4007,11 +3463,8 @@ var Xhr = new Class(Observer, {
4007
3463
 
4008
3464
  // initializes the request callbacks
4009
3465
  initCallbacks: function() {
4010
- // creating an automatical spinner handling
4011
- this.on('create', 'showSpinner').on('complete', 'hideSpinner').on('cancel', 'hideSpinner');
4012
-
4013
- // response scripts evaluation, should be before the global xhr callbacks
4014
- this.on('success', 'tryScripts');
3466
+ // connecting basic callbacks
3467
+ this.on('success', 'tryScripts').on('create', 'showSpinner').on('complete', 'hideSpinner').on('cancel', 'hideSpinner');
4015
3468
 
4016
3469
  // wiring the global xhr callbacks
4017
3470
  Xhr.EVENTS.each(function(name) {
@@ -4046,13 +3499,13 @@ $ext(Xhr, {
4046
3499
  }
4047
3500
  });
4048
3501
 
4049
- Xhr.on('create', function() {
3502
+ Xhr.onCreate(function() {
4050
3503
  this.counter++;
4051
3504
  this.showSpinner();
4052
- }).on('complete', function() {
3505
+ }).onComplete(function() {
4053
3506
  this.counter--;
4054
3507
  if (this.counter < 1) this.hideSpinner();
4055
- }).on('cancel', function() {
3508
+ }).onCancel(function() {
4056
3509
  this.counter--;
4057
3510
  if (this.counter < 1) this.hideSpinner();
4058
3511
  });
@@ -4215,7 +3668,7 @@ var Fx = new Class(Observer, {
4215
3668
 
4216
3669
  // default options
4217
3670
  Options: {
4218
- fps: Browser.IE ? 40 : 60,
3671
+ fps: Browser.IE || Browser.Opera ? 35 : 60,
4219
3672
  duration: 'normal',
4220
3673
  transition: 'Sin',
4221
3674
  queue: true
@@ -4252,7 +3705,7 @@ var Fx = new Class(Observer, {
4252
3705
  */
4253
3706
  initialize: function(element, options) {
4254
3707
  this.$super(options);
4255
- this.element = $(element);
3708
+ this.element = this.fxee = $(element);
4256
3709
  },
4257
3710
 
4258
3711
  /**
@@ -4264,8 +3717,9 @@ var Fx = new Class(Observer, {
4264
3717
  if (this.queue(arguments)) return this;
4265
3718
  this.prepare.apply(this, arguments);
4266
3719
 
4267
- this.transition = Fx.Transitions[this.options.transition] || this.options.transition;
4268
- var duration = Fx.Durations[this.options.duration] || this.options.duration;
3720
+ var options = this.options,
3721
+ duration = Fx.Durations[options.duration] || options.duration;
3722
+ this.transition = Fx.Transitions[options.transition] || options.transition;
4269
3723
 
4270
3724
  this.steps = (duration / 1000 * this.options.fps).ceil();
4271
3725
  this.number = 1;
@@ -4311,28 +3765,18 @@ var Fx = new Class(Observer, {
4311
3765
 
4312
3766
  // protected
4313
3767
  // dummy method, should be implemented in a subclass
4314
- prepare: function() {},
3768
+ prepare: function(values) {},
4315
3769
 
4316
- // dummy method, should implement the actual things happenning
4317
- render: function(value) {},
3770
+ // dummy method, processes the element properties
3771
+ render: function(delta) {},
4318
3772
 
4319
3773
  // the periodically called method
4320
3774
  // NOTE: called outside of the instance scope!
4321
- step: function($this) {
4322
- if ($this.steps >= $this.number) {
4323
- $this.render($this.transition($this.number / $this.steps));
4324
-
4325
- $this.number ++;
4326
- } else {
4327
- $this.finish();
4328
- }
3775
+ step: function(that) {
3776
+ if (that.number > that.steps) that.finish();
3777
+ else that.render(that.transition(that.number ++ / that.steps));
4329
3778
  },
4330
-
4331
- // calculates the current value
4332
- calc: function(start, end, delata) {
4333
- return start + (end - start) * delta;
4334
- },
4335
-
3779
+
4336
3780
  startTimer: function() {
4337
3781
  this.timer = this.step.periodical((1000 / this.options.fps).round(), this);
4338
3782
  return this;
@@ -4349,15 +3793,11 @@ var Fx = new Class(Observer, {
4349
3793
  // should return false if there's no queue and true if there is a queue
4350
3794
  queue: function(args) {
4351
3795
  if (!this.element) return false;
4352
- if (this.$chained) {
4353
- delete(this['$chained']);
4354
- return false;
4355
- }
3796
+ if (this.$ch) return this.$ch = false;
4356
3797
 
4357
3798
  var uid = $uid(this.element), chain;
4358
- if (!Fx.$chains) Fx.$chains = {};
4359
- if (!Fx.$chains[uid]) Fx.$chains[uid] = [];
4360
- chain = Fx.$chains[uid];
3799
+ Fx.$ch = Fx.$ch || [];
3800
+ chain = (Fx.$ch[uid] = Fx.$ch[uid] || []);
4361
3801
 
4362
3802
  if (this.options.queue)
4363
3803
  chain.push([args, this]);
@@ -4365,13 +3805,13 @@ var Fx = new Class(Observer, {
4365
3805
  this.next = function() {
4366
3806
  var next = chain.shift(); next = chain[0];
4367
3807
  if (next) {
4368
- next[1].$chained = true;
3808
+ next[1].$ch = true;
4369
3809
  next[1].start.apply(next[1], next[0]);
4370
3810
  }
4371
3811
  return this;
4372
3812
  };
4373
3813
 
4374
- return chain[0][1] !== this && this.options.queue;
3814
+ return this.options.queue && chain[0][1] !== this;
4375
3815
  },
4376
3816
 
4377
3817
  next: function() {
@@ -4430,11 +3870,11 @@ $ext(String.prototype, {
4430
3870
  * @return String hex color
4431
3871
  */
4432
3872
  toHex: function() {
4433
- var match = this.match(/^#(\w)(\w)(\w)$/);
3873
+ var match = /^#(\w)(\w)(\w)$/.exec(this);
4434
3874
 
4435
3875
  if (match) {
4436
3876
  match = "#"+ match[1]+match[1]+match[2]+match[2]+match[3]+match[3];
4437
- } else if (match = this.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/)) {
3877
+ } else if (match = /^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/.exec(this)) {
4438
3878
  match = "#"+ match.slice(1).map(function(bit) {
4439
3879
  bit = (bit-0).toString(16);
4440
3880
  return bit.length == 1 ? '0'+bit : bit;
@@ -4453,7 +3893,7 @@ $ext(String.prototype, {
4453
3893
  * @return String rgb(R,G,B) or Array [R,G,B]
4454
3894
  */
4455
3895
  toRgb: function(array) {
4456
- var match = (this.toHex()||'').match(/#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})/i);
3896
+ var match = /#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})/i.exec(this.toHex()||'');
4457
3897
 
4458
3898
  if (match) {
4459
3899
  match = match.slice(1).map('toInt', 16);
@@ -4473,187 +3913,222 @@ $ext(String.prototype, {
4473
3913
  *
4474
3914
  * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
4475
3915
  */
4476
- Fx.Morph = new Class(Fx, {
4477
-
4478
- // protected
3916
+ Fx.Morph = new Class(Fx, (function() {
3917
+ // a list of common style names to compact the code a bit
3918
+ var Top = 'Top', Left = 'Left', Right = 'Right', Bottom = 'Bottom', Color = 'Color', Style = 'Style',
3919
+ Width = 'Width', Bg = 'background', Border = 'border', Pos = 'Position', BgColor = Bg + Color,
3920
+ BdStyle = Border + Style, BdColor = Border + Color, BdWidth = Border + Width;
4479
3921
 
4480
- /**
4481
- * starts the effect
4482
- *
4483
- * @param mixed an Object with an end style or a string with the end class-name(s)
4484
- * @return Fx this
4485
- */
3922
+
3923
+ // adds variants to the style names list
3924
+ var add_variants = function(keys, key, variants) {
3925
+ for (var i=0; i < variants.length; i++)
3926
+ keys.push(key + variants[i]);
3927
+ };
3928
+
3929
+ // parses the style hash into a processable format
3930
+ var parse_style = function(values) {
3931
+ var result = {}, re = /[\d\.\-]+/g, m;
3932
+
3933
+ for (var key in values) {
3934
+ m = values[key].match(re);
3935
+ var value = m.map('toFloat');
3936
+ value.t = values[key].split(re);
3937
+ if (/^\d/.test(values[key]) && value.t[0] !== '') value.t.unshift('');
3938
+ for (var i=0; i < value.length; i++) {
3939
+ value.t.splice(i*2+1, 0, value[i]);
3940
+ }
3941
+ result[key] = value;
3942
+ }
3943
+
3944
+ return result;
3945
+ };
3946
+
3947
+ return {
3948
+
3949
+ // protected
3950
+
3951
+ // parepares the effect
4486
3952
  prepare: function(style) {
4487
- this.endStyle = this._findStyle(style);
4488
- this.startStyle = this._getStyle(this.element, Object.keys(this.endStyle));
3953
+ var keys = this._styleKeys(style),
3954
+ before = this._cloneStyle(this.element, keys),
3955
+ after = this._endStyle(style, keys);
4489
3956
 
4490
- this._cleanStyles();
3957
+ this._cleanStyles(before, after);
4491
3958
 
4492
- return this.$super();
3959
+ this.before = parse_style(before);
3960
+ this.after = parse_style(after);
4493
3961
  },
4494
3962
 
4495
3963
  render: function(delta) {
4496
- var value, start, end;
4497
-
4498
- for (var key in this.endStyle) {
4499
- start = this.startStyle[key];
4500
- end = this.endStyle[key];
4501
-
4502
- if (typeof(start) == 'number') {
4503
- // handling floats like opacity
4504
- value = start + (end - start) * delta;
4505
-
4506
- } else if(start.length == 2) {
4507
- // handling usual sizes with dimensions
4508
- value = (start[0] + (end[0] - start[0]) * delta) + end[1];
4509
-
4510
- } else if(start.length == 3) {
4511
- // calculating colors
4512
- value = end.map(function(value, i) {
4513
- return start[i] + (value - start[i]) * delta;
4514
- }).toRgb();
4515
- }
3964
+ var before, after, value, style = this.element.style;
3965
+ for (var key in this.after) {
3966
+ before = this.before[key];
3967
+ after = this.after[key];
4516
3968
 
4517
- if (key == 'opacity') {
4518
- this.element.setOpacity(value);
4519
- } else {
4520
- this.element.style[key] = value;
3969
+ for (var i=0; i < after.length; i++) {
3970
+ value = before[i] + (after[i] - before[i]) * delta;
3971
+ if (after.t[0] === 'rgb(') value = Math.round(value);
3972
+ after.t[i*2+1] = ''+value;
4521
3973
  }
3974
+ style[key] = after.t.join('');
4522
3975
  }
4523
3976
  },
4524
3977
 
4525
- // private
4526
-
4527
- // finds the style definition by a css-selector string
4528
- _findStyle: function(style) {
4529
- // a dummy node to calculate the end styles
4530
- var element = this._dummy().setStyle(style);
4531
-
4532
- // grabbing the computed styles
4533
- var element_styles = element.computedStyles();
4534
- var this_element_styles = this.element.computedStyles();
4535
-
4536
- // grabbing the element style
4537
- var end_style = this._getStyle(element, Object.keys(style), element_styles);
4538
-
4539
- // assigning the border style if the end style has a border
4540
- var border_style = element_styles.borderTopStyle, element_border_style = this_element_styles.borderTopStyle;
4541
- if (border_style != element_border_style) {
4542
- if (element_border_style == 'none') {
4543
- this.element.style.borderWidth = '0px';
4544
- }
4545
- this.element.style.borderStyle = border_style;
4546
- if (this._transp(this_element_styles.borderTopColor)) {
4547
- this.element.style.borderColor = this_element_styles.color;
4548
- }
4549
- }
4550
-
4551
- element.remove();
3978
+ /**
3979
+ * Returns a hash of the end style
3980
+ *
3981
+ * @param Object style
3982
+ * @return Object end style
3983
+ */
3984
+ _endStyle: function(style, keys) {
3985
+ var parent = this.element.parentNode,
3986
+ dummy = $(this.element.cloneNode(true)).setStyle(style);
3987
+
3988
+ // swapping the element with the dummy and getting the new styles
3989
+ if (parent) parent.replaceChild(dummy, this.element);
3990
+ var after = this._cloneStyle(dummy, keys);
3991
+ if (parent) parent.replaceChild(this.element, dummy);
4552
3992
 
4553
- return end_style;
3993
+ return after;
4554
3994
  },
4555
3995
 
4556
- // creates a dummy element to work with
4557
- _dummy: function() {
4558
- // a container for the styles extraction element
4559
- var container = Fx.Morph.$c = (Fx.Morph.$c || $E('div', {style: "visibility:hidden;float:left;height:0;width:0"}));
4560
- if (this.element.parentNode) this.element.parentNode.insertBefore(container, this.element);
3996
+ /**
3997
+ * Fast styles cloning
3998
+ *
3999
+ * @param Element element
4000
+ * @param Array style keys
4001
+ * @return Hash of styles
4002
+ */
4003
+ _cloneStyle: function(element, keys) {
4004
+ for (var i=0, len = keys.length, style = element.computedStyles(), clean = {}; i < len; i++)
4005
+ clean[keys[i]] = style[keys[i]];
4561
4006
 
4562
- return $(this.element.cloneNode(false)).insertTo(container);
4007
+ return clean;
4563
4008
  },
4564
4009
 
4565
- // grabs computed styles with the given keys out of the element
4566
- _getStyle: function(element, keys, styles) {
4567
- var style = {}, styles = styles || element.computedStyles(), name;
4568
- if (isString(keys)) { name = keys, keys = [keys]; }
4010
+ /**
4011
+ * creates an appropriate style-keys list out of the user styles
4012
+ *
4013
+ * @param Object the style hash
4014
+ * @return Array of clean style keys list
4015
+ */
4016
+ _styleKeys: function(style) {
4017
+ var keys = [], border_types = [Style, Color, Width], directions = [Top, Left, Right, Bottom];
4018
+
4019
+ for (var key in style) {
4020
+ if (key.startsWith(Border))
4021
+ for (var i=0; i < border_types.length; i++)
4022
+ for (var j=0; j < directions.length; j++)
4023
+ keys.push(Border + directions[j] + border_types[i]);
4024
+ else if (key === 'margin' || key === 'padding')
4025
+ add_variants(keys, key, directions);
4026
+ else if (key.startsWith(Bg))
4027
+ add_variants(keys, Bg, [Color, Pos, Pos+'X', Pos+'Y']);
4028
+ else if (key === 'opacity' && Browser.IE)
4029
+ keys.push('filter');
4030
+ else
4031
+ keys.push(key);
4032
+ }
4569
4033
 
4570
- for (var i=0; i < keys.length; i++) {
4571
- var key = keys[i].camelize();
4034
+ return keys;
4035
+ },
4036
+
4037
+ /**
4038
+ * cleans up and optimizies the styles
4039
+ *
4040
+ * @param Object before
4041
+ * @param Object after
4042
+ * @return void
4043
+ */
4044
+ _cleanStyles: function(before, after) {
4045
+ var remove = [];
4046
+
4047
+ for (var key in after) {
4048
+ // getting directional options together so they were processed faster
4049
+ if (key.includes(Top)) {
4050
+ var top = key,
4051
+ left = key.replace(Top, Left),
4052
+ right = key.replace(Top, Right),
4053
+ bottom = key.replace(Top, Bottom),
4054
+ common = key.replace(Top, '');
4055
+
4056
+ if (after[top] === after[left] && after[top] === after[right] && after[top] === after[bottom] &&
4057
+ before[top] === before[left] && before[top] === before[right] && before[top] === before[bottom]
4058
+ ) {
4059
+ after[common] = after[top];
4060
+ before[common] = before[top];
4061
+
4062
+ remove = remove.concat([top, left, right, bottom]);
4063
+ }
4064
+ }
4572
4065
 
4573
- // keys preprocessing
4574
- if (key == 'background') key = 'backgroundColor';
4575
- else if (key == 'border') {
4576
- key = 'borderWidth';
4577
- keys.splice(i+1, 0, 'borderColor'); // inserting the border color as the next unit
4066
+ // checking the height/width options
4067
+ if (key === Width || key === 'height') {
4068
+ if (before[key] == 'auto') before[key] = this.element['offset'+key.capitalize()] + 'px';
4578
4069
  }
4070
+ }
4071
+
4072
+ // IE opacity filter fix
4073
+ if (after.filter && !before.filter) before.filter = 'alpha(opacity=100)';
4074
+
4075
+ // adjusting the border style
4076
+ if (before[BdStyle] != after[BdStyle]) {
4077
+ var style = this.element.style;
4579
4078
 
4580
- // getting the actual style
4581
- style[key] = element._getStyle(styles, key);
4079
+ if (before[BdStyle] == 'none') {
4080
+ style[BdWidth] = '0px';
4081
+ }
4582
4082
 
4583
- // Opera returns named colors as quoted strings
4584
- if (Browser.Opera && /color/i.test(key)) style[key] = style[key].replace(/'|"/g, '');
4083
+ style[BdStyle] = after[BdStyle];
4084
+ if (this._transp(before[BdColor])) {
4085
+ style[BdColor] = this.element.getStyle(Color);
4086
+ }
4087
+ }
4088
+
4089
+ // cleaing up the list
4090
+ for (var key in after) {
4091
+ // proprocessing colors
4092
+ if (after[key] !== before[key] && !remove.includes(key) && /color/i.test(key)) {
4093
+ if (Browser.Opera) {
4094
+ after[key] = after[key].replace(/"/g, '');
4095
+ before[key] = before[key].replace(/"/g, '');
4096
+ }
4097
+
4098
+ if (!this._transp(after[key])) after[key] = after[key].toRgb();
4099
+ if (!this._transp(before[key])) before[key] = before[key].toRgb();
4100
+
4101
+ if (!after[key] || !before[key]) after[key] = before[key] = '';
4102
+ }
4585
4103
 
4586
- // getting the real color if it's a transparent
4587
- if (this._transp(style[key])) style[key] = this._getBGColor(element);
4104
+ // filling up the missing sizes
4105
+ if (/\d/.test(after[key]) && !/\d/.test(before[key])) before[key] = after[key].replace(/[\d\.\-]+/g, '0');
4588
4106
 
4589
- // getting the real width and height if they not set or set as 'auto'
4590
- if (!style[key] || style[key] == 'auto') {
4591
- style[key] = key == 'width' ? element.offsetWidth + 'px' :
4592
- key == 'height' ? element.offsetHeight + 'px' : '';
4107
+ // removing unprocessable keys
4108
+ if (after[key] === before[key] || remove.includes(key) || !/\d/.test(before[key]) || !/\d/.test(after[key])) {
4109
+ delete(after[key]);
4110
+ delete(before[key]);
4593
4111
  }
4594
4112
  }
4595
-
4596
- return name ? style[name] : style;
4597
4113
  },
4598
4114
 
4599
4115
  // looking for the visible background color of the element
4600
4116
  _getBGColor: function(element) {
4601
4117
  return [element].concat(element.parents()).map(function(node) {
4602
- var bg = node.getStyle('backgroundColor');
4118
+ var bg = node.getStyle(BgColor);
4603
4119
  return (bg && !this._transp(bg)) ? bg : null;
4604
- }, this).compact().first() || 'rgb(255,255,255)';
4120
+ }, this).compact().first() || '#FFF';
4605
4121
  },
4606
4122
 
4607
- // prepares the style values to be processed correctly
4608
- _cleanStyles: function() {
4609
- var end = this.endStyle, start = this.startStyle;
4610
-
4611
- // filling up missing styles
4612
- for (var key in end) {
4613
- if (start[key] === '' && /^[\d\.\-]+[a-z]+$/.test(end[key])) {
4614
- start[key] = '0px';
4615
- }
4616
- }
4617
-
4618
- [end, start].each(this._cleanStyle, this);
4619
-
4620
- // removing duplications between start and end styles
4621
- for (var key in end) {
4622
- if (!defined(start[key]) || (end[key] instanceof Array ? end[key].join() === start[key].join() : end[key] === start[key])) {
4623
- delete(end[key]);
4624
- delete(start[key]);
4625
- }
4626
- }
4627
- },
4628
-
4629
- // cleans up a style object
4630
- _cleanStyle: function(style) {
4631
- var match;
4632
- for (var key in style) {
4633
- style[key] = String(style[key]);
4634
-
4635
- if (/color/i.test(key)) {
4636
- // preparing the colors
4637
- style[key] = style[key].toRgb(true);
4638
- if (!style[key]) delete(style[key]);
4639
- } else if (/^[\d\.]+$/.test(style[key])) {
4640
- // preparing numberic values
4641
- style[key] = style[key].toFloat();
4642
- } else if (match = style[key].match(/^([\d\.\-]+)([a-z]+)$/i)) {
4643
- // preparing values with dimensions
4644
- style[key] = [match[1].toFloat(), match[2]];
4645
-
4646
- } else {
4647
- delete(style[key]);
4648
- }
4649
- }
4650
- },
4651
4123
 
4652
4124
  // checks if the color is transparent
4653
4125
  _transp: function(color) {
4654
- return color == 'transparent' || color == 'rgba(0, 0, 0, 0)';
4126
+ return color === 'transparent' || color === 'rgba(0, 0, 0, 0)';
4655
4127
  }
4656
- });
4128
+
4129
+ }})());
4130
+
4131
+
4657
4132
 
4658
4133
  /**
4659
4134
  * the elements hightlighting effect
@@ -4753,7 +4228,7 @@ Fx.Slide = new Class(Fx.Twin, {
4753
4228
  this.element.style.overflow = 'hidden';
4754
4229
  this.onFinish('_getBack').onCancel('_getBack');
4755
4230
 
4756
- return this.$super(this._endStyle(this.options.direction));
4231
+ return this.$super(this._getStyle(this.options.direction));
4757
4232
  },
4758
4233
 
4759
4234
  _getBack: function() {
@@ -4761,7 +4236,7 @@ Fx.Slide = new Class(Fx.Twin, {
4761
4236
  },
4762
4237
 
4763
4238
  // calculates the final style
4764
- _endStyle: function(direction) {
4239
+ _getStyle: function(direction) {
4765
4240
  var style = {}, sizes = this.sizes,
4766
4241
  margin_left = (this.styles.marginLeft || '0').toFloat(),
4767
4242
  margin_top = (this.styles.marginTop || '0').toFloat();
@@ -4816,6 +4291,27 @@ Fx.Fade = new Class(Fx.Twin, {
4816
4291
  }
4817
4292
  });
4818
4293
 
4294
+ /**
4295
+ * A smooth scrolling visual effect
4296
+ *
4297
+ * Copyright (C) 2009 Nikolay V. Nemshilov aka St.
4298
+ */
4299
+ Fx.Scroll = new Class(Fx, {
4300
+ prepare: function(value) {
4301
+ this.before = {};
4302
+ this.after = value;
4303
+
4304
+ if (value.x != undefined) this.before.x = this.element.scrollLeft;
4305
+ if (value.y != undefined) this.before.y = this.element.scrollTop;
4306
+ },
4307
+
4308
+ render: function(delta) {
4309
+ for (var key in this.after) {
4310
+ this.element['scroll' + (key === 'x' ? 'Left' : 'Top')] = this.before[key] + (this.after[key] - this.before[key]) * delta;
4311
+ }
4312
+ }
4313
+ });
4314
+
4819
4315
  /**
4820
4316
  * This block contains additional Element shortcuts for effects easy handling
4821
4317
  *
@@ -4828,7 +4324,7 @@ Fx.Fade = new Class(Fx.Twin, {
4828
4324
  Element.addMethods((function(methods) {
4829
4325
  var old_hide = methods.hide,
4830
4326
  old_show = methods.show,
4831
- old_resize = methods.resize;
4327
+ old_scroll = methods.scrollTo;
4832
4328
 
4833
4329
  return {
4834
4330
 
@@ -4852,31 +4348,6 @@ return {
4852
4348
  return fx ? this.fx(fx, ['in', options], old_show) : old_show.call(this);
4853
4349
  },
4854
4350
 
4855
- /**
4856
- * resizes the element using the Morph visual effect
4857
- *
4858
- * @param Integer width
4859
- * @param Integer height
4860
- * @param Object options
4861
- */
4862
- resize: function(width, height, options) {
4863
- if (isHash(width)) {
4864
- height = width.y;
4865
- width = width.x;
4866
- }
4867
- if (options) {
4868
- var style = {};
4869
- if (isNumber(height)) style.height = height+'px';
4870
- if (isNumber(width)) style.width = width +'px';
4871
-
4872
- if (!isHash(options)) options = {duration: options};
4873
-
4874
- return this.fx('morph', [style, options]);
4875
- } else {
4876
- return old_resize.call(this, width, height);
4877
- }
4878
- },
4879
-
4880
4351
  /**
4881
4352
  * runs the Fx.Morth effect to the given style
4882
4353
  *
@@ -4921,6 +4392,30 @@ return {
4921
4392
  return this.fx('slide', arguments);
4922
4393
  },
4923
4394
 
4395
+ /**
4396
+ * Starts the smooth scrolling effect
4397
+ *
4398
+ * @param Object {x: NNN, y: NNN} where to scroll
4399
+ * @param Object fx-options
4400
+ * @return Element this
4401
+ */
4402
+ scroll: function(value, options) {
4403
+ return this.fx('scroll', [value, options||{}]);
4404
+ },
4405
+
4406
+ /**
4407
+ * wraps the old scroll to be able to run it with fxes
4408
+ *
4409
+ * If you send two hashes then will start a smooth scrolling
4410
+ * otherwise will just jump over with the usual method
4411
+ *
4412
+ * @return Element this
4413
+ */
4414
+ scrollTo: function(value, options) {
4415
+ return isHash(options) ? this.scroll(value, options) : old_scroll.apply(this, arguments);
4416
+ },
4417
+
4418
+
4924
4419
  // protected
4925
4420
 
4926
4421
  // runs an Fx on the element
@@ -4937,3 +4432,23 @@ return {
4937
4432
 
4938
4433
  }})(Element.Methods));
4939
4434
 
4435
+ /**
4436
+ * The old browsers support patch loading script
4437
+ * will be included in the core file when it's built
4438
+ * with the no-olds option
4439
+ *
4440
+ * Basically it just checks all the script tags on the page
4441
+ * finds the core inclusion tag and uses it's src attribute
4442
+ * to dynamically load the olds patch
4443
+ *
4444
+ * Copyright (C) 2009 Nikolay V. Nemshilov aka St.
4445
+ */
4446
+ if (!document.querySelector) {
4447
+ (function() {
4448
+ var rigth_src_re = /(\/right)([^\/]+)$/;
4449
+ var core_src = $A(document.getElementsByTagName('script')).map('src').compact().first('match', rigth_src_re);
4450
+ if (core_src)
4451
+ document.write('<scr'+'ipt src="'+core_src.replace(rigth_src_re, '$1-olds$2')+'"></scr'+'ipt>');
4452
+ })();
4453
+ }
4454
+