activeldap 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. data/CHANGES +34 -0
  2. data/README +13 -0
  3. data/Rakefile +2 -1
  4. data/TODO +6 -0
  5. data/benchmark/bench-al.rb +68 -17
  6. data/examples/al-admin/app/helpers/application_helper.rb +3 -5
  7. data/examples/al-admin/app/views/layouts/_footer.html.erb +2 -0
  8. data/examples/al-admin/config/boot.rb +7 -7
  9. data/examples/al-admin/config/environment.rb +27 -12
  10. data/examples/al-admin/config/environments/development.rb +0 -1
  11. data/examples/al-admin/config/environments/production.rb +6 -1
  12. data/examples/al-admin/config/environments/test.rb +1 -1
  13. data/examples/al-admin/config/initializers/gettext.rb +15 -1
  14. data/examples/al-admin/po/en/al-admin.po +1 -1
  15. data/examples/al-admin/po/ja/al-admin.po +1 -1
  16. data/examples/al-admin/po/nl/al-admin.po +1 -1
  17. data/examples/al-admin/public/dispatch.cgi +0 -0
  18. data/examples/al-admin/public/dispatch.fcgi +0 -0
  19. data/examples/al-admin/public/dispatch.rb +0 -0
  20. data/examples/al-admin/public/javascripts/controls.js +73 -73
  21. data/examples/al-admin/public/javascripts/dragdrop.js +166 -165
  22. data/examples/al-admin/public/javascripts/effects.js +174 -166
  23. data/examples/al-admin/public/javascripts/prototype.js +362 -267
  24. data/examples/al-admin/script/about +0 -0
  25. data/examples/al-admin/script/console +0 -0
  26. data/examples/al-admin/script/dbconsole +3 -0
  27. data/examples/al-admin/script/destroy +0 -0
  28. data/examples/al-admin/script/generate +0 -0
  29. data/examples/al-admin/script/performance/benchmarker +0 -0
  30. data/examples/al-admin/script/performance/profiler +0 -0
  31. data/examples/al-admin/script/performance/request +0 -0
  32. data/examples/al-admin/script/plugin +0 -0
  33. data/examples/al-admin/script/process/inspector +0 -0
  34. data/examples/al-admin/script/process/reaper +0 -0
  35. data/examples/al-admin/script/process/spawner +0 -0
  36. data/examples/al-admin/script/runner +0 -0
  37. data/examples/al-admin/script/server +0 -0
  38. data/examples/al-admin/test/run-test.sh +0 -0
  39. data/examples/groupadd +0 -0
  40. data/examples/groupdel +0 -0
  41. data/examples/groupls +0 -0
  42. data/examples/groupmod +0 -0
  43. data/examples/lpasswd +0 -0
  44. data/examples/ouadd +0 -0
  45. data/examples/useradd +0 -0
  46. data/examples/useradd-binary +0 -0
  47. data/examples/userdel +0 -0
  48. data/examples/userls +0 -0
  49. data/examples/usermod +0 -0
  50. data/examples/usermod-binary-add +0 -0
  51. data/examples/usermod-binary-add-time +0 -0
  52. data/examples/usermod-binary-del +0 -0
  53. data/examples/usermod-lang-add +0 -0
  54. data/lib/active_ldap.rb +10 -4
  55. data/lib/active_ldap/action_controller/ldap_benchmarking.rb +28 -9
  56. data/lib/active_ldap/adapter/base.rb +30 -17
  57. data/lib/active_ldap/adapter/jndi.rb +5 -1
  58. data/lib/active_ldap/adapter/ldap.rb +5 -1
  59. data/lib/active_ldap/association/has_many_utils.rb +7 -1
  60. data/lib/active_ldap/associations.rb +10 -5
  61. data/lib/active_ldap/attributes.rb +6 -1
  62. data/lib/active_ldap/base.rb +154 -52
  63. data/lib/active_ldap/configuration.rb +1 -1
  64. data/lib/active_ldap/connection.rb +7 -4
  65. data/lib/active_ldap/get_text.rb +11 -3
  66. data/lib/active_ldap/ldif.rb +16 -4
  67. data/lib/active_ldap/operations.rb +13 -5
  68. data/lib/active_ldap/schema.rb +6 -2
  69. data/lib/active_ldap/schema/syntaxes.rb +15 -3
  70. data/lib/active_ldap/user_password.rb +4 -4
  71. data/lib/active_ldap/validations.rb +32 -44
  72. data/lib/active_ldap/xml.rb +125 -0
  73. data/po/en/active-ldap.po +740 -85
  74. data/po/ja/active-ldap.po +748 -547
  75. data/rails/README +54 -0
  76. data/rails/init.rb +33 -0
  77. data/rails/plugin/active_ldap/generators/README +2 -0
  78. data/rails/plugin/active_ldap/generators/model_active_ldap/model_active_ldap_generator.rb +1 -1
  79. data/rails/plugin/active_ldap/init.rb +3 -0
  80. data/rails_generators/model_active_ldap/USAGE +17 -0
  81. data/rails_generators/model_active_ldap/model_active_ldap_generator.rb +69 -0
  82. data/rails_generators/model_active_ldap/templates/model_active_ldap.rb +3 -0
  83. data/rails_generators/model_active_ldap/templates/unit_test.rb +8 -0
  84. data/rails_generators/scaffold_active_ldap/scaffold_active_ldap_generator.rb +7 -0
  85. data/rails_generators/scaffold_active_ldap/templates/ldap.yml +18 -0
  86. data/rails_generators/scaffold_al/scaffold_al_generator.rb +20 -0
  87. data/test-unit/History.txt +50 -1
  88. data/test-unit/Manifest.txt +22 -12
  89. data/test-unit/README.txt +31 -12
  90. data/test-unit/Rakefile +14 -1
  91. data/test-unit/TODO +5 -0
  92. data/test-unit/bin/testrb +0 -0
  93. data/test-unit/lib/test/unit.rb +62 -0
  94. data/test-unit/lib/test/unit/assertions.rb +419 -75
  95. data/test-unit/lib/test/unit/autorunner.rb +70 -13
  96. data/test-unit/lib/test/unit/collector.rb +1 -1
  97. data/test-unit/lib/test/unit/collector/load.rb +1 -1
  98. data/test-unit/lib/test/unit/color-scheme.rb +86 -0
  99. data/test-unit/lib/test/unit/color.rb +40 -5
  100. data/test-unit/lib/test/unit/diff.rb +14 -0
  101. data/test-unit/lib/test/unit/fixture.rb +7 -16
  102. data/test-unit/lib/test/unit/notification.rb +9 -0
  103. data/test-unit/lib/test/unit/omission.rb +14 -0
  104. data/test-unit/lib/test/unit/pending.rb +16 -0
  105. data/test-unit/lib/test/unit/priority.rb +17 -2
  106. data/test-unit/lib/test/unit/runner/console.rb +8 -2
  107. data/test-unit/lib/test/unit/testcase.rb +188 -2
  108. data/test-unit/lib/test/unit/ui/console/testrunner.rb +51 -26
  109. data/test-unit/lib/test/unit/util/method-owner-finder.rb +28 -0
  110. data/test-unit/lib/test/unit/version.rb +1 -1
  111. data/test-unit/sample/test_user.rb +22 -0
  112. data/test-unit/test/collector/{test_descendant.rb → test-descendant.rb} +0 -0
  113. data/test-unit/test/collector/{test_load.rb → test-load.rb} +1 -1
  114. data/test-unit/test/run-test.rb +0 -0
  115. data/test-unit/test/{test_attribute.rb → test-attribute.rb} +0 -0
  116. data/test-unit/test/test-color-scheme.rb +56 -0
  117. data/test-unit/test/{test_color.rb → test-color.rb} +10 -0
  118. data/test-unit/test/{test_diff.rb → test-diff.rb} +0 -0
  119. data/test-unit/test/{test_emacs_runner.rb → test-emacs-runner.rb} +0 -0
  120. data/test-unit/test/test-fixture.rb +287 -0
  121. data/test-unit/test/{test_notification.rb → test-notification.rb} +4 -4
  122. data/test-unit/test/{test_omission.rb → test-omission.rb} +6 -6
  123. data/test-unit/test/{test_pending.rb → test-pending.rb} +12 -6
  124. data/test-unit/test/{test_priority.rb → test-priority.rb} +30 -0
  125. data/test-unit/test/test_assertions.rb +411 -69
  126. data/test-unit/test/test_testcase.rb +70 -3
  127. data/test-unit/test/{testunit_test_util.rb → testunit-test-util.rb} +4 -2
  128. data/test-unit/test/ui/test_testrunmediator.rb +1 -1
  129. data/test-unit/test/util/test-method-owner-finder.rb +38 -0
  130. data/test/run-test.rb +0 -0
  131. data/test/test_adapter.rb +3 -0
  132. data/test/test_associations.rb +50 -7
  133. data/test/test_base.rb +193 -11
  134. data/test/test_connection_per_dn.rb +1 -1
  135. data/test/test_ldif.rb +86 -0
  136. data/test/test_load.rb +7 -0
  137. data/test/test_schema.rb +31 -1
  138. data/test/test_syntax.rb +20 -0
  139. data/test/test_user_password.rb +22 -14
  140. data/test/test_validation.rb +70 -29
  141. metadata +99 -77
  142. data/data/locale/en/LC_MESSAGES/active-ldap.mo +0 -0
  143. data/data/locale/ja/LC_MESSAGES/active-ldap.mo +0 -0
  144. data/examples/al-admin/config/initializers/ralative_url_support.rb +0 -1
  145. data/examples/al-admin/lib/accept_http_rails_relative_url_root.rb +0 -9
  146. data/test-unit-ext/misc/rd2html.rb +0 -42
  147. data/test-unit/test/test_fixture.rb +0 -275
@@ -1,5 +1,5 @@
1
- /* Prototype JavaScript framework, version 1.6.0.1
2
- * (c) 2005-2007 Sam Stephenson
1
+ /* Prototype JavaScript framework, version 1.6.0.3
2
+ * (c) 2005-2008 Sam Stephenson
3
3
  *
4
4
  * Prototype is freely distributable under the terms of an MIT-style license.
5
5
  * For details, see the Prototype web site: http://www.prototypejs.org/
@@ -7,23 +7,26 @@
7
7
  *--------------------------------------------------------------------------*/
8
8
 
9
9
  var Prototype = {
10
- Version: '1.6.0.1',
10
+ Version: '1.6.0.3',
11
11
 
12
12
  Browser: {
13
- IE: !!(window.attachEvent && !window.opera),
14
- Opera: !!window.opera,
13
+ IE: !!(window.attachEvent &&
14
+ navigator.userAgent.indexOf('Opera') === -1),
15
+ Opera: navigator.userAgent.indexOf('Opera') > -1,
15
16
  WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
16
- Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
17
+ Gecko: navigator.userAgent.indexOf('Gecko') > -1 &&
18
+ navigator.userAgent.indexOf('KHTML') === -1,
17
19
  MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
18
20
  },
19
21
 
20
22
  BrowserFeatures: {
21
23
  XPath: !!document.evaluate,
24
+ SelectorsAPI: !!document.querySelector,
22
25
  ElementExtensions: !!window.HTMLElement,
23
26
  SpecificElementExtensions:
24
- document.createElement('div').__proto__ &&
25
- document.createElement('div').__proto__ !==
26
- document.createElement('form').__proto__
27
+ document.createElement('div')['__proto__'] &&
28
+ document.createElement('div')['__proto__'] !==
29
+ document.createElement('form')['__proto__']
27
30
  },
28
31
 
29
32
  ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
@@ -83,12 +86,13 @@ Class.Methods = {
83
86
  var property = properties[i], value = source[property];
84
87
  if (ancestor && Object.isFunction(value) &&
85
88
  value.argumentNames().first() == "$super") {
86
- var method = value, value = Object.extend((function(m) {
89
+ var method = value;
90
+ value = (function(m) {
87
91
  return function() { return ancestor[m].apply(this, arguments) };
88
- })(property).wrap(method), {
89
- valueOf: function() { return method },
90
- toString: function() { return method.toString() }
91
- });
92
+ })(property).wrap(method);
93
+
94
+ value.valueOf = method.valueOf.bind(method);
95
+ value.toString = method.toString.bind(method);
92
96
  }
93
97
  this.prototype[property] = value;
94
98
  }
@@ -110,7 +114,7 @@ Object.extend(Object, {
110
114
  try {
111
115
  if (Object.isUndefined(object)) return 'undefined';
112
116
  if (object === null) return 'null';
113
- return object.inspect ? object.inspect() : object.toString();
117
+ return object.inspect ? object.inspect() : String(object);
114
118
  } catch (e) {
115
119
  if (e instanceof RangeError) return '...';
116
120
  throw e;
@@ -167,11 +171,12 @@ Object.extend(Object, {
167
171
  },
168
172
 
169
173
  isElement: function(object) {
170
- return object && object.nodeType == 1;
174
+ return !!(object && object.nodeType == 1);
171
175
  },
172
176
 
173
177
  isArray: function(object) {
174
- return object && object.constructor === Array;
178
+ return object != null && typeof object == "object" &&
179
+ 'splice' in object && 'join' in object;
175
180
  },
176
181
 
177
182
  isHash: function(object) {
@@ -197,7 +202,8 @@ Object.extend(Object, {
197
202
 
198
203
  Object.extend(Function.prototype, {
199
204
  argumentNames: function() {
200
- var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip");
205
+ var names = this.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1]
206
+ .replace(/\s+/g, '').split(',');
201
207
  return names.length == 1 && !names[0] ? [] : names;
202
208
  },
203
209
 
@@ -231,6 +237,11 @@ Object.extend(Function.prototype, {
231
237
  }, timeout);
232
238
  },
233
239
 
240
+ defer: function() {
241
+ var args = [0.01].concat($A(arguments));
242
+ return this.delay.apply(this, args);
243
+ },
244
+
234
245
  wrap: function(wrapper) {
235
246
  var __method = this;
236
247
  return function() {
@@ -247,8 +258,6 @@ Object.extend(Function.prototype, {
247
258
  }
248
259
  });
249
260
 
250
- Function.prototype.defer = Function.prototype.delay.curry(0.01);
251
-
252
261
  Date.prototype.toJSON = function() {
253
262
  return '"' + this.getUTCFullYear() + '-' +
254
263
  (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
@@ -529,7 +538,7 @@ if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.proto
529
538
  return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
530
539
  },
531
540
  unescapeHTML: function() {
532
- return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
541
+ return this.stripTags().replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
533
542
  }
534
543
  });
535
544
 
@@ -546,7 +555,7 @@ Object.extend(String.prototype.escapeHTML, {
546
555
  text: document.createTextNode('')
547
556
  });
548
557
 
549
- with (String.prototype.escapeHTML) div.appendChild(text);
558
+ String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text);
550
559
 
551
560
  var Template = Class.create({
552
561
  initialize: function(template, pattern) {
@@ -578,7 +587,7 @@ var Template = Class.create({
578
587
  }
579
588
 
580
589
  return before + String.interpret(ctx);
581
- }.bind(this));
590
+ });
582
591
  }
583
592
  });
584
593
  Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
@@ -588,10 +597,9 @@ var $break = { };
588
597
  var Enumerable = {
589
598
  each: function(iterator, context) {
590
599
  var index = 0;
591
- iterator = iterator.bind(context);
592
600
  try {
593
601
  this._each(function(value) {
594
- iterator(value, index++);
602
+ iterator.call(context, value, index++);
595
603
  });
596
604
  } catch (e) {
597
605
  if (e != $break) throw e;
@@ -600,47 +608,46 @@ var Enumerable = {
600
608
  },
601
609
 
602
610
  eachSlice: function(number, iterator, context) {
603
- iterator = iterator ? iterator.bind(context) : Prototype.K;
604
611
  var index = -number, slices = [], array = this.toArray();
612
+ if (number < 1) return array;
605
613
  while ((index += number) < array.length)
606
614
  slices.push(array.slice(index, index+number));
607
615
  return slices.collect(iterator, context);
608
616
  },
609
617
 
610
618
  all: function(iterator, context) {
611
- iterator = iterator ? iterator.bind(context) : Prototype.K;
619
+ iterator = iterator || Prototype.K;
612
620
  var result = true;
613
621
  this.each(function(value, index) {
614
- result = result && !!iterator(value, index);
622
+ result = result && !!iterator.call(context, value, index);
615
623
  if (!result) throw $break;
616
624
  });
617
625
  return result;
618
626
  },
619
627
 
620
628
  any: function(iterator, context) {
621
- iterator = iterator ? iterator.bind(context) : Prototype.K;
629
+ iterator = iterator || Prototype.K;
622
630
  var result = false;
623
631
  this.each(function(value, index) {
624
- if (result = !!iterator(value, index))
632
+ if (result = !!iterator.call(context, value, index))
625
633
  throw $break;
626
634
  });
627
635
  return result;
628
636
  },
629
637
 
630
638
  collect: function(iterator, context) {
631
- iterator = iterator ? iterator.bind(context) : Prototype.K;
639
+ iterator = iterator || Prototype.K;
632
640
  var results = [];
633
641
  this.each(function(value, index) {
634
- results.push(iterator(value, index));
642
+ results.push(iterator.call(context, value, index));
635
643
  });
636
644
  return results;
637
645
  },
638
646
 
639
647
  detect: function(iterator, context) {
640
- iterator = iterator.bind(context);
641
648
  var result;
642
649
  this.each(function(value, index) {
643
- if (iterator(value, index)) {
650
+ if (iterator.call(context, value, index)) {
644
651
  result = value;
645
652
  throw $break;
646
653
  }
@@ -649,17 +656,16 @@ var Enumerable = {
649
656
  },
650
657
 
651
658
  findAll: function(iterator, context) {
652
- iterator = iterator.bind(context);
653
659
  var results = [];
654
660
  this.each(function(value, index) {
655
- if (iterator(value, index))
661
+ if (iterator.call(context, value, index))
656
662
  results.push(value);
657
663
  });
658
664
  return results;
659
665
  },
660
666
 
661
667
  grep: function(filter, iterator, context) {
662
- iterator = iterator ? iterator.bind(context) : Prototype.K;
668
+ iterator = iterator || Prototype.K;
663
669
  var results = [];
664
670
 
665
671
  if (Object.isString(filter))
@@ -667,7 +673,7 @@ var Enumerable = {
667
673
 
668
674
  this.each(function(value, index) {
669
675
  if (filter.match(value))
670
- results.push(iterator(value, index));
676
+ results.push(iterator.call(context, value, index));
671
677
  });
672
678
  return results;
673
679
  },
@@ -695,9 +701,8 @@ var Enumerable = {
695
701
  },
696
702
 
697
703
  inject: function(memo, iterator, context) {
698
- iterator = iterator.bind(context);
699
704
  this.each(function(value, index) {
700
- memo = iterator(memo, value, index);
705
+ memo = iterator.call(context, memo, value, index);
701
706
  });
702
707
  return memo;
703
708
  },
@@ -710,10 +715,10 @@ var Enumerable = {
710
715
  },
711
716
 
712
717
  max: function(iterator, context) {
713
- iterator = iterator ? iterator.bind(context) : Prototype.K;
718
+ iterator = iterator || Prototype.K;
714
719
  var result;
715
720
  this.each(function(value, index) {
716
- value = iterator(value, index);
721
+ value = iterator.call(context, value, index);
717
722
  if (result == null || value >= result)
718
723
  result = value;
719
724
  });
@@ -721,10 +726,10 @@ var Enumerable = {
721
726
  },
722
727
 
723
728
  min: function(iterator, context) {
724
- iterator = iterator ? iterator.bind(context) : Prototype.K;
729
+ iterator = iterator || Prototype.K;
725
730
  var result;
726
731
  this.each(function(value, index) {
727
- value = iterator(value, index);
732
+ value = iterator.call(context, value, index);
728
733
  if (result == null || value < result)
729
734
  result = value;
730
735
  });
@@ -732,10 +737,10 @@ var Enumerable = {
732
737
  },
733
738
 
734
739
  partition: function(iterator, context) {
735
- iterator = iterator ? iterator.bind(context) : Prototype.K;
740
+ iterator = iterator || Prototype.K;
736
741
  var trues = [], falses = [];
737
742
  this.each(function(value, index) {
738
- (iterator(value, index) ?
743
+ (iterator.call(context, value, index) ?
739
744
  trues : falses).push(value);
740
745
  });
741
746
  return [trues, falses];
@@ -750,19 +755,20 @@ var Enumerable = {
750
755
  },
751
756
 
752
757
  reject: function(iterator, context) {
753
- iterator = iterator.bind(context);
754
758
  var results = [];
755
759
  this.each(function(value, index) {
756
- if (!iterator(value, index))
760
+ if (!iterator.call(context, value, index))
757
761
  results.push(value);
758
762
  });
759
763
  return results;
760
764
  },
761
765
 
762
766
  sortBy: function(iterator, context) {
763
- iterator = iterator.bind(context);
764
767
  return this.map(function(value, index) {
765
- return {value: value, criteria: iterator(value, index)};
768
+ return {
769
+ value: value,
770
+ criteria: iterator.call(context, value, index)
771
+ };
766
772
  }).sort(function(left, right) {
767
773
  var a = left.criteria, b = right.criteria;
768
774
  return a < b ? -1 : a > b ? 1 : 0;
@@ -806,20 +812,24 @@ Object.extend(Enumerable, {
806
812
  function $A(iterable) {
807
813
  if (!iterable) return [];
808
814
  if (iterable.toArray) return iterable.toArray();
809
- var length = iterable.length, results = new Array(length);
815
+ var length = iterable.length || 0, results = new Array(length);
810
816
  while (length--) results[length] = iterable[length];
811
817
  return results;
812
818
  }
813
819
 
814
820
  if (Prototype.Browser.WebKit) {
815
- function $A(iterable) {
821
+ $A = function(iterable) {
816
822
  if (!iterable) return [];
817
- if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
818
- iterable.toArray) return iterable.toArray();
819
- var length = iterable.length, results = new Array(length);
823
+ // In Safari, only use the `toArray` method if it's not a NodeList.
824
+ // A NodeList is a function, has an function `item` property, and a numeric
825
+ // `length` property. Adapted from Google Doctype.
826
+ if (!(typeof iterable === 'function' && typeof iterable.length ===
827
+ 'number' && typeof iterable.item === 'function') && iterable.toArray)
828
+ return iterable.toArray();
829
+ var length = iterable.length || 0, results = new Array(length);
820
830
  while (length--) results[length] = iterable[length];
821
831
  return results;
822
- }
832
+ };
823
833
  }
824
834
 
825
835
  Array.from = $A;
@@ -962,8 +972,8 @@ Object.extend(Number.prototype, {
962
972
  return this + 1;
963
973
  },
964
974
 
965
- times: function(iterator) {
966
- $R(0, this, true).each(iterator);
975
+ times: function(iterator, context) {
976
+ $R(0, this, true).each(iterator, context);
967
977
  return this;
968
978
  },
969
979
 
@@ -1010,7 +1020,9 @@ var Hash = Class.create(Enumerable, (function() {
1010
1020
  },
1011
1021
 
1012
1022
  get: function(key) {
1013
- return this._object[key];
1023
+ // simulating poorly supported hasOwnProperty
1024
+ if (this._object[key] !== Object.prototype[key])
1025
+ return this._object[key];
1014
1026
  },
1015
1027
 
1016
1028
  unset: function(key) {
@@ -1050,14 +1062,14 @@ var Hash = Class.create(Enumerable, (function() {
1050
1062
  },
1051
1063
 
1052
1064
  toQueryString: function() {
1053
- return this.map(function(pair) {
1065
+ return this.inject([], function(results, pair) {
1054
1066
  var key = encodeURIComponent(pair.key), values = pair.value;
1055
1067
 
1056
1068
  if (values && typeof values == 'object') {
1057
1069
  if (Object.isArray(values))
1058
- return values.map(toQueryPair.curry(key)).join('&');
1059
- }
1060
- return toQueryPair(key, values);
1070
+ return results.concat(values.map(toQueryPair.curry(key)));
1071
+ } else results.push(toQueryPair(key, values));
1072
+ return results;
1061
1073
  }).join('&');
1062
1074
  },
1063
1075
 
@@ -1298,7 +1310,7 @@ Ajax.Request = Class.create(Ajax.Base, {
1298
1310
 
1299
1311
  var contentType = response.getHeader('Content-type');
1300
1312
  if (this.options.evalJS == 'force'
1301
- || (this.options.evalJS && contentType
1313
+ || (this.options.evalJS && this.isSameOrigin() && contentType
1302
1314
  && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
1303
1315
  this.evalResponse();
1304
1316
  }
@@ -1316,9 +1328,18 @@ Ajax.Request = Class.create(Ajax.Base, {
1316
1328
  }
1317
1329
  },
1318
1330
 
1331
+ isSameOrigin: function() {
1332
+ var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
1333
+ return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
1334
+ protocol: location.protocol,
1335
+ domain: document.domain,
1336
+ port: location.port ? ':' + location.port : ''
1337
+ }));
1338
+ },
1339
+
1319
1340
  getHeader: function(name) {
1320
1341
  try {
1321
- return this.transport.getResponseHeader(name);
1342
+ return this.transport.getResponseHeader(name) || null;
1322
1343
  } catch (e) { return null }
1323
1344
  },
1324
1345
 
@@ -1391,7 +1412,8 @@ Ajax.Response = Class.create({
1391
1412
  if (!json) return null;
1392
1413
  json = decodeURIComponent(escape(json));
1393
1414
  try {
1394
- return json.evalJSON(this.request.options.sanitizeJSON);
1415
+ return json.evalJSON(this.request.options.sanitizeJSON ||
1416
+ !this.request.isSameOrigin());
1395
1417
  } catch (e) {
1396
1418
  this.request.dispatchException(e);
1397
1419
  }
@@ -1404,7 +1426,8 @@ Ajax.Response = Class.create({
1404
1426
  this.responseText.blank())
1405
1427
  return null;
1406
1428
  try {
1407
- return this.responseText.evalJSON(options.sanitizeJSON);
1429
+ return this.responseText.evalJSON(options.sanitizeJSON ||
1430
+ !this.request.isSameOrigin());
1408
1431
  } catch (e) {
1409
1432
  this.request.dispatchException(e);
1410
1433
  }
@@ -1546,6 +1569,7 @@ if (!Node.ELEMENT_NODE) {
1546
1569
  return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
1547
1570
  };
1548
1571
  Object.extend(this.Element, element || { });
1572
+ if (element) this.Element.prototype = element.prototype;
1549
1573
  }).call(window);
1550
1574
 
1551
1575
  Element.cache = { };
@@ -1562,12 +1586,14 @@ Element.Methods = {
1562
1586
  },
1563
1587
 
1564
1588
  hide: function(element) {
1565
- $(element).style.display = 'none';
1589
+ element = $(element);
1590
+ element.style.display = 'none';
1566
1591
  return element;
1567
1592
  },
1568
1593
 
1569
1594
  show: function(element) {
1570
- $(element).style.display = '';
1595
+ element = $(element);
1596
+ element.style.display = '';
1571
1597
  return element;
1572
1598
  },
1573
1599
 
@@ -1608,24 +1634,28 @@ Element.Methods = {
1608
1634
  Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
1609
1635
  insertions = {bottom:insertions};
1610
1636
 
1611
- var content, t, range;
1637
+ var content, insert, tagName, childNodes;
1612
1638
 
1613
- for (position in insertions) {
1639
+ for (var position in insertions) {
1614
1640
  content = insertions[position];
1615
1641
  position = position.toLowerCase();
1616
- t = Element._insertionTranslations[position];
1642
+ insert = Element._insertionTranslations[position];
1617
1643
 
1618
1644
  if (content && content.toElement) content = content.toElement();
1619
1645
  if (Object.isElement(content)) {
1620
- t.insert(element, content);
1646
+ insert(element, content);
1621
1647
  continue;
1622
1648
  }
1623
1649
 
1624
1650
  content = Object.toHTML(content);
1625
1651
 
1626
- range = element.ownerDocument.createRange();
1627
- t.initializeRange(element, range);
1628
- t.insert(element, range.createContextualFragment(content.stripScripts()));
1652
+ tagName = ((position == 'before' || position == 'after')
1653
+ ? element.parentNode : element).tagName.toUpperCase();
1654
+
1655
+ childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
1656
+
1657
+ if (position == 'top' || position == 'after') childNodes.reverse();
1658
+ childNodes.each(insert.curry(element));
1629
1659
 
1630
1660
  content.evalScripts.bind(content).defer();
1631
1661
  }
@@ -1670,7 +1700,7 @@ Element.Methods = {
1670
1700
  },
1671
1701
 
1672
1702
  descendants: function(element) {
1673
- return $(element).getElementsBySelector("*");
1703
+ return $(element).select("*");
1674
1704
  },
1675
1705
 
1676
1706
  firstDescendant: function(element) {
@@ -1709,32 +1739,31 @@ Element.Methods = {
1709
1739
  element = $(element);
1710
1740
  if (arguments.length == 1) return $(element.parentNode);
1711
1741
  var ancestors = element.ancestors();
1712
- return expression ? Selector.findElement(ancestors, expression, index) :
1713
- ancestors[index || 0];
1742
+ return Object.isNumber(expression) ? ancestors[expression] :
1743
+ Selector.findElement(ancestors, expression, index);
1714
1744
  },
1715
1745
 
1716
1746
  down: function(element, expression, index) {
1717
1747
  element = $(element);
1718
1748
  if (arguments.length == 1) return element.firstDescendant();
1719
- var descendants = element.descendants();
1720
- return expression ? Selector.findElement(descendants, expression, index) :
1721
- descendants[index || 0];
1749
+ return Object.isNumber(expression) ? element.descendants()[expression] :
1750
+ Element.select(element, expression)[index || 0];
1722
1751
  },
1723
1752
 
1724
1753
  previous: function(element, expression, index) {
1725
1754
  element = $(element);
1726
1755
  if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
1727
1756
  var previousSiblings = element.previousSiblings();
1728
- return expression ? Selector.findElement(previousSiblings, expression, index) :
1729
- previousSiblings[index || 0];
1757
+ return Object.isNumber(expression) ? previousSiblings[expression] :
1758
+ Selector.findElement(previousSiblings, expression, index);
1730
1759
  },
1731
1760
 
1732
1761
  next: function(element, expression, index) {
1733
1762
  element = $(element);
1734
1763
  if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
1735
1764
  var nextSiblings = element.nextSiblings();
1736
- return expression ? Selector.findElement(nextSiblings, expression, index) :
1737
- nextSiblings[index || 0];
1765
+ return Object.isNumber(expression) ? nextSiblings[expression] :
1766
+ Selector.findElement(nextSiblings, expression, index);
1738
1767
  },
1739
1768
 
1740
1769
  select: function() {
@@ -1848,23 +1877,16 @@ Element.Methods = {
1848
1877
 
1849
1878
  descendantOf: function(element, ancestor) {
1850
1879
  element = $(element), ancestor = $(ancestor);
1851
- var originalAncestor = ancestor;
1852
1880
 
1853
1881
  if (element.compareDocumentPosition)
1854
1882
  return (element.compareDocumentPosition(ancestor) & 8) === 8;
1855
1883
 
1856
- if (element.sourceIndex && !Prototype.Browser.Opera) {
1857
- var e = element.sourceIndex, a = ancestor.sourceIndex,
1858
- nextAncestor = ancestor.nextSibling;
1859
- if (!nextAncestor) {
1860
- do { ancestor = ancestor.parentNode; }
1861
- while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);
1862
- }
1863
- if (nextAncestor) return (e > a && e < nextAncestor.sourceIndex);
1864
- }
1884
+ if (ancestor.contains)
1885
+ return ancestor.contains(element) && ancestor !== element;
1865
1886
 
1866
1887
  while (element = element.parentNode)
1867
- if (element == originalAncestor) return true;
1888
+ if (element == ancestor) return true;
1889
+
1868
1890
  return false;
1869
1891
  },
1870
1892
 
@@ -1879,7 +1901,7 @@ Element.Methods = {
1879
1901
  element = $(element);
1880
1902
  style = style == 'float' ? 'cssFloat' : style.camelize();
1881
1903
  var value = element.style[style];
1882
- if (!value) {
1904
+ if (!value || value == 'auto') {
1883
1905
  var css = document.defaultView.getComputedStyle(element, null);
1884
1906
  value = css ? css[style] : null;
1885
1907
  }
@@ -1918,7 +1940,7 @@ Element.Methods = {
1918
1940
 
1919
1941
  getDimensions: function(element) {
1920
1942
  element = $(element);
1921
- var display = $(element).getStyle('display');
1943
+ var display = element.getStyle('display');
1922
1944
  if (display != 'none' && display != null) // Safari bug
1923
1945
  return {width: element.offsetWidth, height: element.offsetHeight};
1924
1946
 
@@ -1947,7 +1969,7 @@ Element.Methods = {
1947
1969
  element.style.position = 'relative';
1948
1970
  // Opera returns the offset relative to the positioning context, when an
1949
1971
  // element is position relative but top and left have not been defined
1950
- if (window.opera) {
1972
+ if (Prototype.Browser.Opera) {
1951
1973
  element.style.top = 0;
1952
1974
  element.style.left = 0;
1953
1975
  }
@@ -2002,9 +2024,9 @@ Element.Methods = {
2002
2024
  valueL += element.offsetLeft || 0;
2003
2025
  element = element.offsetParent;
2004
2026
  if (element) {
2005
- if (element.tagName == 'BODY') break;
2027
+ if (element.tagName.toUpperCase() == 'BODY') break;
2006
2028
  var p = Element.getStyle(element, 'position');
2007
- if (p == 'relative' || p == 'absolute') break;
2029
+ if (p !== 'static') break;
2008
2030
  }
2009
2031
  } while (element);
2010
2032
  return Element._returnOffset(valueL, valueT);
@@ -2012,7 +2034,7 @@ Element.Methods = {
2012
2034
 
2013
2035
  absolutize: function(element) {
2014
2036
  element = $(element);
2015
- if (element.getStyle('position') == 'absolute') return;
2037
+ if (element.getStyle('position') == 'absolute') return element;
2016
2038
  // Position.prepare(); // To be done manually by Scripty when it needs it.
2017
2039
 
2018
2040
  var offsets = element.positionedOffset();
@@ -2036,7 +2058,7 @@ Element.Methods = {
2036
2058
 
2037
2059
  relativize: function(element) {
2038
2060
  element = $(element);
2039
- if (element.getStyle('position') == 'relative') return;
2061
+ if (element.getStyle('position') == 'relative') return element;
2040
2062
  // Position.prepare(); // To be done manually by Scripty when it needs it.
2041
2063
 
2042
2064
  element.style.position = 'relative';
@@ -2087,7 +2109,7 @@ Element.Methods = {
2087
2109
 
2088
2110
  element = forElement;
2089
2111
  do {
2090
- if (!Prototype.Browser.Opera || element.tagName == 'BODY') {
2112
+ if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) {
2091
2113
  valueT -= element.scrollTop || 0;
2092
2114
  valueL -= element.scrollLeft || 0;
2093
2115
  }
@@ -2153,46 +2175,6 @@ Element._attributeTranslations = {
2153
2175
  }
2154
2176
  };
2155
2177
 
2156
-
2157
- if (!document.createRange || Prototype.Browser.Opera) {
2158
- Element.Methods.insert = function(element, insertions) {
2159
- element = $(element);
2160
-
2161
- if (Object.isString(insertions) || Object.isNumber(insertions) ||
2162
- Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
2163
- insertions = { bottom: insertions };
2164
-
2165
- var t = Element._insertionTranslations, content, position, pos, tagName;
2166
-
2167
- for (position in insertions) {
2168
- content = insertions[position];
2169
- position = position.toLowerCase();
2170
- pos = t[position];
2171
-
2172
- if (content && content.toElement) content = content.toElement();
2173
- if (Object.isElement(content)) {
2174
- pos.insert(element, content);
2175
- continue;
2176
- }
2177
-
2178
- content = Object.toHTML(content);
2179
- tagName = ((position == 'before' || position == 'after')
2180
- ? element.parentNode : element).tagName.toUpperCase();
2181
-
2182
- if (t.tags[tagName]) {
2183
- var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
2184
- if (position == 'top' || position == 'after') fragments.reverse();
2185
- fragments.each(pos.insert.curry(element));
2186
- }
2187
- else element.insertAdjacentHTML(pos.adjacency, content.stripScripts());
2188
-
2189
- content.evalScripts.bind(content).defer();
2190
- }
2191
-
2192
- return element;
2193
- };
2194
- }
2195
-
2196
2178
  if (Prototype.Browser.Opera) {
2197
2179
  Element.Methods.getStyle = Element.Methods.getStyle.wrap(
2198
2180
  function(proceed, element, style) {
@@ -2237,12 +2219,36 @@ if (Prototype.Browser.Opera) {
2237
2219
  }
2238
2220
 
2239
2221
  else if (Prototype.Browser.IE) {
2240
- $w('positionedOffset getOffsetParent viewportOffset').each(function(method) {
2222
+ // IE doesn't report offsets correctly for static elements, so we change them
2223
+ // to "relative" to get the values, then change them back.
2224
+ Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
2225
+ function(proceed, element) {
2226
+ element = $(element);
2227
+ // IE throws an error if element is not in document
2228
+ try { element.offsetParent }
2229
+ catch(e) { return $(document.body) }
2230
+ var position = element.getStyle('position');
2231
+ if (position !== 'static') return proceed(element);
2232
+ element.setStyle({ position: 'relative' });
2233
+ var value = proceed(element);
2234
+ element.setStyle({ position: position });
2235
+ return value;
2236
+ }
2237
+ );
2238
+
2239
+ $w('positionedOffset viewportOffset').each(function(method) {
2241
2240
  Element.Methods[method] = Element.Methods[method].wrap(
2242
2241
  function(proceed, element) {
2243
2242
  element = $(element);
2243
+ try { element.offsetParent }
2244
+ catch(e) { return Element._returnOffset(0,0) }
2244
2245
  var position = element.getStyle('position');
2245
- if (position != 'static') return proceed(element);
2246
+ if (position !== 'static') return proceed(element);
2247
+ // Trigger hasLayout on the offset parent so that IE6 reports
2248
+ // accurate offsetTop and offsetLeft values for position: fixed.
2249
+ var offsetParent = element.getOffsetParent();
2250
+ if (offsetParent && offsetParent.getStyle('position') === 'fixed')
2251
+ offsetParent.setStyle({ zoom: 1 });
2246
2252
  element.setStyle({ position: 'relative' });
2247
2253
  var value = proceed(element);
2248
2254
  element.setStyle({ position: position });
@@ -2251,6 +2257,14 @@ else if (Prototype.Browser.IE) {
2251
2257
  );
2252
2258
  });
2253
2259
 
2260
+ Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap(
2261
+ function(proceed, element) {
2262
+ try { element.offsetParent }
2263
+ catch(e) { return Element._returnOffset(0,0) }
2264
+ return proceed(element);
2265
+ }
2266
+ );
2267
+
2254
2268
  Element.Methods.getStyle = function(element, style) {
2255
2269
  element = $(element);
2256
2270
  style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
@@ -2324,7 +2338,10 @@ else if (Prototype.Browser.IE) {
2324
2338
  };
2325
2339
 
2326
2340
  Element._attributeTranslations.write = {
2327
- names: Object.clone(Element._attributeTranslations.read.names),
2341
+ names: Object.extend({
2342
+ cellpadding: 'cellPadding',
2343
+ cellspacing: 'cellSpacing'
2344
+ }, Element._attributeTranslations.read.names),
2328
2345
  values: {
2329
2346
  checked: function(element, value) {
2330
2347
  element.checked = !!value;
@@ -2339,7 +2356,7 @@ else if (Prototype.Browser.IE) {
2339
2356
  Element._attributeTranslations.has = {};
2340
2357
 
2341
2358
  $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
2342
- 'encType maxLength readOnly longDesc').each(function(attr) {
2359
+ 'encType maxLength readOnly longDesc frameBorder').each(function(attr) {
2343
2360
  Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
2344
2361
  Element._attributeTranslations.has[attr.toLowerCase()] = attr;
2345
2362
  });
@@ -2392,7 +2409,7 @@ else if (Prototype.Browser.WebKit) {
2392
2409
  (value < 0.00001) ? 0 : value;
2393
2410
 
2394
2411
  if (value == 1)
2395
- if(element.tagName == 'IMG' && element.width) {
2412
+ if(element.tagName.toUpperCase() == 'IMG' && element.width) {
2396
2413
  element.width++; element.width--;
2397
2414
  } else try {
2398
2415
  var n = document.createTextNode(' ');
@@ -2444,7 +2461,7 @@ if (Prototype.Browser.IE || Prototype.Browser.Opera) {
2444
2461
  };
2445
2462
  }
2446
2463
 
2447
- if (document.createElement('div').outerHTML) {
2464
+ if ('outerHTML' in document.createElement('div')) {
2448
2465
  Element.Methods.replace = function(element, content) {
2449
2466
  element = $(element);
2450
2467
 
@@ -2482,45 +2499,25 @@ Element._returnOffset = function(l, t) {
2482
2499
 
2483
2500
  Element._getContentFromAnonymousElement = function(tagName, html) {
2484
2501
  var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
2485
- div.innerHTML = t[0] + html + t[1];
2486
- t[2].times(function() { div = div.firstChild });
2502
+ if (t) {
2503
+ div.innerHTML = t[0] + html + t[1];
2504
+ t[2].times(function() { div = div.firstChild });
2505
+ } else div.innerHTML = html;
2487
2506
  return $A(div.childNodes);
2488
2507
  };
2489
2508
 
2490
2509
  Element._insertionTranslations = {
2491
- before: {
2492
- adjacency: 'beforeBegin',
2493
- insert: function(element, node) {
2494
- element.parentNode.insertBefore(node, element);
2495
- },
2496
- initializeRange: function(element, range) {
2497
- range.setStartBefore(element);
2498
- }
2510
+ before: function(element, node) {
2511
+ element.parentNode.insertBefore(node, element);
2499
2512
  },
2500
- top: {
2501
- adjacency: 'afterBegin',
2502
- insert: function(element, node) {
2503
- element.insertBefore(node, element.firstChild);
2504
- },
2505
- initializeRange: function(element, range) {
2506
- range.selectNodeContents(element);
2507
- range.collapse(true);
2508
- }
2513
+ top: function(element, node) {
2514
+ element.insertBefore(node, element.firstChild);
2509
2515
  },
2510
- bottom: {
2511
- adjacency: 'beforeEnd',
2512
- insert: function(element, node) {
2513
- element.appendChild(node);
2514
- }
2516
+ bottom: function(element, node) {
2517
+ element.appendChild(node);
2515
2518
  },
2516
- after: {
2517
- adjacency: 'afterEnd',
2518
- insert: function(element, node) {
2519
- element.parentNode.insertBefore(node, element.nextSibling);
2520
- },
2521
- initializeRange: function(element, range) {
2522
- range.setStartAfter(element);
2523
- }
2519
+ after: function(element, node) {
2520
+ element.parentNode.insertBefore(node, element.nextSibling);
2524
2521
  },
2525
2522
  tags: {
2526
2523
  TABLE: ['<table>', '</table>', 1],
@@ -2532,7 +2529,6 @@ Element._insertionTranslations = {
2532
2529
  };
2533
2530
 
2534
2531
  (function() {
2535
- this.bottom.initializeRange = this.top.initializeRange;
2536
2532
  Object.extend(this.tags, {
2537
2533
  THEAD: this.tags.TBODY,
2538
2534
  TFOOT: this.tags.TBODY,
@@ -2544,7 +2540,7 @@ Element.Methods.Simulated = {
2544
2540
  hasAttribute: function(element, attribute) {
2545
2541
  attribute = Element._attributeTranslations.has[attribute] || attribute;
2546
2542
  var node = $(element).getAttributeNode(attribute);
2547
- return node && node.specified;
2543
+ return !!(node && node.specified);
2548
2544
  }
2549
2545
  };
2550
2546
 
@@ -2553,9 +2549,9 @@ Element.Methods.ByTag = { };
2553
2549
  Object.extend(Element, Element.Methods);
2554
2550
 
2555
2551
  if (!Prototype.BrowserFeatures.ElementExtensions &&
2556
- document.createElement('div').__proto__) {
2552
+ document.createElement('div')['__proto__']) {
2557
2553
  window.HTMLElement = { };
2558
- window.HTMLElement.prototype = document.createElement('div').__proto__;
2554
+ window.HTMLElement.prototype = document.createElement('div')['__proto__'];
2559
2555
  Prototype.BrowserFeatures.ElementExtensions = true;
2560
2556
  }
2561
2557
 
@@ -2570,7 +2566,7 @@ Element.extend = (function() {
2570
2566
  element.nodeType != 1 || element == window) return element;
2571
2567
 
2572
2568
  var methods = Object.clone(Methods),
2573
- tagName = element.tagName, property, value;
2569
+ tagName = element.tagName.toUpperCase(), property, value;
2574
2570
 
2575
2571
  // extend methods for specific tags
2576
2572
  if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
@@ -2666,7 +2662,7 @@ Element.addMethods = function(methods) {
2666
2662
  if (window[klass]) return window[klass];
2667
2663
 
2668
2664
  window[klass] = { };
2669
- window[klass].prototype = document.createElement(tagName).__proto__;
2665
+ window[klass].prototype = document.createElement(tagName)['__proto__'];
2670
2666
  return window[klass];
2671
2667
  }
2672
2668
 
@@ -2692,12 +2688,18 @@ Element.addMethods = function(methods) {
2692
2688
 
2693
2689
  document.viewport = {
2694
2690
  getDimensions: function() {
2695
- var dimensions = { };
2696
- var B = Prototype.Browser;
2691
+ var dimensions = { }, B = Prototype.Browser;
2697
2692
  $w('width height').each(function(d) {
2698
2693
  var D = d.capitalize();
2699
- dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] :
2700
- (B.Opera) ? document.body['client' + D] : document.documentElement['client' + D];
2694
+ if (B.WebKit && !document.evaluate) {
2695
+ // Safari <3.0 needs self.innerWidth/Height
2696
+ dimensions[d] = self['inner' + D];
2697
+ } else if (B.Opera && parseFloat(window.opera.version()) < 9.5) {
2698
+ // Opera <9.5 needs document.body.clientWidth/Height
2699
+ dimensions[d] = document.body['client' + D]
2700
+ } else {
2701
+ dimensions[d] = document.documentElement['client' + D];
2702
+ }
2701
2703
  });
2702
2704
  return dimensions;
2703
2705
  },
@@ -2716,14 +2718,24 @@ document.viewport = {
2716
2718
  window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
2717
2719
  }
2718
2720
  };
2719
- /* Portions of the Selector class are derived from Jack Slocums DomQuery,
2721
+ /* Portions of the Selector class are derived from Jack Slocum's DomQuery,
2720
2722
  * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
2721
2723
  * license. Please see http://www.yui-ext.com/ for more information. */
2722
2724
 
2723
2725
  var Selector = Class.create({
2724
2726
  initialize: function(expression) {
2725
2727
  this.expression = expression.strip();
2726
- this.compileMatcher();
2728
+
2729
+ if (this.shouldUseSelectorsAPI()) {
2730
+ this.mode = 'selectorsAPI';
2731
+ } else if (this.shouldUseXPath()) {
2732
+ this.mode = 'xpath';
2733
+ this.compileXPathMatcher();
2734
+ } else {
2735
+ this.mode = "normal";
2736
+ this.compileMatcher();
2737
+ }
2738
+
2727
2739
  },
2728
2740
 
2729
2741
  shouldUseXPath: function() {
@@ -2738,16 +2750,29 @@ var Selector = Class.create({
2738
2750
 
2739
2751
  // XPath can't do namespaced attributes, nor can it read
2740
2752
  // the "checked" property from DOM nodes
2741
- if ((/(\[[\w-]*?:|:checked)/).test(this.expression))
2753
+ if ((/(\[[\w-]*?:|:checked)/).test(e))
2742
2754
  return false;
2743
2755
 
2744
2756
  return true;
2745
2757
  },
2746
2758
 
2747
- compileMatcher: function() {
2748
- if (this.shouldUseXPath())
2749
- return this.compileXPathMatcher();
2759
+ shouldUseSelectorsAPI: function() {
2760
+ if (!Prototype.BrowserFeatures.SelectorsAPI) return false;
2761
+
2762
+ if (!Selector._div) Selector._div = new Element('div');
2763
+
2764
+ // Make sure the browser treats the selector as valid. Test on an
2765
+ // isolated element to minimize cost of this check.
2766
+ try {
2767
+ Selector._div.querySelector(this.expression);
2768
+ } catch(e) {
2769
+ return false;
2770
+ }
2750
2771
 
2772
+ return true;
2773
+ },
2774
+
2775
+ compileMatcher: function() {
2751
2776
  var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
2752
2777
  c = Selector.criteria, le, p, m;
2753
2778
 
@@ -2765,7 +2790,7 @@ var Selector = Class.create({
2765
2790
  p = ps[i];
2766
2791
  if (m = e.match(p)) {
2767
2792
  this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
2768
- new Template(c[i]).evaluate(m));
2793
+ new Template(c[i]).evaluate(m));
2769
2794
  e = e.replace(m[0], '');
2770
2795
  break;
2771
2796
  }
@@ -2804,8 +2829,27 @@ var Selector = Class.create({
2804
2829
 
2805
2830
  findElements: function(root) {
2806
2831
  root = root || document;
2807
- if (this.xpath) return document._getElementsByXPath(this.xpath, root);
2808
- return this.matcher(root);
2832
+ var e = this.expression, results;
2833
+
2834
+ switch (this.mode) {
2835
+ case 'selectorsAPI':
2836
+ // querySelectorAll queries document-wide, then filters to descendants
2837
+ // of the context element. That's not what we want.
2838
+ // Add an explicit context to the selector if necessary.
2839
+ if (root !== document) {
2840
+ var oldId = root.id, id = $(root).identify();
2841
+ e = "#" + id + " " + e;
2842
+ }
2843
+
2844
+ results = $A(root.querySelectorAll(e)).map(Element.extend);
2845
+ root.id = oldId;
2846
+
2847
+ return results;
2848
+ case 'xpath':
2849
+ return document._getElementsByXPath(this.xpath, root);
2850
+ default:
2851
+ return this.matcher(root);
2852
+ }
2809
2853
  },
2810
2854
 
2811
2855
  match: function(element) {
@@ -2896,10 +2940,10 @@ Object.extend(Selector, {
2896
2940
  'first-child': '[not(preceding-sibling::*)]',
2897
2941
  'last-child': '[not(following-sibling::*)]',
2898
2942
  'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
2899
- 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
2943
+ 'empty': "[count(*) = 0 and (count(text()) = 0)]",
2900
2944
  'checked': "[@checked]",
2901
- 'disabled': "[@disabled]",
2902
- 'enabled': "[not(@disabled)]",
2945
+ 'disabled': "[(@disabled) and (@type!='hidden')]",
2946
+ 'enabled': "[not(@disabled) and (@type!='hidden')]",
2903
2947
  'not': function(m) {
2904
2948
  var e = m[6], p = Selector.patterns,
2905
2949
  x = Selector.xpath, le, v;
@@ -2959,13 +3003,13 @@ Object.extend(Selector, {
2959
3003
  },
2960
3004
 
2961
3005
  criteria: {
2962
- tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
2963
- className: 'n = h.className(n, r, "#{1}", c); c = false;',
2964
- id: 'n = h.id(n, r, "#{1}", c); c = false;',
2965
- attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
3006
+ tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
3007
+ className: 'n = h.className(n, r, "#{1}", c); c = false;',
3008
+ id: 'n = h.id(n, r, "#{1}", c); c = false;',
3009
+ attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;',
2966
3010
  attr: function(m) {
2967
3011
  m[3] = (m[5] || m[6]);
2968
- return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
3012
+ return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);
2969
3013
  },
2970
3014
  pseudo: function(m) {
2971
3015
  if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
@@ -2989,8 +3033,9 @@ Object.extend(Selector, {
2989
3033
  tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
2990
3034
  id: /^#([\w\-\*]+)(\b|$)/,
2991
3035
  className: /^\.([\w\-\*]+)(\b|$)/,
2992
- pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s)|(?=:))/,
2993
- attrPresence: /^\[([\w]+)\]/,
3036
+ pseudo:
3037
+ /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,
3038
+ attrPresence: /^\[((?:[\w]+:)?[\w]+)\]/,
2994
3039
  attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
2995
3040
  },
2996
3041
 
@@ -3014,7 +3059,7 @@ Object.extend(Selector, {
3014
3059
 
3015
3060
  attr: function(element, matches) {
3016
3061
  var nodeValue = Element.readAttribute(element, matches[1]);
3017
- return Selector.operators[matches[2]](nodeValue, matches[3]);
3062
+ return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);
3018
3063
  }
3019
3064
  },
3020
3065
 
@@ -3029,14 +3074,15 @@ Object.extend(Selector, {
3029
3074
 
3030
3075
  // marks an array of nodes for counting
3031
3076
  mark: function(nodes) {
3077
+ var _true = Prototype.emptyFunction;
3032
3078
  for (var i = 0, node; node = nodes[i]; i++)
3033
- node._counted = true;
3079
+ node._countedByPrototype = _true;
3034
3080
  return nodes;
3035
3081
  },
3036
3082
 
3037
3083
  unmark: function(nodes) {
3038
3084
  for (var i = 0, node; node = nodes[i]; i++)
3039
- node._counted = undefined;
3085
+ node._countedByPrototype = undefined;
3040
3086
  return nodes;
3041
3087
  },
3042
3088
 
@@ -3044,15 +3090,15 @@ Object.extend(Selector, {
3044
3090
  // "ofType" flag indicates whether we're indexing for nth-of-type
3045
3091
  // rather than nth-child
3046
3092
  index: function(parentNode, reverse, ofType) {
3047
- parentNode._counted = true;
3093
+ parentNode._countedByPrototype = Prototype.emptyFunction;
3048
3094
  if (reverse) {
3049
3095
  for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
3050
3096
  var node = nodes[i];
3051
- if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
3097
+ if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
3052
3098
  }
3053
3099
  } else {
3054
3100
  for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
3055
- if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
3101
+ if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
3056
3102
  }
3057
3103
  },
3058
3104
 
@@ -3061,8 +3107,8 @@ Object.extend(Selector, {
3061
3107
  if (nodes.length == 0) return nodes;
3062
3108
  var results = [], n;
3063
3109
  for (var i = 0, l = nodes.length; i < l; i++)
3064
- if (!(n = nodes[i])._counted) {
3065
- n._counted = true;
3110
+ if (!(n = nodes[i])._countedByPrototype) {
3111
+ n._countedByPrototype = Prototype.emptyFunction;
3066
3112
  results.push(Element.extend(n));
3067
3113
  }
3068
3114
  return Selector.handlers.unmark(results);
@@ -3102,7 +3148,7 @@ Object.extend(Selector, {
3102
3148
 
3103
3149
  nextElementSibling: function(node) {
3104
3150
  while (node = node.nextSibling)
3105
- if (node.nodeType == 1) return node;
3151
+ if (node.nodeType == 1) return node;
3106
3152
  return null;
3107
3153
  },
3108
3154
 
@@ -3114,7 +3160,7 @@ Object.extend(Selector, {
3114
3160
 
3115
3161
  // TOKEN FUNCTIONS
3116
3162
  tagName: function(nodes, root, tagName, combinator) {
3117
- tagName = tagName.toUpperCase();
3163
+ var uTagName = tagName.toUpperCase();
3118
3164
  var results = [], h = Selector.handlers;
3119
3165
  if (nodes) {
3120
3166
  if (combinator) {
@@ -3127,7 +3173,7 @@ Object.extend(Selector, {
3127
3173
  if (tagName == "*") return nodes;
3128
3174
  }
3129
3175
  for (var i = 0, node; node = nodes[i]; i++)
3130
- if (node.tagName.toUpperCase() == tagName) results.push(node);
3176
+ if (node.tagName.toUpperCase() === uTagName) results.push(node);
3131
3177
  return results;
3132
3178
  } else return root.getElementsByTagName(tagName);
3133
3179
  },
@@ -3174,16 +3220,18 @@ Object.extend(Selector, {
3174
3220
  return results;
3175
3221
  },
3176
3222
 
3177
- attrPresence: function(nodes, root, attr) {
3223
+ attrPresence: function(nodes, root, attr, combinator) {
3178
3224
  if (!nodes) nodes = root.getElementsByTagName("*");
3225
+ if (nodes && combinator) nodes = this[combinator](nodes);
3179
3226
  var results = [];
3180
3227
  for (var i = 0, node; node = nodes[i]; i++)
3181
3228
  if (Element.hasAttribute(node, attr)) results.push(node);
3182
3229
  return results;
3183
3230
  },
3184
3231
 
3185
- attr: function(nodes, root, attr, value, operator) {
3232
+ attr: function(nodes, root, attr, value, operator, combinator) {
3186
3233
  if (!nodes) nodes = root.getElementsByTagName("*");
3234
+ if (nodes && combinator) nodes = this[combinator](nodes);
3187
3235
  var handler = Selector.operators[operator], results = [];
3188
3236
  for (var i = 0, node; node = nodes[i]; i++) {
3189
3237
  var nodeValue = Element.readAttribute(node, attr);
@@ -3262,7 +3310,7 @@ Object.extend(Selector, {
3262
3310
  var h = Selector.handlers, results = [], indexed = [], m;
3263
3311
  h.mark(nodes);
3264
3312
  for (var i = 0, node; node = nodes[i]; i++) {
3265
- if (!node.parentNode._counted) {
3313
+ if (!node.parentNode._countedByPrototype) {
3266
3314
  h.index(node.parentNode, reverse, ofType);
3267
3315
  indexed.push(node.parentNode);
3268
3316
  }
@@ -3289,7 +3337,7 @@ Object.extend(Selector, {
3289
3337
  'empty': function(nodes, value, root) {
3290
3338
  for (var i = 0, results = [], node; node = nodes[i]; i++) {
3291
3339
  // IE treats comments as element nodes
3292
- if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
3340
+ if (node.tagName == '!' || node.firstChild) continue;
3293
3341
  results.push(node);
3294
3342
  }
3295
3343
  return results;
@@ -3300,14 +3348,15 @@ Object.extend(Selector, {
3300
3348
  var exclusions = new Selector(selector).findElements(root);
3301
3349
  h.mark(exclusions);
3302
3350
  for (var i = 0, results = [], node; node = nodes[i]; i++)
3303
- if (!node._counted) results.push(node);
3351
+ if (!node._countedByPrototype) results.push(node);
3304
3352
  h.unmark(exclusions);
3305
3353
  return results;
3306
3354
  },
3307
3355
 
3308
3356
  'enabled': function(nodes, value, root) {
3309
3357
  for (var i = 0, results = [], node; node = nodes[i]; i++)
3310
- if (!node.disabled) results.push(node);
3358
+ if (!node.disabled && (!node.type || node.type !== 'hidden'))
3359
+ results.push(node);
3311
3360
  return results;
3312
3361
  },
3313
3362
 
@@ -3327,18 +3376,29 @@ Object.extend(Selector, {
3327
3376
  operators: {
3328
3377
  '=': function(nv, v) { return nv == v; },
3329
3378
  '!=': function(nv, v) { return nv != v; },
3330
- '^=': function(nv, v) { return nv.startsWith(v); },
3379
+ '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); },
3380
+ '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); },
3381
+ '*=': function(nv, v) { return nv == v || nv && nv.include(v); },
3331
3382
  '$=': function(nv, v) { return nv.endsWith(v); },
3332
3383
  '*=': function(nv, v) { return nv.include(v); },
3333
3384
  '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
3334
- '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
3385
+ '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() +
3386
+ '-').include('-' + (v || "").toUpperCase() + '-'); }
3387
+ },
3388
+
3389
+ split: function(expression) {
3390
+ var expressions = [];
3391
+ expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
3392
+ expressions.push(m[1].strip());
3393
+ });
3394
+ return expressions;
3335
3395
  },
3336
3396
 
3337
3397
  matchElements: function(elements, expression) {
3338
- var matches = new Selector(expression).findElements(), h = Selector.handlers;
3398
+ var matches = $$(expression), h = Selector.handlers;
3339
3399
  h.mark(matches);
3340
3400
  for (var i = 0, results = [], element; element = elements[i]; i++)
3341
- if (element._counted) results.push(element);
3401
+ if (element._countedByPrototype) results.push(element);
3342
3402
  h.unmark(matches);
3343
3403
  return results;
3344
3404
  },
@@ -3351,11 +3411,7 @@ Object.extend(Selector, {
3351
3411
  },
3352
3412
 
3353
3413
  findChildElements: function(element, expressions) {
3354
- var exprs = expressions.join(',');
3355
- expressions = [];
3356
- exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
3357
- expressions.push(m[1].strip());
3358
- });
3414
+ expressions = Selector.split(expressions.join(','));
3359
3415
  var results = [], h = Selector.handlers;
3360
3416
  for (var i = 0, l = expressions.length, selector; i < l; i++) {
3361
3417
  selector = new Selector(expressions[i].strip());
@@ -3366,13 +3422,22 @@ Object.extend(Selector, {
3366
3422
  });
3367
3423
 
3368
3424
  if (Prototype.Browser.IE) {
3369
- // IE returns comment nodes on getElementsByTagName("*").
3370
- // Filter them out.
3371
- Selector.handlers.concat = function(a, b) {
3372
- for (var i = 0, node; node = b[i]; i++)
3373
- if (node.tagName !== "!") a.push(node);
3374
- return a;
3375
- };
3425
+ Object.extend(Selector.handlers, {
3426
+ // IE returns comment nodes on getElementsByTagName("*").
3427
+ // Filter them out.
3428
+ concat: function(a, b) {
3429
+ for (var i = 0, node; node = b[i]; i++)
3430
+ if (node.tagName !== "!") a.push(node);
3431
+ return a;
3432
+ },
3433
+
3434
+ // IE improperly serializes _countedByPrototype in (inner|outer)HTML.
3435
+ unmark: function(nodes) {
3436
+ for (var i = 0, node; node = nodes[i]; i++)
3437
+ node.removeAttribute('_countedByPrototype');
3438
+ return nodes;
3439
+ }
3440
+ });
3376
3441
  }
3377
3442
 
3378
3443
  function $$() {
@@ -3392,7 +3457,7 @@ var Form = {
3392
3457
  var data = elements.inject({ }, function(result, element) {
3393
3458
  if (!element.disabled && element.name) {
3394
3459
  key = element.name; value = $(element).getValue();
3395
- if (value != null && (element.type != 'submit' || (!submitted &&
3460
+ if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
3396
3461
  submit !== false && (!submit || key == submit) && (submitted = true)))) {
3397
3462
  if (key in result) {
3398
3463
  // a key is already present; construct an array of values
@@ -3553,7 +3618,6 @@ Form.Element.Methods = {
3553
3618
 
3554
3619
  disable: function(element) {
3555
3620
  element = $(element);
3556
- element.blur();
3557
3621
  element.disabled = true;
3558
3622
  return element;
3559
3623
  },
@@ -3593,22 +3657,22 @@ Form.Element.Serializers = {
3593
3657
  else element.value = value;
3594
3658
  },
3595
3659
 
3596
- select: function(element, index) {
3597
- if (Object.isUndefined(index))
3660
+ select: function(element, value) {
3661
+ if (Object.isUndefined(value))
3598
3662
  return this[element.type == 'select-one' ?
3599
3663
  'selectOne' : 'selectMany'](element);
3600
3664
  else {
3601
- var opt, value, single = !Object.isArray(index);
3665
+ var opt, currentValue, single = !Object.isArray(value);
3602
3666
  for (var i = 0, length = element.length; i < length; i++) {
3603
3667
  opt = element.options[i];
3604
- value = this.optionValue(opt);
3668
+ currentValue = this.optionValue(opt);
3605
3669
  if (single) {
3606
- if (value == index) {
3670
+ if (currentValue == value) {
3607
3671
  opt.selected = true;
3608
3672
  return;
3609
3673
  }
3610
3674
  }
3611
- else opt.selected = index.include(value);
3675
+ else opt.selected = value.include(currentValue);
3612
3676
  }
3613
3677
  }
3614
3678
  },
@@ -3779,8 +3843,23 @@ Event.Methods = (function() {
3779
3843
  isRightClick: function(event) { return isButton(event, 2) },
3780
3844
 
3781
3845
  element: function(event) {
3782
- var node = Event.extend(event).target;
3783
- return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node);
3846
+ event = Event.extend(event);
3847
+
3848
+ var node = event.target,
3849
+ type = event.type,
3850
+ currentTarget = event.currentTarget;
3851
+
3852
+ if (currentTarget && currentTarget.tagName) {
3853
+ // Firefox screws up the "click" event when moving between radio buttons
3854
+ // via arrow keys. It also screws up the "load" and "error" events on images,
3855
+ // reporting the document as the target instead of the original image.
3856
+ if (type === 'load' || type === 'error' ||
3857
+ (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
3858
+ && currentTarget.type === 'radio'))
3859
+ node = currentTarget;
3860
+ }
3861
+ if (node.nodeType == Node.TEXT_NODE) node = node.parentNode;
3862
+ return Element.extend(node);
3784
3863
  },
3785
3864
 
3786
3865
  findElement: function(event, expression) {
@@ -3791,11 +3870,15 @@ Event.Methods = (function() {
3791
3870
  },
3792
3871
 
3793
3872
  pointer: function(event) {
3873
+ var docElement = document.documentElement,
3874
+ body = document.body || { scrollLeft: 0, scrollTop: 0 };
3794
3875
  return {
3795
3876
  x: event.pageX || (event.clientX +
3796
- (document.documentElement.scrollLeft || document.body.scrollLeft)),
3877
+ (docElement.scrollLeft || body.scrollLeft) -
3878
+ (docElement.clientLeft || 0)),
3797
3879
  y: event.pageY || (event.clientY +
3798
- (document.documentElement.scrollTop || document.body.scrollTop))
3880
+ (docElement.scrollTop || body.scrollTop) -
3881
+ (docElement.clientTop || 0))
3799
3882
  };
3800
3883
  },
3801
3884
 
@@ -3840,7 +3923,7 @@ Event.extend = (function() {
3840
3923
  };
3841
3924
 
3842
3925
  } else {
3843
- Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__;
3926
+ Event.prototype = Event.prototype || document.createEvent("HTMLEvents")['__proto__'];
3844
3927
  Object.extend(Event.prototype, methods);
3845
3928
  return Prototype.K;
3846
3929
  }
@@ -3850,9 +3933,9 @@ Object.extend(Event, (function() {
3850
3933
  var cache = Event.cache;
3851
3934
 
3852
3935
  function getEventID(element) {
3853
- if (element._eventID) return element._eventID;
3936
+ if (element._prototypeEventID) return element._prototypeEventID[0];
3854
3937
  arguments.callee.id = arguments.callee.id || 1;
3855
- return element._eventID = ++arguments.callee.id;
3938
+ return element._prototypeEventID = [++arguments.callee.id];
3856
3939
  }
3857
3940
 
3858
3941
  function getDOMEventName(eventName) {
@@ -3880,7 +3963,7 @@ Object.extend(Event, (function() {
3880
3963
  return false;
3881
3964
 
3882
3965
  Event.extend(event);
3883
- handler.call(element, event)
3966
+ handler.call(element, event);
3884
3967
  };
3885
3968
 
3886
3969
  wrapper.handler = handler;
@@ -3905,10 +3988,20 @@ Object.extend(Event, (function() {
3905
3988
  cache[id][eventName] = null;
3906
3989
  }
3907
3990
 
3991
+
3992
+ // Internet Explorer needs to remove event handlers on page unload
3993
+ // in order to avoid memory leaks.
3908
3994
  if (window.attachEvent) {
3909
3995
  window.attachEvent("onunload", destroyCache);
3910
3996
  }
3911
3997
 
3998
+ // Safari has a dummy event handler on page unload so that it won't
3999
+ // use its bfcache. Safari <= 3.1 has an issue with restoring the "document"
4000
+ // object when page is returned to via the back button using its bfcache.
4001
+ if (Prototype.Browser.WebKit) {
4002
+ window.addEventListener('unload', Prototype.emptyFunction, false);
4003
+ }
4004
+
3912
4005
  return {
3913
4006
  observe: function(element, eventName, handler) {
3914
4007
  element = $(element);
@@ -3962,11 +4055,12 @@ Object.extend(Event, (function() {
3962
4055
  if (element == document && document.createEvent && !element.dispatchEvent)
3963
4056
  element = document.documentElement;
3964
4057
 
4058
+ var event;
3965
4059
  if (document.createEvent) {
3966
- var event = document.createEvent("HTMLEvents");
4060
+ event = document.createEvent("HTMLEvents");
3967
4061
  event.initEvent("dataavailable", true, true);
3968
4062
  } else {
3969
- var event = document.createEventObject();
4063
+ event = document.createEventObject();
3970
4064
  event.eventType = "ondataavailable";
3971
4065
  }
3972
4066
 
@@ -3995,20 +4089,21 @@ Element.addMethods({
3995
4089
  Object.extend(document, {
3996
4090
  fire: Element.Methods.fire.methodize(),
3997
4091
  observe: Element.Methods.observe.methodize(),
3998
- stopObserving: Element.Methods.stopObserving.methodize()
4092
+ stopObserving: Element.Methods.stopObserving.methodize(),
4093
+ loaded: false
3999
4094
  });
4000
4095
 
4001
4096
  (function() {
4002
4097
  /* Support for the DOMContentLoaded event is based on work by Dan Webb,
4003
4098
  Matthias Miller, Dean Edwards and John Resig. */
4004
4099
 
4005
- var timer, fired = false;
4100
+ var timer;
4006
4101
 
4007
4102
  function fireContentLoadedEvent() {
4008
- if (fired) return;
4103
+ if (document.loaded) return;
4009
4104
  if (timer) window.clearInterval(timer);
4010
4105
  document.fire("dom:loaded");
4011
- fired = true;
4106
+ document.loaded = true;
4012
4107
  }
4013
4108
 
4014
4109
  if (document.addEventListener) {