right-rails 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+