sproutcore 0.9.14 → 0.9.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/History.txt +43 -0
  2. data/Manifest.txt +12 -3
  3. data/bin/sc-build +19 -3
  4. data/bin/sc-install +5 -0
  5. data/bin/sc-remove +5 -0
  6. data/bin/sc-update +5 -0
  7. data/frameworks/prototype/prototype.js +267 -230
  8. data/frameworks/sproutcore/HISTORY +281 -135
  9. data/frameworks/sproutcore/controllers/array.js +133 -22
  10. data/frameworks/sproutcore/controllers/collection.js +4 -5
  11. data/frameworks/sproutcore/controllers/object.js +8 -2
  12. data/frameworks/sproutcore/core.js +361 -159
  13. data/frameworks/sproutcore/{foundation → debug}/unittest.js +3 -3
  14. data/frameworks/sproutcore/english.lproj/detect-browser +1 -1
  15. data/frameworks/sproutcore/english.lproj/theme.css +2 -2
  16. data/frameworks/sproutcore/foundation/application.js +6 -1
  17. data/frameworks/sproutcore/foundation/benchmark.js +37 -11
  18. data/frameworks/sproutcore/foundation/date.js +1 -1
  19. data/frameworks/sproutcore/foundation/enumerator.js +105 -0
  20. data/frameworks/sproutcore/foundation/object.js +19 -20
  21. data/frameworks/sproutcore/foundation/responder.js +1 -1
  22. data/frameworks/sproutcore/foundation/set.js +164 -57
  23. data/frameworks/sproutcore/foundation/string.js +151 -47
  24. data/frameworks/sproutcore/foundation/utils.js +84 -3
  25. data/frameworks/sproutcore/lib/collection_view.rb +1 -0
  26. data/frameworks/sproutcore/license.js +28 -0
  27. data/frameworks/sproutcore/mixins/array.js +73 -209
  28. data/frameworks/sproutcore/mixins/delegate_support.js +1 -1
  29. data/frameworks/sproutcore/mixins/enumerable.js +1006 -0
  30. data/frameworks/sproutcore/mixins/observable.js +153 -84
  31. data/frameworks/sproutcore/mixins/selection_support.js +13 -1
  32. data/frameworks/sproutcore/models/record.js +74 -27
  33. data/frameworks/sproutcore/models/store.js +7 -3
  34. data/frameworks/sproutcore/server/rails_server.js +82 -0
  35. data/frameworks/sproutcore/server/rest_server.js +178 -0
  36. data/frameworks/sproutcore/{foundation → server}/server.js +101 -48
  37. data/frameworks/sproutcore/tests/core/guidFor.rhtml +114 -0
  38. data/frameworks/sproutcore/tests/foundation/array.rhtml +6 -7
  39. data/frameworks/sproutcore/tests/foundation/set.rhtml +254 -0
  40. data/frameworks/sproutcore/tests/mixins/enumerable.rhtml +421 -0
  41. data/frameworks/sproutcore/tests/mixins/observable.rhtml +127 -0
  42. data/frameworks/sproutcore/tests/models/model.rhtml +23 -22
  43. data/frameworks/sproutcore/tests/views/collection/incremental_rendering.rhtml +2 -2
  44. data/frameworks/sproutcore/tests/views/view/clippingFrame.rhtml +112 -109
  45. data/frameworks/sproutcore/tests/views/view/frame.rhtml +91 -88
  46. data/frameworks/sproutcore/validators/date.js +1 -7
  47. data/frameworks/sproutcore/views/collection/collection.js +7 -2
  48. data/frameworks/sproutcore/views/list_item.js +141 -3
  49. data/frameworks/sproutcore/views/split.js +14 -11
  50. data/frameworks/sproutcore/views/view.js +9 -6
  51. data/lib/sproutcore/build_tools/html_builder.rb +19 -3
  52. data/lib/sproutcore/build_tools/resource_builder.rb +9 -3
  53. data/lib/sproutcore/bundle.rb +21 -0
  54. data/lib/sproutcore/bundle_manifest.rb +64 -20
  55. data/lib/sproutcore/helpers/capture_helper.rb +2 -2
  56. data/lib/sproutcore/library.rb +33 -9
  57. data/lib/sproutcore/merb/bundle_controller.rb +16 -5
  58. data/lib/sproutcore/version.rb +1 -1
  59. data/lib/sproutcore/view_helpers.rb +1 -1
  60. data/{sc-config.rb → sc-config} +5 -2
  61. metadata +24 -5
@@ -9,7 +9,7 @@
9
9
  @license */
10
10
 
11
11
  var Prototype = {
12
- Version: '1.6.0',
12
+ Version: '1.6.0.2',
13
13
 
14
14
  Browser: {
15
15
  IE: !!(window.attachEvent && !window.opera),
@@ -38,8 +38,6 @@ var Prototype = {
38
38
  if (Prototype.Browser.MobileSafari)
39
39
  Prototype.BrowserFeatures.SpecificElementExtensions = false;
40
40
 
41
- if (Prototype.Browser.WebKit)
42
- Prototype.BrowserFeatures.XPath = false;
43
41
 
44
42
  /* Based on Alex Arnell's inheritance implementation. */
45
43
  var Class = {
@@ -112,9 +110,9 @@ Object.extend = function(destination, source) {
112
110
  Object.extend(Object, {
113
111
  inspect: function(object) {
114
112
  try {
115
- if (object === undefined) return 'undefined';
113
+ if (Object.isUndefined(object)) return 'undefined';
116
114
  if (object === null) return 'null';
117
- return object.inspect ? object.inspect() : object.toString();
115
+ return object.inspect ? object.inspect() : String(object);
118
116
  } catch (e) {
119
117
  if (e instanceof RangeError) return '...';
120
118
  throw e;
@@ -137,7 +135,7 @@ Object.extend(Object, {
137
135
  var results = [];
138
136
  for (var property in object) {
139
137
  var value = Object.toJSON(object[property]);
140
- if (value !== undefined)
138
+ if (!Object.isUndefined(value))
141
139
  results.push(property.toJSON() + ': ' + value);
142
140
  }
143
141
 
@@ -175,7 +173,8 @@ Object.extend(Object, {
175
173
  },
176
174
 
177
175
  isArray: function(object) {
178
- return object && object.constructor === Array;
176
+ return object != null && typeof object == "object" &&
177
+ 'splice' in object && 'join' in object;
179
178
  },
180
179
 
181
180
  isHash: function(object) {
@@ -206,7 +205,7 @@ Object.extend(Function.prototype, {
206
205
  },
207
206
 
208
207
  bind: function() {
209
- if (arguments.length < 2 && arguments[0] === undefined) return this;
208
+ if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
210
209
  var __method = this, args = $A(arguments), object = args.shift();
211
210
  return function() {
212
211
  return __method.apply(object, args.concat($A(arguments)));
@@ -353,7 +352,7 @@ Object.extend(String.prototype, {
353
352
 
354
353
  sub: function(pattern, replacement, count) {
355
354
  replacement = this.gsub.prepareReplacement(replacement);
356
- count = count === undefined ? 1 : count;
355
+ count = Object.isUndefined(count) ? 1 : count;
357
356
 
358
357
  return this.gsub(pattern, function(match) {
359
358
  if (--count < 0) return match[0];
@@ -368,7 +367,7 @@ Object.extend(String.prototype, {
368
367
 
369
368
  truncate: function(length, truncation) {
370
369
  length = length || 30;
371
- truncation = truncation === undefined ? '...' : truncation;
370
+ truncation = Object.isUndefined(truncation) ? '...' : truncation;
372
371
  return this.length > length ?
373
372
  this.slice(0, length - truncation.length) + truncation : String(this);
374
373
  },
@@ -488,7 +487,9 @@ Object.extend(String.prototype, {
488
487
  },
489
488
 
490
489
  isJSON: function() {
491
- var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
490
+ var str = this;
491
+ if (str.blank()) return false;
492
+ str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
492
493
  return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
493
494
  },
494
495
 
@@ -567,7 +568,8 @@ var Template = Class.create({
567
568
  if (before == '\\') return match[2];
568
569
 
569
570
  var ctx = object, expr = match[3];
570
- var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/, match = pattern.exec(expr);
571
+ var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
572
+ match = pattern.exec(expr);
571
573
  if (match == null) return before;
572
574
 
573
575
  while (match != null) {
@@ -579,7 +581,7 @@ var Template = Class.create({
579
581
  }
580
582
 
581
583
  return before + String.interpret(ctx);
582
- }.bind(this));
584
+ });
583
585
  }
584
586
  });
585
587
  Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
@@ -688,7 +690,7 @@ var Enumerable = {
688
690
  },
689
691
 
690
692
  inGroupsOf: function(number, fillWith) {
691
- fillWith = fillWith === undefined ? null : fillWith;
693
+ fillWith = Object.isUndefined(fillWith) ? null : fillWith;
692
694
  return this.eachSlice(number, function(slice) {
693
695
  while(slice.length < number) slice.push(fillWith);
694
696
  return slice;
@@ -715,7 +717,7 @@ var Enumerable = {
715
717
  var result;
716
718
  this.each(function(value, index) {
717
719
  value = iterator(value, index);
718
- if (result == undefined || value >= result)
720
+ if (result == null || value >= result)
719
721
  result = value;
720
722
  });
721
723
  return result;
@@ -726,7 +728,7 @@ var Enumerable = {
726
728
  var result;
727
729
  this.each(function(value, index) {
728
730
  value = iterator(value, index);
729
- if (result == undefined || value < result)
731
+ if (result == null || value < result)
730
732
  result = value;
731
733
  });
732
734
  return result;
@@ -807,20 +809,20 @@ Object.extend(Enumerable, {
807
809
  function $A(iterable) {
808
810
  if (!iterable) return [];
809
811
  if (iterable.toArray) return iterable.toArray();
810
- var length = iterable.length, results = new Array(length);
812
+ var length = iterable.length || 0, results = new Array(length);
811
813
  while (length--) results[length] = iterable[length];
812
814
  return results;
813
815
  }
814
816
 
815
817
  if (Prototype.Browser.WebKit) {
816
- function $A(iterable) {
818
+ $A = function(iterable) {
817
819
  if (!iterable) return [];
818
820
  if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
819
821
  iterable.toArray) return iterable.toArray();
820
- var length = iterable.length, results = new Array(length);
822
+ var length = iterable.length || 0, results = new Array(length);
821
823
  while (length--) results[length] = iterable[length];
822
824
  return results;
823
- }
825
+ };
824
826
  }
825
827
 
826
828
  Array.from = $A;
@@ -906,7 +908,7 @@ Object.extend(Array.prototype, {
906
908
  var results = [];
907
909
  this.each(function(object) {
908
910
  var value = Object.toJSON(object);
909
- if (value !== undefined) results.push(value);
911
+ if (!Object.isUndefined(value)) results.push(value);
910
912
  });
911
913
  return '[' + results.join(', ') + ']';
912
914
  }
@@ -986,34 +988,6 @@ function $H(object) {
986
988
  };
987
989
 
988
990
  var Hash = Class.create(Enumerable, (function() {
989
- if (function() {
990
- var i = 0, Test = function(value) { this.key = value; };
991
- Test.prototype.key = 'foo';
992
- for (var property in new Test('bar')) i++;
993
- return i > 1;
994
- }()) {
995
- function each(iterator) {
996
- var cache = [];
997
- for (var key in this._object) {
998
- var value = this._object[key];
999
- if (cache.include(key)) continue;
1000
- cache.push(key);
1001
- var pair = [key, value];
1002
- pair.key = key;
1003
- pair.value = value;
1004
- iterator(pair);
1005
- }
1006
- }
1007
- } else {
1008
- function each(iterator) {
1009
- for (var key in this._object) {
1010
- var value = this._object[key], pair = [key, value];
1011
- pair.key = key;
1012
- pair.value = value;
1013
- iterator(pair);
1014
- }
1015
- }
1016
- }
1017
991
 
1018
992
  function toQueryPair(key, value) {
1019
993
  if (Object.isUndefined(value)) return key;
@@ -1025,7 +999,14 @@ var Hash = Class.create(Enumerable, (function() {
1025
999
  this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
1026
1000
  },
1027
1001
 
1028
- _each: each,
1002
+ _each: function(iterator) {
1003
+ for (var key in this._object) {
1004
+ var value = this._object[key], pair = [key, value];
1005
+ pair.key = key;
1006
+ pair.value = value;
1007
+ iterator(pair);
1008
+ }
1009
+ },
1029
1010
 
1030
1011
  set: function(key, value) {
1031
1012
  return this._object[key] = value;
@@ -1189,8 +1170,11 @@ Ajax.Base = Class.create({
1189
1170
  Object.extend(this.options, options || { });
1190
1171
 
1191
1172
  this.options.method = this.options.method.toLowerCase();
1173
+
1192
1174
  if (Object.isString(this.options.parameters))
1193
1175
  this.options.parameters = this.options.parameters.toQueryParams();
1176
+ else if (Object.isHash(this.options.parameters))
1177
+ this.options.parameters = this.options.parameters.toObject();
1194
1178
  }
1195
1179
  });
1196
1180
 
@@ -1208,7 +1192,7 @@ Ajax.Request = Class.create(Ajax.Base, {
1208
1192
  this.method = this.options.method;
1209
1193
  var params = Object.clone(this.options.parameters);
1210
1194
 
1211
- if (!['get', 'post'].include(this.method)) {
1195
+ if (this.options.emulateUncommonMethods && !['get', 'post'].include(this.method)) {
1212
1196
  // simulate other verbs over post
1213
1197
  params['_method'] = this.method;
1214
1198
  this.method = 'post';
@@ -1230,14 +1214,14 @@ Ajax.Request = Class.create(Ajax.Base, {
1230
1214
  Ajax.Responders.dispatch('onCreate', this, response);
1231
1215
 
1232
1216
  this.transport.open(this.method.toUpperCase(), this.url,
1233
- this.options.asynchronous);
1217
+ this.options.asynchronous);
1234
1218
 
1235
1219
  if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
1236
1220
 
1237
1221
  this.transport.onreadystatechange = this.onStateChange.bind(this);
1238
1222
  this.setRequestHeaders();
1239
1223
 
1240
- this.body = this.method == 'post' ? (this.options.postBody || params) : null;
1224
+ this.body = this.method != 'get' ? (this.options.postBody || params) : null;
1241
1225
  this.transport.send(this.body);
1242
1226
 
1243
1227
  /* Force Firefox to handle ready state 4 for synchronous requests */
@@ -1317,7 +1301,7 @@ Ajax.Request = Class.create(Ajax.Base, {
1317
1301
 
1318
1302
  var contentType = response.getHeader('Content-type');
1319
1303
  if (this.options.evalJS == 'force'
1320
- || (this.options.evalJS && contentType
1304
+ || (this.options.evalJS && this.isSameOrigin() && contentType
1321
1305
  && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
1322
1306
  this.evalResponse();
1323
1307
  }
@@ -1335,9 +1319,18 @@ Ajax.Request = Class.create(Ajax.Base, {
1335
1319
  }
1336
1320
  },
1337
1321
 
1322
+ isSameOrigin: function() {
1323
+ var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
1324
+ return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
1325
+ protocol: location.protocol,
1326
+ domain: document.domain,
1327
+ port: location.port ? ':' + location.port : ''
1328
+ }));
1329
+ },
1330
+
1338
1331
  getHeader: function(name) {
1339
1332
  try {
1340
- return this.transport.getResponseHeader(name);
1333
+ return this.transport.getResponseHeader(name) || null;
1341
1334
  } catch (e) { return null; }
1342
1335
  },
1343
1336
 
@@ -1373,7 +1366,7 @@ Ajax.Response = Class.create({
1373
1366
 
1374
1367
  if(readyState == 4) {
1375
1368
  var xml = transport.responseXML;
1376
- this.responseXML = xml === undefined ? null : xml;
1369
+ this.responseXML = Object.isUndefined(xml) ? null : xml;
1377
1370
  this.responseJSON = this._getResponseJSON();
1378
1371
  }
1379
1372
  },
@@ -1410,7 +1403,8 @@ Ajax.Response = Class.create({
1410
1403
  if (!json) return null;
1411
1404
  json = decodeURIComponent(escape(json));
1412
1405
  try {
1413
- return json.evalJSON(this.request.options.sanitizeJSON);
1406
+ return json.evalJSON(this.request.options.sanitizeJSON ||
1407
+ !this.request.isSameOrigin());
1414
1408
  } catch (e) {
1415
1409
  this.request.dispatchException(e);
1416
1410
  }
@@ -1419,10 +1413,12 @@ Ajax.Response = Class.create({
1419
1413
  _getResponseJSON: function() {
1420
1414
  var options = this.request.options;
1421
1415
  if (!options.evalJSON || (options.evalJSON != 'force' &&
1422
- !(this.getHeader('Content-type') || '').include('application/json')))
1423
- return null;
1416
+ !(this.getHeader('Content-type') || '').include('application/json')) ||
1417
+ this.responseText.blank())
1418
+ return null;
1424
1419
  try {
1425
- return this.transport.responseText.evalJSON(options.sanitizeJSON);
1420
+ return this.responseText.evalJSON(options.sanitizeJSON ||
1421
+ !this.request.isSameOrigin());
1426
1422
  } catch (e) {
1427
1423
  this.request.dispatchException(e);
1428
1424
  }
@@ -1436,11 +1432,11 @@ Ajax.Updater = Class.create(Ajax.Request, {
1436
1432
  failure: (container.failure || (container.success ? null : container))
1437
1433
  };
1438
1434
 
1439
- options = options || { };
1435
+ options = Object.clone(options);
1440
1436
  var onComplete = options.onComplete;
1441
- options.onComplete = (function(response, param) {
1437
+ options.onComplete = (function(response, json) {
1442
1438
  this.updateContent(response.responseText);
1443
- if (Object.isFunction(onComplete)) onComplete(response, param);
1439
+ if (Object.isFunction(onComplete)) onComplete(response, json);
1444
1440
  }).bind(this);
1445
1441
 
1446
1442
  $super(url, options);
@@ -1462,10 +1458,6 @@ Ajax.Updater = Class.create(Ajax.Request, {
1462
1458
  }
1463
1459
  else receiver.update(responseText);
1464
1460
  }
1465
-
1466
- if (this.success()) {
1467
- if (this.onComplete) this.onComplete.bind(this).defer();
1468
- }
1469
1461
  }
1470
1462
  });
1471
1463
 
@@ -1630,24 +1622,28 @@ Element.Methods = {
1630
1622
  Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
1631
1623
  insertions = {bottom:insertions};
1632
1624
 
1633
- var content, t, range;
1625
+ var content, insert, tagName, childNodes;
1634
1626
 
1635
- for (position in insertions) {
1627
+ for (var position in insertions) {
1636
1628
  content = insertions[position];
1637
1629
  position = position.toLowerCase();
1638
- t = Element._insertionTranslations[position];
1630
+ insert = Element._insertionTranslations[position];
1639
1631
 
1640
1632
  if (content && content.toElement) content = content.toElement();
1641
1633
  if (Object.isElement(content)) {
1642
- t.insert(element, content);
1634
+ insert(element, content);
1643
1635
  continue;
1644
1636
  }
1645
1637
 
1646
1638
  content = Object.toHTML(content);
1647
1639
 
1648
- range = element.ownerDocument.createRange();
1649
- t.initializeRange(element, range);
1650
- t.insert(element, range.createContextualFragment(content.stripScripts()));
1640
+ tagName = ((position == 'before' || position == 'after')
1641
+ ? element.parentNode : element).tagName.toUpperCase();
1642
+
1643
+ childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
1644
+
1645
+ if (position == 'top' || position == 'after') childNodes.reverse();
1646
+ childNodes.each(insert.curry(element));
1651
1647
 
1652
1648
  content.evalScripts.bind(content).defer();
1653
1649
  }
@@ -1692,7 +1688,7 @@ Element.Methods = {
1692
1688
  },
1693
1689
 
1694
1690
  descendants: function(element) {
1695
- return $A($(element).getElementsByTagName('*')).each(Element.extend);
1691
+ return $(element).select("*");
1696
1692
  },
1697
1693
 
1698
1694
  firstDescendant: function(element) {
@@ -1731,32 +1727,31 @@ Element.Methods = {
1731
1727
  element = $(element);
1732
1728
  if (arguments.length == 1) return $(element.parentNode);
1733
1729
  var ancestors = element.ancestors();
1734
- return expression ? Selector.findElement(ancestors, expression, index) :
1735
- ancestors[index || 0];
1730
+ return Object.isNumber(expression) ? ancestors[expression] :
1731
+ Selector.findElement(ancestors, expression, index);
1736
1732
  },
1737
1733
 
1738
1734
  down: function(element, expression, index) {
1739
1735
  element = $(element);
1740
1736
  if (arguments.length == 1) return element.firstDescendant();
1741
- var descendants = element.descendants();
1742
- return expression ? Selector.findElement(descendants, expression, index) :
1743
- descendants[index || 0];
1737
+ return Object.isNumber(expression) ? element.descendants()[expression] :
1738
+ element.select(expression)[index || 0];
1744
1739
  },
1745
1740
 
1746
1741
  previous: function(element, expression, index) {
1747
1742
  element = $(element);
1748
1743
  if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
1749
1744
  var previousSiblings = element.previousSiblings();
1750
- return expression ? Selector.findElement(previousSiblings, expression, index) :
1751
- previousSiblings[index || 0];
1745
+ return Object.isNumber(expression) ? previousSiblings[expression] :
1746
+ Selector.findElement(previousSiblings, expression, index);
1752
1747
  },
1753
1748
 
1754
1749
  next: function(element, expression, index) {
1755
1750
  element = $(element);
1756
1751
  if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
1757
1752
  var nextSiblings = element.nextSiblings();
1758
- return expression ? Selector.findElement(nextSiblings, expression, index) :
1759
- nextSiblings[index || 0];
1753
+ return Object.isNumber(expression) ? nextSiblings[expression] :
1754
+ Selector.findElement(nextSiblings, expression, index);
1760
1755
  },
1761
1756
 
1762
1757
  select: function() {
@@ -1797,10 +1792,11 @@ Element.Methods = {
1797
1792
  var attributes = { }, t = Element._attributeTranslations.write;
1798
1793
 
1799
1794
  if (typeof name == 'object') attributes = name;
1800
- else attributes[name] = value === undefined ? true : value;
1795
+ else attributes[name] = Object.isUndefined(value) ? true : value;
1801
1796
 
1802
1797
  for (var attr in attributes) {
1803
- var name = t.names[attr] || attr, value = attributes[attr];
1798
+ name = t.names[attr] || attr;
1799
+ value = attributes[attr];
1804
1800
  if (t.values[attr]) name = t.values[attr](element, value);
1805
1801
  if (value === false || value === null)
1806
1802
  element.removeAttribute(name);
@@ -1869,6 +1865,7 @@ Element.Methods = {
1869
1865
 
1870
1866
  descendantOf: function(element, ancestor) {
1871
1867
  element = $(element); ancestor = $(ancestor);
1868
+ var originalAncestor = ancestor;
1872
1869
 
1873
1870
  if (element.compareDocumentPosition)
1874
1871
  return (element.compareDocumentPosition(ancestor) & 8) === 8;
@@ -1880,11 +1877,12 @@ Element.Methods = {
1880
1877
  do { ancestor = ancestor.parentNode; }
1881
1878
  while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);
1882
1879
  }
1883
- if (nextAncestor) return (e > a && e < nextAncestor.sourceIndex);
1880
+ if (nextAncestor && nextAncestor.sourceIndex)
1881
+ return (e > a && e < nextAncestor.sourceIndex);
1884
1882
  }
1885
1883
 
1886
1884
  while (element = element.parentNode)
1887
- if (element == ancestor) return true;
1885
+ if (element == originalAncestor) return true;
1888
1886
  return false;
1889
1887
  },
1890
1888
 
@@ -1923,7 +1921,7 @@ Element.Methods = {
1923
1921
  if (property == 'opacity') element.setOpacity(styles[property]);
1924
1922
  else
1925
1923
  elementStyle[(property == 'float' || property == 'cssFloat') ?
1926
- (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
1924
+ (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
1927
1925
  property] = styles[property];
1928
1926
 
1929
1927
  return element;
@@ -2024,7 +2022,7 @@ Element.Methods = {
2024
2022
  if (element) {
2025
2023
  if (element.tagName == 'BODY') break;
2026
2024
  var p = Element.getStyle(element, 'position');
2027
- if (p == 'relative' || p == 'absolute') break;
2025
+ if (p !== 'static') break;
2028
2026
  }
2029
2027
  } while (element);
2030
2028
  return Element._returnOffset(valueL, valueT);
@@ -2173,72 +2171,75 @@ Element._attributeTranslations = {
2173
2171
  }
2174
2172
  };
2175
2173
 
2176
-
2177
- if (!document.createRange || Prototype.Browser.Opera) {
2178
- Element.Methods.insert = function(element, insertions) {
2179
- element = $(element);
2180
-
2181
- if (Object.isString(insertions) || Object.isNumber(insertions) ||
2182
- Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
2183
- insertions = { bottom: insertions };
2184
-
2185
- var t = Element._insertionTranslations, content, position, pos, tagName;
2186
-
2187
- for (position in insertions) {
2188
- content = insertions[position];
2189
- position = position.toLowerCase();
2190
- pos = t[position];
2191
-
2192
- if (content && content.toElement) content = content.toElement();
2193
- if (Object.isElement(content)) {
2194
- pos.insert(element, content);
2195
- continue;
2196
- }
2197
-
2198
- content = Object.toHTML(content);
2199
- tagName = ((position == 'before' || position == 'after')
2200
- ? element.parentNode : element).tagName.toUpperCase();
2201
-
2202
- if (t.tags[tagName]) {
2203
- var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
2204
- if (position == 'top' || position == 'after') fragments.reverse();
2205
- fragments.each(pos.insert.curry(element));
2174
+ if (Prototype.Browser.Opera) {
2175
+ Element.Methods.getStyle = Element.Methods.getStyle.wrap(
2176
+ function(proceed, element, style) {
2177
+ switch (style) {
2178
+ case 'left': case 'top': case 'right': case 'bottom':
2179
+ if (proceed(element, 'position') === 'static') return null;
2180
+ case 'height': case 'width':
2181
+ // returns '0px' for hidden elements; we want it to return null
2182
+ if (!Element.visible(element)) return null;
2183
+
2184
+ // returns the border-box dimensions rather than the content-box
2185
+ // dimensions, so we subtract padding and borders from the value
2186
+ var dim = parseInt(proceed(element, style), 10);
2187
+
2188
+ if (dim !== element['offset' + style.capitalize()])
2189
+ return dim + 'px';
2190
+
2191
+ var properties;
2192
+ if (style === 'height') {
2193
+ properties = ['border-top-width', 'padding-top',
2194
+ 'padding-bottom', 'border-bottom-width'];
2195
+ }
2196
+ else {
2197
+ properties = ['border-left-width', 'padding-left',
2198
+ 'padding-right', 'border-right-width'];
2199
+ }
2200
+ return properties.inject(dim, function(memo, property) {
2201
+ var val = proceed(element, property);
2202
+ return val === null ? memo : memo - parseInt(val, 10);
2203
+ }) + 'px';
2204
+ default: return proceed(element, style);
2206
2205
  }
2207
- else element.insertAdjacentHTML(pos.adjacency, content.stripScripts());
2208
-
2209
- content.evalScripts.bind(content).defer();
2210
2206
  }
2207
+ );
2211
2208
 
2212
- return element;
2213
- };
2214
- }
2215
-
2216
- if (Prototype.Browser.Opera) {
2217
- Element.Methods._getStyle = Element.Methods.getStyle;
2218
- Element.Methods.getStyle = function(element, style) {
2219
- switch(style) {
2220
- case 'left':
2221
- case 'top':
2222
- case 'right':
2223
- case 'bottom':
2224
- if (Element._getStyle(element, 'position') == 'static') return null;
2225
- default: return Element._getStyle(element, style);
2209
+ Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
2210
+ function(proceed, element, attribute) {
2211
+ if (attribute === 'title') return element.title;
2212
+ return proceed(element, attribute);
2226
2213
  }
2227
- };
2228
- Element.Methods._readAttribute = Element.Methods.readAttribute;
2229
- Element.Methods.readAttribute = function(element, attribute) {
2230
- if (attribute == 'title') return element.title;
2231
- return Element._readAttribute(element, attribute);
2232
- };
2214
+ );
2233
2215
  }
2234
2216
 
2235
2217
  else if (Prototype.Browser.IE) {
2236
- $w('positionedOffset getOffsetParent viewportOffset').each(function(method) {
2218
+ // IE doesn't report offsets correctly for static elements, so we change them
2219
+ // to "relative" to get the values, then change them back.
2220
+ Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
2221
+ function(proceed, element) {
2222
+ element = $(element);
2223
+ var position = element.getStyle('position');
2224
+ if (position !== 'static') return proceed(element);
2225
+ element.setStyle({ position: 'relative' });
2226
+ var value = proceed(element);
2227
+ element.setStyle({ position: position });
2228
+ return value;
2229
+ }
2230
+ );
2231
+
2232
+ $w('positionedOffset viewportOffset').each(function(method) {
2237
2233
  Element.Methods[method] = Element.Methods[method].wrap(
2238
2234
  function(proceed, element) {
2239
2235
  element = $(element);
2240
2236
  var position = element.getStyle('position');
2241
- if (position != 'static') return proceed(element);
2237
+ if (position !== 'static') return proceed(element);
2238
+ // Trigger hasLayout on the offset parent so that IE6 reports
2239
+ // accurate offsetTop and offsetLeft values for position: fixed.
2240
+ var offsetParent = element.getOffsetParent();
2241
+ if (offsetParent && offsetParent.getStyle('position') === 'fixed')
2242
+ offsetParent.setStyle({ zoom: 1 });
2242
2243
  element.setStyle({ position: 'relative' });
2243
2244
  var value = proceed(element);
2244
2245
  element.setStyle({ position: position });
@@ -2303,7 +2304,7 @@ else if (Prototype.Browser.IE) {
2303
2304
  return node ? node.value : "";
2304
2305
  },
2305
2306
  _getEv: function(element, attribute) {
2306
- var attribute = element.getAttribute(attribute);
2307
+ attribute = element.getAttribute(attribute);
2307
2308
  return attribute ? attribute.toString().slice(23, -2) : null;
2308
2309
  },
2309
2310
  _flag: function(element, attribute) {
@@ -2320,7 +2321,10 @@ else if (Prototype.Browser.IE) {
2320
2321
  };
2321
2322
 
2322
2323
  Element._attributeTranslations.write = {
2323
- names: Object.clone(Element._attributeTranslations.read.names),
2324
+ names: Object.extend({
2325
+ cellpadding: 'cellPadding',
2326
+ cellspacing: 'cellSpacing'
2327
+ }, Element._attributeTranslations.read.names),
2324
2328
  values: {
2325
2329
  checked: function(element, value) {
2326
2330
  element.checked = !!value;
@@ -2400,7 +2404,7 @@ else if (Prototype.Browser.WebKit) {
2400
2404
  };
2401
2405
 
2402
2406
  // Safari returns margins on body which is incorrect if the child is absolutely
2403
- // positioned. For performance reasons, redefine Position.cumulativeOffset for
2407
+ // positioned. For performance reasons, redefine Element#cumulativeOffset for
2404
2408
  // KHTML/WebKit only.
2405
2409
  Element.Methods.cumulativeOffset = function(element) {
2406
2410
  var valueT = 0, valueL = 0;
@@ -2440,7 +2444,7 @@ if (Prototype.Browser.IE || Prototype.Browser.Opera) {
2440
2444
  };
2441
2445
  }
2442
2446
 
2443
- if (document.createElement('div').outerHTML) {
2447
+ if ('outerHTML' in document.createElement('div')) {
2444
2448
  Element.Methods.replace = function(element, content) {
2445
2449
  element = $(element);
2446
2450
 
@@ -2478,45 +2482,25 @@ Element._returnOffset = function(l, t) {
2478
2482
 
2479
2483
  Element._getContentFromAnonymousElement = function(tagName, html) {
2480
2484
  var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
2481
- div.innerHTML = t[0] + html + t[1];
2482
- t[2].times(function() { div = div.firstChild; });
2485
+ if (t) {
2486
+ div.innerHTML = t[0] + html + t[1];
2487
+ t[2].times(function() { div = div.firstChild; });
2488
+ } else div.innerHTML = html;
2483
2489
  return $A(div.childNodes);
2484
2490
  };
2485
2491
 
2486
2492
  Element._insertionTranslations = {
2487
- before: {
2488
- adjacency: 'beforeBegin',
2489
- insert: function(element, node) {
2490
- element.parentNode.insertBefore(node, element);
2491
- },
2492
- initializeRange: function(element, range) {
2493
- range.setStartBefore(element);
2494
- }
2493
+ before: function(element, node) {
2494
+ element.parentNode.insertBefore(node, element);
2495
2495
  },
2496
- top: {
2497
- adjacency: 'afterBegin',
2498
- insert: function(element, node) {
2499
- element.insertBefore(node, element.firstChild);
2500
- },
2501
- initializeRange: function(element, range) {
2502
- range.selectNodeContents(element);
2503
- range.collapse(true);
2504
- }
2496
+ top: function(element, node) {
2497
+ element.insertBefore(node, element.firstChild);
2505
2498
  },
2506
- bottom: {
2507
- adjacency: 'beforeEnd',
2508
- insert: function(element, node) {
2509
- element.appendChild(node);
2510
- }
2499
+ bottom: function(element, node) {
2500
+ element.appendChild(node);
2511
2501
  },
2512
- after: {
2513
- adjacency: 'afterEnd',
2514
- insert: function(element, node) {
2515
- element.parentNode.insertBefore(node, element.nextSibling);
2516
- },
2517
- initializeRange: function(element, range) {
2518
- range.setStartAfter(element);
2519
- }
2502
+ after: function(element, node) {
2503
+ element.parentNode.insertBefore(node, element.nextSibling);
2520
2504
  },
2521
2505
  tags: {
2522
2506
  TABLE: ['<table>', '</table>', 1],
@@ -2528,7 +2512,6 @@ Element._insertionTranslations = {
2528
2512
  };
2529
2513
 
2530
2514
  (function() {
2531
- this.bottom.initializeRange = this.top.initializeRange;
2532
2515
  Object.extend(this.tags, {
2533
2516
  THEAD: this.tags.TBODY,
2534
2517
  TFOOT: this.tags.TBODY,
@@ -2689,10 +2672,11 @@ Element.addMethods = function(methods) {
2689
2672
  document.viewport = {
2690
2673
  getDimensions: function() {
2691
2674
  var dimensions = { };
2675
+ var B = Prototype.Browser;
2692
2676
  $w('width height').each(function(d) {
2693
2677
  var D = d.capitalize();
2694
- dimensions[d] = self['inner' + D] ||
2695
- (document.documentElement['client' + D] || document.body['client' + D]);
2678
+ dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] :
2679
+ (B.Opera) ? document.body['client' + D] : document.documentElement['client' + D];
2696
2680
  });
2697
2681
  return dimensions;
2698
2682
  },
@@ -2721,9 +2705,26 @@ var Selector = Class.create({
2721
2705
  this.compileMatcher();
2722
2706
  },
2723
2707
 
2708
+ shouldUseXPath: function() {
2709
+ if (!Prototype.BrowserFeatures.XPath) return false;
2710
+
2711
+ var e = this.expression;
2712
+
2713
+ // Safari 3 chokes on :*-of-type and :empty
2714
+ if (Prototype.Browser.WebKit &&
2715
+ (e.include("-of-type") || e.include(":empty")))
2716
+ return false;
2717
+
2718
+ // XPath can't do namespaced attributes, nor can it read
2719
+ // the "checked" property from DOM nodes
2720
+ if ((/(\[[\w-]*?:|:checked)/).test(this.expression))
2721
+ return false;
2722
+
2723
+ return true;
2724
+ },
2725
+
2724
2726
  compileMatcher: function() {
2725
- // Selectors with namespaced attributes can't use the XPath version
2726
- if (Prototype.BrowserFeatures.XPath && !(/(\[[\w-]*?:|:checked)/).test(this.expression))
2727
+ if (this.shouldUseXPath())
2727
2728
  return this.compileXPathMatcher();
2728
2729
 
2729
2730
  var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
@@ -2846,8 +2847,12 @@ Object.extend(Selector, {
2846
2847
  },
2847
2848
  className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
2848
2849
  id: "[@id='#{1}']",
2849
- attrPresence: "[@#{1}]",
2850
+ attrPresence: function(m) {
2851
+ m[1] = m[1].toLowerCase();
2852
+ return new Template("[@#{1}]").evaluate(m);
2853
+ },
2850
2854
  attr: function(m) {
2855
+ m[1] = m[1].toLowerCase();
2851
2856
  m[3] = m[5] || m[6];
2852
2857
  return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
2853
2858
  },
@@ -2876,7 +2881,7 @@ Object.extend(Selector, {
2876
2881
  'enabled': "[not(@disabled)]",
2877
2882
  'not': function(m) {
2878
2883
  var e = m[6], p = Selector.patterns,
2879
- x = Selector.xpath, le, m, v;
2884
+ x = Selector.xpath, le, v;
2880
2885
 
2881
2886
  var exclusion = [];
2882
2887
  while (e && le != e && (/\S/).test(e)) {
@@ -2933,13 +2938,13 @@ Object.extend(Selector, {
2933
2938
  },
2934
2939
 
2935
2940
  criteria: {
2936
- tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
2937
- className: 'n = h.className(n, r, "#{1}", c); c = false;',
2938
- id: 'n = h.id(n, r, "#{1}", c); c = false;',
2939
- attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
2941
+ tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
2942
+ className: 'n = h.className(n, r, "#{1}", c); c = false;',
2943
+ id: 'n = h.id(n, r, "#{1}", c); c = false;',
2944
+ attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;',
2940
2945
  attr: function(m) {
2941
2946
  m[3] = (m[5] || m[6]);
2942
- return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
2947
+ return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);
2943
2948
  },
2944
2949
  pseudo: function(m) {
2945
2950
  if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
@@ -2963,7 +2968,8 @@ Object.extend(Selector, {
2963
2968
  tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
2964
2969
  id: /^#([\w\-\*]+)(\b|$)/,
2965
2970
  className: /^\.([\w\-\*]+)(\b|$)/,
2966
- pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s)|(?=:))/,
2971
+ pseudo:
2972
+ /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,
2967
2973
  attrPresence: /^\[([\w]+)\]/,
2968
2974
  attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
2969
2975
  },
@@ -2988,7 +2994,7 @@ Object.extend(Selector, {
2988
2994
 
2989
2995
  attr: function(element, matches) {
2990
2996
  var nodeValue = Element.readAttribute(element, matches[1]);
2991
- return Selector.operators[matches[2]](nodeValue, matches[3]);
2997
+ return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);
2992
2998
  }
2993
2999
  },
2994
3000
 
@@ -3003,14 +3009,15 @@ Object.extend(Selector, {
3003
3009
 
3004
3010
  // marks an array of nodes for counting
3005
3011
  mark: function(nodes) {
3012
+ var _true = Prototype.emptyFunction;
3006
3013
  for (var i = 0, node; node = nodes[i]; i++)
3007
- node._counted = true;
3014
+ node._countedByPrototype = _true;
3008
3015
  return nodes;
3009
3016
  },
3010
3017
 
3011
3018
  unmark: function(nodes) {
3012
3019
  for (var i = 0, node; node = nodes[i]; i++)
3013
- node._counted = undefined;
3020
+ node._countedByPrototype = undefined;
3014
3021
  return nodes;
3015
3022
  },
3016
3023
 
@@ -3018,15 +3025,15 @@ Object.extend(Selector, {
3018
3025
  // "ofType" flag indicates whether we're indexing for nth-of-type
3019
3026
  // rather than nth-child
3020
3027
  index: function(parentNode, reverse, ofType) {
3021
- parentNode._counted = true;
3028
+ parentNode._countedByPrototype = Prototype.emptyFunction;
3022
3029
  if (reverse) {
3023
3030
  for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
3024
3031
  var node = nodes[i];
3025
- if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
3032
+ if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
3026
3033
  }
3027
3034
  } else {
3028
3035
  for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
3029
- if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
3036
+ if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
3030
3037
  }
3031
3038
  },
3032
3039
 
@@ -3035,8 +3042,8 @@ Object.extend(Selector, {
3035
3042
  if (nodes.length == 0) return nodes;
3036
3043
  var results = [], n;
3037
3044
  for (var i = 0, l = nodes.length; i < l; i++)
3038
- if (!(n = nodes[i])._counted) {
3039
- n._counted = true;
3045
+ if (!(n = nodes[i])._countedByPrototype) {
3046
+ n._countedByPrototype = Prototype.emptyFunction;
3040
3047
  results.push(Element.extend(n));
3041
3048
  }
3042
3049
  return Selector.handlers.unmark(results);
@@ -3053,7 +3060,7 @@ Object.extend(Selector, {
3053
3060
  child: function(nodes) {
3054
3061
  var h = Selector.handlers;
3055
3062
  for (var i = 0, results = [], node; node = nodes[i]; i++) {
3056
- for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
3063
+ for (var j = 0, child; child = node.childNodes[j]; j++)
3057
3064
  if (child.nodeType == 1 && child.tagName != '!') results.push(child);
3058
3065
  }
3059
3066
  return results;
@@ -3088,7 +3095,7 @@ Object.extend(Selector, {
3088
3095
 
3089
3096
  // TOKEN FUNCTIONS
3090
3097
  tagName: function(nodes, root, tagName, combinator) {
3091
- tagName = tagName.toUpperCase();
3098
+ var uTagName = tagName.toUpperCase();
3092
3099
  var results = [], h = Selector.handlers;
3093
3100
  if (nodes) {
3094
3101
  if (combinator) {
@@ -3101,7 +3108,7 @@ Object.extend(Selector, {
3101
3108
  if (tagName == "*") return nodes;
3102
3109
  }
3103
3110
  for (var i = 0, node; node = nodes[i]; i++)
3104
- if (node.tagName.toUpperCase() == tagName) results.push(node);
3111
+ if (node.tagName.toUpperCase() === uTagName) results.push(node);
3105
3112
  return results;
3106
3113
  } else return root.getElementsByTagName(tagName);
3107
3114
  },
@@ -3148,16 +3155,18 @@ Object.extend(Selector, {
3148
3155
  return results;
3149
3156
  },
3150
3157
 
3151
- attrPresence: function(nodes, root, attr) {
3158
+ attrPresence: function(nodes, root, attr, combinator) {
3152
3159
  if (!nodes) nodes = root.getElementsByTagName("*");
3160
+ if (nodes && combinator) nodes = this[combinator](nodes);
3153
3161
  var results = [];
3154
3162
  for (var i = 0, node; node = nodes[i]; i++)
3155
3163
  if (Element.hasAttribute(node, attr)) results.push(node);
3156
3164
  return results;
3157
3165
  },
3158
3166
 
3159
- attr: function(nodes, root, attr, value, operator) {
3167
+ attr: function(nodes, root, attr, value, operator, combinator) {
3160
3168
  if (!nodes) nodes = root.getElementsByTagName("*");
3169
+ if (nodes && combinator) nodes = this[combinator](nodes);
3161
3170
  var handler = Selector.operators[operator], results = [];
3162
3171
  for (var i = 0, node; node = nodes[i]; i++) {
3163
3172
  var nodeValue = Element.readAttribute(node, attr);
@@ -3236,7 +3245,7 @@ Object.extend(Selector, {
3236
3245
  var h = Selector.handlers, results = [], indexed = [], m;
3237
3246
  h.mark(nodes);
3238
3247
  for (var i = 0, node; node = nodes[i]; i++) {
3239
- if (!node.parentNode._counted) {
3248
+ if (!node.parentNode._countedByPrototype) {
3240
3249
  h.index(node.parentNode, reverse, ofType);
3241
3250
  indexed.push(node.parentNode);
3242
3251
  }
@@ -3274,7 +3283,7 @@ Object.extend(Selector, {
3274
3283
  var exclusions = new Selector(selector).findElements(root);
3275
3284
  h.mark(exclusions);
3276
3285
  for (var i = 0, results = [], node; node = nodes[i]; i++)
3277
- if (!node._counted) results.push(node);
3286
+ if (!node._countedByPrototype) results.push(node);
3278
3287
  h.unmark(exclusions);
3279
3288
  return results;
3280
3289
  },
@@ -3308,11 +3317,19 @@ Object.extend(Selector, {
3308
3317
  '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
3309
3318
  },
3310
3319
 
3320
+ split: function(expression) {
3321
+ var expressions = [];
3322
+ expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
3323
+ expressions.push(m[1].strip());
3324
+ });
3325
+ return expressions;
3326
+ },
3327
+
3311
3328
  matchElements: function(elements, expression) {
3312
- var matches = new Selector(expression).findElements(), h = Selector.handlers;
3329
+ var matches = $$(expression), h = Selector.handlers;
3313
3330
  h.mark(matches);
3314
3331
  for (var i = 0, results = [], element; element = elements[i]; i++)
3315
- if (element._counted) results.push(element);
3332
+ if (element._countedByPrototype) results.push(element);
3316
3333
  h.unmark(matches);
3317
3334
  return results;
3318
3335
  },
@@ -3325,10 +3342,7 @@ Object.extend(Selector, {
3325
3342
  },
3326
3343
 
3327
3344
  findChildElements: function(element, expressions) {
3328
- var exprs = expressions.join(','), expressions = [];
3329
- exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
3330
- expressions.push(m[1].strip());
3331
- });
3345
+ expressions = Selector.split(expressions.join(','));
3332
3346
  var results = [], h = Selector.handlers;
3333
3347
  for (var i = 0, l = expressions.length, selector; i < l; i++) {
3334
3348
  selector = new Selector(expressions[i].strip());
@@ -3338,6 +3352,25 @@ Object.extend(Selector, {
3338
3352
  }
3339
3353
  });
3340
3354
 
3355
+ if (Prototype.Browser.IE) {
3356
+ Object.extend(Selector.handlers, {
3357
+ // IE returns comment nodes on getElementsByTagName("*").
3358
+ // Filter them out.
3359
+ concat: function(a, b) {
3360
+ for (var i = 0, node; node = b[i]; i++)
3361
+ if (node.tagName !== "!") a.push(node);
3362
+ return a;
3363
+ },
3364
+
3365
+ // IE improperly serializes _countedByPrototype in (inner|outer)HTML.
3366
+ unmark: function(nodes) {
3367
+ for (var i = 0, node; node = nodes[i]; i++)
3368
+ node.removeAttribute('_countedByPrototype');
3369
+ return nodes;
3370
+ }
3371
+ });
3372
+ }
3373
+
3341
3374
  function $$() {
3342
3375
  return Selector.findChildElements(document, $A(arguments));
3343
3376
  }
@@ -3349,7 +3382,7 @@ var Form = {
3349
3382
 
3350
3383
  serializeElements: function(elements, options) {
3351
3384
  if (typeof options != 'object') options = { hash: !!options };
3352
- else if (options.hash === undefined) options.hash = true;
3385
+ else if (Object.isUndefined(options.hash)) options.hash = true;
3353
3386
  var key, value, submitted = false, submit = options.submit;
3354
3387
 
3355
3388
  var data = elements.inject({ }, function(result, element) {
@@ -3547,17 +3580,17 @@ Form.Element.Serializers = {
3547
3580
  },
3548
3581
 
3549
3582
  inputSelector: function(element, value) {
3550
- if (value === undefined) return element.checked ? element.value : null;
3583
+ if (Object.isUndefined(value)) return element.checked ? element.value : null;
3551
3584
  else element.checked = !!value;
3552
3585
  },
3553
3586
 
3554
3587
  textarea: function(element, value) {
3555
- if (value === undefined) return element.value;
3588
+ if (Object.isUndefined(value)) return element.value;
3556
3589
  else element.value = value;
3557
3590
  },
3558
3591
 
3559
3592
  select: function(element, index) {
3560
- if (index === undefined)
3593
+ if (Object.isUndefined(index))
3561
3594
  return this[element.type == 'select-one' ?
3562
3595
  'selectOne' : 'selectMany'](element);
3563
3596
  else {
@@ -3748,7 +3781,9 @@ Event.Methods = (function() {
3748
3781
 
3749
3782
  findElement: function(event, expression) {
3750
3783
  var element = Event.element(event);
3751
- return element.match(expression) ? element : element.up(expression);
3784
+ if (!expression) return element;
3785
+ var elements = [element].concat(element.ancestors());
3786
+ return Selector.findElement(elements, expression, 0);
3752
3787
  },
3753
3788
 
3754
3789
  pointer: function(event) {
@@ -3811,9 +3846,9 @@ Object.extend(Event, (function() {
3811
3846
  var cache = Event.cache;
3812
3847
 
3813
3848
  function getEventID(element) {
3814
- if (element._eventID) return element._eventID;
3849
+ if (element._prototypeEventID) return element._prototypeEventID[0];
3815
3850
  arguments.callee.id = arguments.callee.id || 1;
3816
- return element._eventID = ++arguments.callee.id;
3851
+ return element._prototypeEventID = [++arguments.callee.id];
3817
3852
  }
3818
3853
 
3819
3854
  function getDOMEventName(eventName) {
@@ -3923,11 +3958,12 @@ Object.extend(Event, (function() {
3923
3958
  if (element == document && document.createEvent && !element.dispatchEvent)
3924
3959
  element = document.documentElement;
3925
3960
 
3961
+ var event;
3926
3962
  if (document.createEvent) {
3927
- var event = document.createEvent("HTMLEvents");
3963
+ event = document.createEvent("HTMLEvents");
3928
3964
  event.initEvent("dataavailable", true, true);
3929
3965
  } else {
3930
- var event = document.createEventObject();
3966
+ event = document.createEventObject();
3931
3967
  event.eventType = "ondataavailable";
3932
3968
  }
3933
3969
 
@@ -3940,7 +3976,7 @@ Object.extend(Event, (function() {
3940
3976
  element.fireEvent(event.eventType, event);
3941
3977
  }
3942
3978
 
3943
- return event;
3979
+ return Event.extend(event);
3944
3980
  }
3945
3981
  };
3946
3982
  })());
@@ -3956,20 +3992,21 @@ Element.addMethods({
3956
3992
  Object.extend(document, {
3957
3993
  fire: Element.Methods.fire.methodize(),
3958
3994
  observe: Element.Methods.observe.methodize(),
3959
- stopObserving: Element.Methods.stopObserving.methodize()
3995
+ stopObserving: Element.Methods.stopObserving.methodize(),
3996
+ loaded: false
3960
3997
  });
3961
3998
 
3962
3999
  (function() {
3963
4000
  /* Support for the DOMContentLoaded event is based on work by Dan Webb,
3964
4001
  Matthias Miller, Dean Edwards and John Resig. */
3965
4002
 
3966
- var timer, fired = false;
4003
+ var timer;
3967
4004
 
3968
4005
  function fireContentLoadedEvent() {
3969
- if (fired) return;
4006
+ if (document.loaded) return;
3970
4007
  if (timer) window.clearInterval(timer);
3971
4008
  document.fire("dom:loaded");
3972
- fired = true;
4009
+ document.loaded = true;
3973
4010
  }
3974
4011
 
3975
4012
  if (document.addEventListener) {
@@ -4183,4 +4220,4 @@ Object.extend(Element.ClassNames.prototype, Enumerable);
4183
4220
 
4184
4221
  /*--------------------------------------------------------------------------*/
4185
4222
 
4186
- Element.addMethods();
4223
+ Element.addMethods();