bivouac 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. data/README +15 -0
  2. data/bin/bivouac +5 -10
  3. data/doc/rdoc/classes/BivouacHelpers/HtmlView.html +46 -37
  4. data/doc/rdoc/classes/BivouacHelpers/ScriptAculoUsView.html +27 -20
  5. data/doc/rdoc/created.rid +1 -1
  6. data/doc/rdoc/files/README.html +45 -1
  7. data/doc/rdoc/files/lib/bivouac/helpers/view/goh/html_rb.html +1 -1
  8. data/doc/rdoc/files/lib/bivouac/helpers/view/goh/javascript_rb.html +1 -1
  9. data/doc/rdoc/files/lib/bivouac/helpers/view/goh/scriptaculous_rb.html +1 -1
  10. data/examples/bivouac_sample/Rakefile +0 -0
  11. data/examples/bivouac_sample/app/controllers/toggle_sortable.rb +2 -1
  12. data/examples/bivouac_sample/app/views/_sortable_result.rb +1 -1
  13. data/examples/bivouac_sample/script/console +0 -0
  14. data/examples/bivouac_sample/script/generate +0 -0
  15. data/examples/bivouac_sample/script/plugin +0 -0
  16. data/examples/bivouac_sample/script/server +0 -0
  17. data/examples/blog/Rakefile +56 -0
  18. data/examples/blog/app/blog.rb +107 -0
  19. data/examples/blog/app/controllers/comment.rb +17 -0
  20. data/examples/blog/app/controllers/index.rb +15 -0
  21. data/examples/blog/app/controllers/login.rb +33 -0
  22. data/examples/blog/app/controllers/logout.rb +15 -0
  23. data/examples/blog/app/controllers/not_found.rb +14 -0
  24. data/examples/blog/app/controllers/post.rb +48 -0
  25. data/examples/blog/app/helpers/_helpers.rb +30 -0
  26. data/examples/blog/app/helpers/blog.rb +14 -0
  27. data/examples/blog/app/models/comment.rb +18 -0
  28. data/examples/blog/app/models/post.rb +19 -0
  29. data/examples/blog/app/models/user.rb +12 -0
  30. data/examples/blog/app/views/_partials.rb +81 -0
  31. data/examples/blog/app/views/index/index.rb +23 -0
  32. data/examples/blog/app/views/layouts/default_layout.rb +40 -0
  33. data/examples/blog/app/views/login/login.rb +27 -0
  34. data/examples/blog/app/views/not_found.rb +13 -0
  35. data/examples/blog/app/views/post/add.rb +12 -0
  36. data/examples/blog/app/views/post/edit.rb +12 -0
  37. data/examples/blog/app/views/post/view.rb +14 -0
  38. data/examples/blog/config/console.rc +12 -0
  39. data/examples/blog/config/database.yml +3 -0
  40. data/examples/blog/config/environment.rb +58 -0
  41. data/examples/blog/db/blog.db +0 -0
  42. data/examples/blog/db/create.rb +11 -0
  43. data/examples/blog/db/migrate/001_users.rb +22 -0
  44. data/examples/blog/db/migrate/002_posts.rb +24 -0
  45. data/examples/blog/db/migrate/003_comments.rb +24 -0
  46. data/examples/blog/log/Blog.log +382 -0
  47. data/examples/{blog_goh → blog}/public/images/camping.png +0 -0
  48. data/examples/{blog_goh → blog}/public/index.html +3 -2
  49. data/examples/blog/public/javascripts/builder.js +136 -0
  50. data/examples/blog/public/javascripts/controls.js +965 -0
  51. data/examples/blog/public/javascripts/dragdrop.js +974 -0
  52. data/examples/blog/public/javascripts/effects.js +1122 -0
  53. data/examples/blog/public/javascripts/prototype.js +4320 -0
  54. data/examples/blog/public/javascripts/scriptaculous.js +58 -0
  55. data/examples/blog/public/javascripts/slider.js +275 -0
  56. data/examples/blog/public/javascripts/sound.js +55 -0
  57. data/examples/blog/public/javascripts/unittest.js +568 -0
  58. data/examples/blog/public/stylesheets/autocomplete.css +22 -0
  59. data/examples/blog/public/stylesheets/blog.css +107 -0
  60. data/examples/blog/script/console +12 -0
  61. data/examples/blog/script/generate +17 -0
  62. data/examples/blog/script/plugin +16 -0
  63. data/examples/blog/script/server +135 -0
  64. data/examples/blog/test/test_comment.rb +22 -0
  65. data/examples/blog/test/test_index.rb +22 -0
  66. data/examples/blog/test/test_login.rb +22 -0
  67. data/examples/blog/test/test_logout.rb +18 -0
  68. data/examples/blog/test/test_post.rb +30 -0
  69. data/examples/blog/test/test_post_new.rb +22 -0
  70. data/lib/bivouac.rb +2 -2
  71. data/lib/bivouac/commands/generate.rb +48 -8
  72. data/lib/bivouac/commands/plugin.rb +30 -15
  73. data/lib/bivouac/ext/filtering_camping.rb +46 -0
  74. data/lib/bivouac/helpers/view/goh/html.rb +9 -0
  75. data/lib/bivouac/helpers/view/goh/scriptaculous.rb +12 -8
  76. data/lib/bivouac/tasks/bivouac.rb +1 -0
  77. data/lib/bivouac/tasks/framework.rake +8 -8
  78. data/lib/bivouac/tasks/plugins.rake +17 -1
  79. data/lib/bivouac/template.rb +0 -0
  80. data/lib/bivouac/template/{application_goh.rb → application.rb} +36 -12
  81. data/lib/bivouac/template/application/{helpers_goh.rb → helpers.rb} +1 -1
  82. data/lib/bivouac/template/console.rb +2 -4
  83. data/lib/bivouac/template/environment.rb +1 -1
  84. data/lib/bivouac/template/generate.rb +0 -0
  85. data/lib/bivouac/template/generate/create.rb +0 -0
  86. data/lib/bivouac/template/generate/helper.rb +12 -0
  87. data/lib/bivouac/template/generate/migrate.rb +0 -0
  88. data/lib/bivouac/template/generate/migrate_end.rb +1 -0
  89. data/lib/bivouac/template/plugin.rb +6 -1
  90. data/lib/bivouac/template/server.rb +124 -3
  91. data/lib/bivouac/template/static/builder.js +19 -19
  92. data/lib/bivouac/template/static/controls.js +74 -74
  93. data/lib/bivouac/template/static/dragdrop.js +167 -166
  94. data/lib/bivouac/template/static/effects.js +171 -163
  95. data/lib/bivouac/template/static/not_found_controller.rb +8 -4
  96. data/lib/bivouac/template/static/prototype.js +218 -119
  97. data/lib/bivouac/template/static/scriptaculous.js +22 -20
  98. data/lib/bivouac/template/static/slider.js +39 -39
  99. data/lib/bivouac/template/static/sound.js +11 -11
  100. data/lib/bivouac/template/static/unittest.js +16 -16
  101. metadata +96 -60
  102. data/examples/blog_goh/app/blog.rb +0 -72
  103. data/examples/blog_goh/app/controllers/add.rb +0 -19
  104. data/examples/blog_goh/app/controllers/comment.rb +0 -9
  105. data/examples/blog_goh/app/controllers/edit.rb +0 -18
  106. data/examples/blog_goh/app/controllers/index.rb +0 -8
  107. data/examples/blog_goh/app/controllers/info.rb +0 -11
  108. data/examples/blog_goh/app/controllers/login.rb +0 -15
  109. data/examples/blog_goh/app/controllers/logout.rb +0 -8
  110. data/examples/blog_goh/app/controllers/view.rb +0 -9
  111. data/examples/blog_goh/app/models/comment.rb +0 -5
  112. data/examples/blog_goh/app/models/post.rb +0 -5
  113. data/examples/blog_goh/app/models/user.rb +0 -4
  114. data/examples/blog_goh/app/views/_form.rb +0 -16
  115. data/examples/blog_goh/app/views/_login.rb +0 -13
  116. data/examples/blog_goh/app/views/_post.rb +0 -9
  117. data/examples/blog_goh/app/views/add.rb +0 -9
  118. data/examples/blog_goh/app/views/edit.rb +0 -9
  119. data/examples/blog_goh/app/views/index.rb +0 -12
  120. data/examples/blog_goh/app/views/layout.rb +0 -18
  121. data/examples/blog_goh/app/views/login.rb +0 -6
  122. data/examples/blog_goh/app/views/logout.rb +0 -6
  123. data/examples/blog_goh/app/views/view.rb +0 -20
  124. data/examples/blog_goh/config/environment.rb +0 -27
  125. data/examples/blog_goh/db/Blog.db +0 -0
  126. data/examples/blog_goh/db/create.rb +0 -8
  127. data/examples/blog_goh/db/migrate/comment.rb +0 -15
  128. data/examples/blog_goh/db/migrate/post.rb +0 -15
  129. data/examples/blog_goh/db/migrate/user.rb +0 -15
  130. data/examples/blog_goh/log/Blog.log +0 -75
  131. data/examples/blog_goh/public/stylesheets/style.css +0 -10
  132. data/examples/blog_goh/script/generate +0 -3
  133. data/examples/blog_goh/script/server +0 -5
  134. data/lib/bivouac/template/application/postamble.rb +0 -195
  135. data/lib/camping/cookies_sessions.rb +0 -39
@@ -5,12 +5,16 @@
5
5
  # Copyright (c) <%= Time.now.year %> __My__. All rights reserved.
6
6
  #
7
7
 
8
- module <%= @conf.appname %>::Controllers
9
- class NotFound
10
- def get( path )
8
+ module <%= @conf.appname %>
9
+ def r404(p=env.PATH)
10
+ puts p.gsub( /^\//, "" )
11
+ if File.exist?( File.join( filePath( __FILE__ ), '..', '..', 'public', p ) )
12
+ redirect "/public" << p
13
+ else
11
14
  @status = 404
12
- @path = path
15
+ @path = p
13
16
  render :not_found
14
17
  end
15
18
  end
16
19
  end
20
+
@@ -1,4 +1,4 @@
1
- /* Prototype JavaScript framework, version 1.6.0.2
1
+ /* Prototype JavaScript framework, version 1.6.0.3
2
2
  * (c) 2005-2008 Sam Stephenson
3
3
  *
4
4
  * Prototype is freely distributable under the terms of an MIT-style license.
@@ -7,23 +7,26 @@
7
7
  *--------------------------------------------------------------------------*/
8
8
 
9
9
  var Prototype = {
10
- Version: '1.6.0.2',
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
  }
@@ -167,7 +171,7 @@ 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) {
@@ -198,7 +202,8 @@ Object.extend(Object, {
198
202
 
199
203
  Object.extend(Function.prototype, {
200
204
  argumentNames: function() {
201
- 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(',');
202
207
  return names.length == 1 && !names[0] ? [] : names;
203
208
  },
204
209
 
@@ -232,6 +237,11 @@ Object.extend(Function.prototype, {
232
237
  }, timeout);
233
238
  },
234
239
 
240
+ defer: function() {
241
+ var args = [0.01].concat($A(arguments));
242
+ return this.delay.apply(this, args);
243
+ },
244
+
235
245
  wrap: function(wrapper) {
236
246
  var __method = this;
237
247
  return function() {
@@ -248,8 +258,6 @@ Object.extend(Function.prototype, {
248
258
  }
249
259
  });
250
260
 
251
- Function.prototype.defer = Function.prototype.delay.curry(0.01);
252
-
253
261
  Date.prototype.toJSON = function() {
254
262
  return '"' + this.getUTCFullYear() + '-' +
255
263
  (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
@@ -530,7 +538,7 @@ if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.proto
530
538
  return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
531
539
  },
532
540
  unescapeHTML: function() {
533
- return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
541
+ return this.stripTags().replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
534
542
  }
535
543
  });
536
544
 
@@ -547,7 +555,7 @@ Object.extend(String.prototype.escapeHTML, {
547
555
  text: document.createTextNode('')
548
556
  });
549
557
 
550
- with (String.prototype.escapeHTML) div.appendChild(text);
558
+ String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text);
551
559
 
552
560
  var Template = Class.create({
553
561
  initialize: function(template, pattern) {
@@ -589,10 +597,9 @@ var $break = { };
589
597
  var Enumerable = {
590
598
  each: function(iterator, context) {
591
599
  var index = 0;
592
- iterator = iterator.bind(context);
593
600
  try {
594
601
  this._each(function(value) {
595
- iterator(value, index++);
602
+ iterator.call(context, value, index++);
596
603
  });
597
604
  } catch (e) {
598
605
  if (e != $break) throw e;
@@ -601,47 +608,46 @@ var Enumerable = {
601
608
  },
602
609
 
603
610
  eachSlice: function(number, iterator, context) {
604
- iterator = iterator ? iterator.bind(context) : Prototype.K;
605
611
  var index = -number, slices = [], array = this.toArray();
612
+ if (number < 1) return array;
606
613
  while ((index += number) < array.length)
607
614
  slices.push(array.slice(index, index+number));
608
615
  return slices.collect(iterator, context);
609
616
  },
610
617
 
611
618
  all: function(iterator, context) {
612
- iterator = iterator ? iterator.bind(context) : Prototype.K;
619
+ iterator = iterator || Prototype.K;
613
620
  var result = true;
614
621
  this.each(function(value, index) {
615
- result = result && !!iterator(value, index);
622
+ result = result && !!iterator.call(context, value, index);
616
623
  if (!result) throw $break;
617
624
  });
618
625
  return result;
619
626
  },
620
627
 
621
628
  any: function(iterator, context) {
622
- iterator = iterator ? iterator.bind(context) : Prototype.K;
629
+ iterator = iterator || Prototype.K;
623
630
  var result = false;
624
631
  this.each(function(value, index) {
625
- if (result = !!iterator(value, index))
632
+ if (result = !!iterator.call(context, value, index))
626
633
  throw $break;
627
634
  });
628
635
  return result;
629
636
  },
630
637
 
631
638
  collect: function(iterator, context) {
632
- iterator = iterator ? iterator.bind(context) : Prototype.K;
639
+ iterator = iterator || Prototype.K;
633
640
  var results = [];
634
641
  this.each(function(value, index) {
635
- results.push(iterator(value, index));
642
+ results.push(iterator.call(context, value, index));
636
643
  });
637
644
  return results;
638
645
  },
639
646
 
640
647
  detect: function(iterator, context) {
641
- iterator = iterator.bind(context);
642
648
  var result;
643
649
  this.each(function(value, index) {
644
- if (iterator(value, index)) {
650
+ if (iterator.call(context, value, index)) {
645
651
  result = value;
646
652
  throw $break;
647
653
  }
@@ -650,17 +656,16 @@ var Enumerable = {
650
656
  },
651
657
 
652
658
  findAll: function(iterator, context) {
653
- iterator = iterator.bind(context);
654
659
  var results = [];
655
660
  this.each(function(value, index) {
656
- if (iterator(value, index))
661
+ if (iterator.call(context, value, index))
657
662
  results.push(value);
658
663
  });
659
664
  return results;
660
665
  },
661
666
 
662
667
  grep: function(filter, iterator, context) {
663
- iterator = iterator ? iterator.bind(context) : Prototype.K;
668
+ iterator = iterator || Prototype.K;
664
669
  var results = [];
665
670
 
666
671
  if (Object.isString(filter))
@@ -668,7 +673,7 @@ var Enumerable = {
668
673
 
669
674
  this.each(function(value, index) {
670
675
  if (filter.match(value))
671
- results.push(iterator(value, index));
676
+ results.push(iterator.call(context, value, index));
672
677
  });
673
678
  return results;
674
679
  },
@@ -696,9 +701,8 @@ var Enumerable = {
696
701
  },
697
702
 
698
703
  inject: function(memo, iterator, context) {
699
- iterator = iterator.bind(context);
700
704
  this.each(function(value, index) {
701
- memo = iterator(memo, value, index);
705
+ memo = iterator.call(context, memo, value, index);
702
706
  });
703
707
  return memo;
704
708
  },
@@ -711,10 +715,10 @@ var Enumerable = {
711
715
  },
712
716
 
713
717
  max: function(iterator, context) {
714
- iterator = iterator ? iterator.bind(context) : Prototype.K;
718
+ iterator = iterator || Prototype.K;
715
719
  var result;
716
720
  this.each(function(value, index) {
717
- value = iterator(value, index);
721
+ value = iterator.call(context, value, index);
718
722
  if (result == null || value >= result)
719
723
  result = value;
720
724
  });
@@ -722,10 +726,10 @@ var Enumerable = {
722
726
  },
723
727
 
724
728
  min: function(iterator, context) {
725
- iterator = iterator ? iterator.bind(context) : Prototype.K;
729
+ iterator = iterator || Prototype.K;
726
730
  var result;
727
731
  this.each(function(value, index) {
728
- value = iterator(value, index);
732
+ value = iterator.call(context, value, index);
729
733
  if (result == null || value < result)
730
734
  result = value;
731
735
  });
@@ -733,10 +737,10 @@ var Enumerable = {
733
737
  },
734
738
 
735
739
  partition: function(iterator, context) {
736
- iterator = iterator ? iterator.bind(context) : Prototype.K;
740
+ iterator = iterator || Prototype.K;
737
741
  var trues = [], falses = [];
738
742
  this.each(function(value, index) {
739
- (iterator(value, index) ?
743
+ (iterator.call(context, value, index) ?
740
744
  trues : falses).push(value);
741
745
  });
742
746
  return [trues, falses];
@@ -751,19 +755,20 @@ var Enumerable = {
751
755
  },
752
756
 
753
757
  reject: function(iterator, context) {
754
- iterator = iterator.bind(context);
755
758
  var results = [];
756
759
  this.each(function(value, index) {
757
- if (!iterator(value, index))
760
+ if (!iterator.call(context, value, index))
758
761
  results.push(value);
759
762
  });
760
763
  return results;
761
764
  },
762
765
 
763
766
  sortBy: function(iterator, context) {
764
- iterator = iterator.bind(context);
765
767
  return this.map(function(value, index) {
766
- return {value: value, criteria: iterator(value, index)};
768
+ return {
769
+ value: value,
770
+ criteria: iterator.call(context, value, index)
771
+ };
767
772
  }).sort(function(left, right) {
768
773
  var a = left.criteria, b = right.criteria;
769
774
  return a < b ? -1 : a > b ? 1 : 0;
@@ -815,8 +820,12 @@ function $A(iterable) {
815
820
  if (Prototype.Browser.WebKit) {
816
821
  $A = function(iterable) {
817
822
  if (!iterable) return [];
818
- if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
819
- iterable.toArray) return iterable.toArray();
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();
820
829
  var length = iterable.length || 0, results = new Array(length);
821
830
  while (length--) results[length] = iterable[length];
822
831
  return results;
@@ -963,8 +972,8 @@ Object.extend(Number.prototype, {
963
972
  return this + 1;
964
973
  },
965
974
 
966
- times: function(iterator) {
967
- $R(0, this, true).each(iterator);
975
+ times: function(iterator, context) {
976
+ $R(0, this, true).each(iterator, context);
968
977
  return this;
969
978
  },
970
979
 
@@ -1011,7 +1020,9 @@ var Hash = Class.create(Enumerable, (function() {
1011
1020
  },
1012
1021
 
1013
1022
  get: function(key) {
1014
- return this._object[key];
1023
+ // simulating poorly supported hasOwnProperty
1024
+ if (this._object[key] !== Object.prototype[key])
1025
+ return this._object[key];
1015
1026
  },
1016
1027
 
1017
1028
  unset: function(key) {
@@ -1051,14 +1062,14 @@ var Hash = Class.create(Enumerable, (function() {
1051
1062
  },
1052
1063
 
1053
1064
  toQueryString: function() {
1054
- return this.map(function(pair) {
1065
+ return this.inject([], function(results, pair) {
1055
1066
  var key = encodeURIComponent(pair.key), values = pair.value;
1056
1067
 
1057
1068
  if (values && typeof values == 'object') {
1058
1069
  if (Object.isArray(values))
1059
- return values.map(toQueryPair.curry(key)).join('&');
1060
- }
1061
- return toQueryPair(key, values);
1070
+ return results.concat(values.map(toQueryPair.curry(key)));
1071
+ } else results.push(toQueryPair(key, values));
1072
+ return results;
1062
1073
  }).join('&');
1063
1074
  },
1064
1075
 
@@ -1558,6 +1569,7 @@ if (!Node.ELEMENT_NODE) {
1558
1569
  return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
1559
1570
  };
1560
1571
  Object.extend(this.Element, element || { });
1572
+ if (element) this.Element.prototype = element.prototype;
1561
1573
  }).call(window);
1562
1574
 
1563
1575
  Element.cache = { };
@@ -1574,12 +1586,14 @@ Element.Methods = {
1574
1586
  },
1575
1587
 
1576
1588
  hide: function(element) {
1577
- $(element).style.display = 'none';
1589
+ element = $(element);
1590
+ element.style.display = 'none';
1578
1591
  return element;
1579
1592
  },
1580
1593
 
1581
1594
  show: function(element) {
1582
- $(element).style.display = '';
1595
+ element = $(element);
1596
+ element.style.display = '';
1583
1597
  return element;
1584
1598
  },
1585
1599
 
@@ -1733,7 +1747,7 @@ Element.Methods = {
1733
1747
  element = $(element);
1734
1748
  if (arguments.length == 1) return element.firstDescendant();
1735
1749
  return Object.isNumber(expression) ? element.descendants()[expression] :
1736
- element.select(expression)[index || 0];
1750
+ Element.select(element, expression)[index || 0];
1737
1751
  },
1738
1752
 
1739
1753
  previous: function(element, expression, index) {
@@ -1863,24 +1877,16 @@ Element.Methods = {
1863
1877
 
1864
1878
  descendantOf: function(element, ancestor) {
1865
1879
  element = $(element), ancestor = $(ancestor);
1866
- var originalAncestor = ancestor;
1867
1880
 
1868
1881
  if (element.compareDocumentPosition)
1869
1882
  return (element.compareDocumentPosition(ancestor) & 8) === 8;
1870
1883
 
1871
- if (element.sourceIndex && !Prototype.Browser.Opera) {
1872
- var e = element.sourceIndex, a = ancestor.sourceIndex,
1873
- nextAncestor = ancestor.nextSibling;
1874
- if (!nextAncestor) {
1875
- do { ancestor = ancestor.parentNode; }
1876
- while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);
1877
- }
1878
- if (nextAncestor && nextAncestor.sourceIndex)
1879
- return (e > a && e < nextAncestor.sourceIndex);
1880
- }
1884
+ if (ancestor.contains)
1885
+ return ancestor.contains(element) && ancestor !== element;
1881
1886
 
1882
1887
  while (element = element.parentNode)
1883
- if (element == originalAncestor) return true;
1888
+ if (element == ancestor) return true;
1889
+
1884
1890
  return false;
1885
1891
  },
1886
1892
 
@@ -1895,7 +1901,7 @@ Element.Methods = {
1895
1901
  element = $(element);
1896
1902
  style = style == 'float' ? 'cssFloat' : style.camelize();
1897
1903
  var value = element.style[style];
1898
- if (!value) {
1904
+ if (!value || value == 'auto') {
1899
1905
  var css = document.defaultView.getComputedStyle(element, null);
1900
1906
  value = css ? css[style] : null;
1901
1907
  }
@@ -1934,7 +1940,7 @@ Element.Methods = {
1934
1940
 
1935
1941
  getDimensions: function(element) {
1936
1942
  element = $(element);
1937
- var display = $(element).getStyle('display');
1943
+ var display = element.getStyle('display');
1938
1944
  if (display != 'none' && display != null) // Safari bug
1939
1945
  return {width: element.offsetWidth, height: element.offsetHeight};
1940
1946
 
@@ -1963,7 +1969,7 @@ Element.Methods = {
1963
1969
  element.style.position = 'relative';
1964
1970
  // Opera returns the offset relative to the positioning context, when an
1965
1971
  // element is position relative but top and left have not been defined
1966
- if (window.opera) {
1972
+ if (Prototype.Browser.Opera) {
1967
1973
  element.style.top = 0;
1968
1974
  element.style.left = 0;
1969
1975
  }
@@ -2018,7 +2024,7 @@ Element.Methods = {
2018
2024
  valueL += element.offsetLeft || 0;
2019
2025
  element = element.offsetParent;
2020
2026
  if (element) {
2021
- if (element.tagName == 'BODY') break;
2027
+ if (element.tagName.toUpperCase() == 'BODY') break;
2022
2028
  var p = Element.getStyle(element, 'position');
2023
2029
  if (p !== 'static') break;
2024
2030
  }
@@ -2028,7 +2034,7 @@ Element.Methods = {
2028
2034
 
2029
2035
  absolutize: function(element) {
2030
2036
  element = $(element);
2031
- if (element.getStyle('position') == 'absolute') return;
2037
+ if (element.getStyle('position') == 'absolute') return element;
2032
2038
  // Position.prepare(); // To be done manually by Scripty when it needs it.
2033
2039
 
2034
2040
  var offsets = element.positionedOffset();
@@ -2052,7 +2058,7 @@ Element.Methods = {
2052
2058
 
2053
2059
  relativize: function(element) {
2054
2060
  element = $(element);
2055
- if (element.getStyle('position') == 'relative') return;
2061
+ if (element.getStyle('position') == 'relative') return element;
2056
2062
  // Position.prepare(); // To be done manually by Scripty when it needs it.
2057
2063
 
2058
2064
  element.style.position = 'relative';
@@ -2103,7 +2109,7 @@ Element.Methods = {
2103
2109
 
2104
2110
  element = forElement;
2105
2111
  do {
2106
- if (!Prototype.Browser.Opera || element.tagName == 'BODY') {
2112
+ if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) {
2107
2113
  valueT -= element.scrollTop || 0;
2108
2114
  valueL -= element.scrollLeft || 0;
2109
2115
  }
@@ -2218,6 +2224,9 @@ else if (Prototype.Browser.IE) {
2218
2224
  Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
2219
2225
  function(proceed, element) {
2220
2226
  element = $(element);
2227
+ // IE throws an error if element is not in document
2228
+ try { element.offsetParent }
2229
+ catch(e) { return $(document.body) }
2221
2230
  var position = element.getStyle('position');
2222
2231
  if (position !== 'static') return proceed(element);
2223
2232
  element.setStyle({ position: 'relative' });
@@ -2231,6 +2240,8 @@ else if (Prototype.Browser.IE) {
2231
2240
  Element.Methods[method] = Element.Methods[method].wrap(
2232
2241
  function(proceed, element) {
2233
2242
  element = $(element);
2243
+ try { element.offsetParent }
2244
+ catch(e) { return Element._returnOffset(0,0) }
2234
2245
  var position = element.getStyle('position');
2235
2246
  if (position !== 'static') return proceed(element);
2236
2247
  // Trigger hasLayout on the offset parent so that IE6 reports
@@ -2246,6 +2257,14 @@ else if (Prototype.Browser.IE) {
2246
2257
  );
2247
2258
  });
2248
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
+
2249
2268
  Element.Methods.getStyle = function(element, style) {
2250
2269
  element = $(element);
2251
2270
  style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
@@ -2337,7 +2356,7 @@ else if (Prototype.Browser.IE) {
2337
2356
  Element._attributeTranslations.has = {};
2338
2357
 
2339
2358
  $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
2340
- 'encType maxLength readOnly longDesc').each(function(attr) {
2359
+ 'encType maxLength readOnly longDesc frameBorder').each(function(attr) {
2341
2360
  Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
2342
2361
  Element._attributeTranslations.has[attr.toLowerCase()] = attr;
2343
2362
  });
@@ -2390,7 +2409,7 @@ else if (Prototype.Browser.WebKit) {
2390
2409
  (value < 0.00001) ? 0 : value;
2391
2410
 
2392
2411
  if (value == 1)
2393
- if(element.tagName == 'IMG' && element.width) {
2412
+ if(element.tagName.toUpperCase() == 'IMG' && element.width) {
2394
2413
  element.width++; element.width--;
2395
2414
  } else try {
2396
2415
  var n = document.createTextNode(' ');
@@ -2521,7 +2540,7 @@ Element.Methods.Simulated = {
2521
2540
  hasAttribute: function(element, attribute) {
2522
2541
  attribute = Element._attributeTranslations.has[attribute] || attribute;
2523
2542
  var node = $(element).getAttributeNode(attribute);
2524
- return node && node.specified;
2543
+ return !!(node && node.specified);
2525
2544
  }
2526
2545
  };
2527
2546
 
@@ -2530,9 +2549,9 @@ Element.Methods.ByTag = { };
2530
2549
  Object.extend(Element, Element.Methods);
2531
2550
 
2532
2551
  if (!Prototype.BrowserFeatures.ElementExtensions &&
2533
- document.createElement('div').__proto__) {
2552
+ document.createElement('div')['__proto__']) {
2534
2553
  window.HTMLElement = { };
2535
- window.HTMLElement.prototype = document.createElement('div').__proto__;
2554
+ window.HTMLElement.prototype = document.createElement('div')['__proto__'];
2536
2555
  Prototype.BrowserFeatures.ElementExtensions = true;
2537
2556
  }
2538
2557
 
@@ -2547,7 +2566,7 @@ Element.extend = (function() {
2547
2566
  element.nodeType != 1 || element == window) return element;
2548
2567
 
2549
2568
  var methods = Object.clone(Methods),
2550
- tagName = element.tagName, property, value;
2569
+ tagName = element.tagName.toUpperCase(), property, value;
2551
2570
 
2552
2571
  // extend methods for specific tags
2553
2572
  if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
@@ -2643,7 +2662,7 @@ Element.addMethods = function(methods) {
2643
2662
  if (window[klass]) return window[klass];
2644
2663
 
2645
2664
  window[klass] = { };
2646
- window[klass].prototype = document.createElement(tagName).__proto__;
2665
+ window[klass].prototype = document.createElement(tagName)['__proto__'];
2647
2666
  return window[klass];
2648
2667
  }
2649
2668
 
@@ -2669,12 +2688,18 @@ Element.addMethods = function(methods) {
2669
2688
 
2670
2689
  document.viewport = {
2671
2690
  getDimensions: function() {
2672
- var dimensions = { };
2673
- var B = Prototype.Browser;
2691
+ var dimensions = { }, B = Prototype.Browser;
2674
2692
  $w('width height').each(function(d) {
2675
2693
  var D = d.capitalize();
2676
- dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] :
2677
- (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
+ }
2678
2703
  });
2679
2704
  return dimensions;
2680
2705
  },
@@ -2693,14 +2718,24 @@ document.viewport = {
2693
2718
  window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
2694
2719
  }
2695
2720
  };
2696
- /* Portions of the Selector class are derived from Jack Slocums DomQuery,
2721
+ /* Portions of the Selector class are derived from Jack Slocum's DomQuery,
2697
2722
  * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
2698
2723
  * license. Please see http://www.yui-ext.com/ for more information. */
2699
2724
 
2700
2725
  var Selector = Class.create({
2701
2726
  initialize: function(expression) {
2702
2727
  this.expression = expression.strip();
2703
- 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
+
2704
2739
  },
2705
2740
 
2706
2741
  shouldUseXPath: function() {
@@ -2715,16 +2750,29 @@ var Selector = Class.create({
2715
2750
 
2716
2751
  // XPath can't do namespaced attributes, nor can it read
2717
2752
  // the "checked" property from DOM nodes
2718
- if ((/(\[[\w-]*?:|:checked)/).test(this.expression))
2753
+ if ((/(\[[\w-]*?:|:checked)/).test(e))
2719
2754
  return false;
2720
2755
 
2721
2756
  return true;
2722
2757
  },
2723
2758
 
2724
- compileMatcher: function() {
2725
- if (this.shouldUseXPath())
2726
- 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
+ }
2771
+
2772
+ return true;
2773
+ },
2727
2774
 
2775
+ compileMatcher: function() {
2728
2776
  var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
2729
2777
  c = Selector.criteria, le, p, m;
2730
2778
 
@@ -2742,7 +2790,7 @@ var Selector = Class.create({
2742
2790
  p = ps[i];
2743
2791
  if (m = e.match(p)) {
2744
2792
  this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
2745
- new Template(c[i]).evaluate(m));
2793
+ new Template(c[i]).evaluate(m));
2746
2794
  e = e.replace(m[0], '');
2747
2795
  break;
2748
2796
  }
@@ -2781,8 +2829,27 @@ var Selector = Class.create({
2781
2829
 
2782
2830
  findElements: function(root) {
2783
2831
  root = root || document;
2784
- if (this.xpath) return document._getElementsByXPath(this.xpath, root);
2785
- 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
+ }
2786
2853
  },
2787
2854
 
2788
2855
  match: function(element) {
@@ -2873,10 +2940,10 @@ Object.extend(Selector, {
2873
2940
  'first-child': '[not(preceding-sibling::*)]',
2874
2941
  'last-child': '[not(following-sibling::*)]',
2875
2942
  'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
2876
- 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
2943
+ 'empty': "[count(*) = 0 and (count(text()) = 0)]",
2877
2944
  'checked': "[@checked]",
2878
- 'disabled': "[@disabled]",
2879
- 'enabled': "[not(@disabled)]",
2945
+ 'disabled': "[(@disabled) and (@type!='hidden')]",
2946
+ 'enabled': "[not(@disabled) and (@type!='hidden')]",
2880
2947
  'not': function(m) {
2881
2948
  var e = m[6], p = Selector.patterns,
2882
2949
  x = Selector.xpath, le, v;
@@ -2968,7 +3035,7 @@ Object.extend(Selector, {
2968
3035
  className: /^\.([\w\-\*]+)(\b|$)/,
2969
3036
  pseudo:
2970
3037
  /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,
2971
- attrPresence: /^\[([\w]+)\]/,
3038
+ attrPresence: /^\[((?:[\w]+:)?[\w]+)\]/,
2972
3039
  attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
2973
3040
  },
2974
3041
 
@@ -3081,7 +3148,7 @@ Object.extend(Selector, {
3081
3148
 
3082
3149
  nextElementSibling: function(node) {
3083
3150
  while (node = node.nextSibling)
3084
- if (node.nodeType == 1) return node;
3151
+ if (node.nodeType == 1) return node;
3085
3152
  return null;
3086
3153
  },
3087
3154
 
@@ -3270,7 +3337,7 @@ Object.extend(Selector, {
3270
3337
  'empty': function(nodes, value, root) {
3271
3338
  for (var i = 0, results = [], node; node = nodes[i]; i++) {
3272
3339
  // IE treats comments as element nodes
3273
- if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
3340
+ if (node.tagName == '!' || node.firstChild) continue;
3274
3341
  results.push(node);
3275
3342
  }
3276
3343
  return results;
@@ -3288,7 +3355,8 @@ Object.extend(Selector, {
3288
3355
 
3289
3356
  'enabled': function(nodes, value, root) {
3290
3357
  for (var i = 0, results = [], node; node = nodes[i]; i++)
3291
- if (!node.disabled) results.push(node);
3358
+ if (!node.disabled && (!node.type || node.type !== 'hidden'))
3359
+ results.push(node);
3292
3360
  return results;
3293
3361
  },
3294
3362
 
@@ -3308,11 +3376,14 @@ Object.extend(Selector, {
3308
3376
  operators: {
3309
3377
  '=': function(nv, v) { return nv == v; },
3310
3378
  '!=': function(nv, v) { return nv != v; },
3311
- '^=': 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); },
3312
3382
  '$=': function(nv, v) { return nv.endsWith(v); },
3313
3383
  '*=': function(nv, v) { return nv.include(v); },
3314
3384
  '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
3315
- '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
3385
+ '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() +
3386
+ '-').include('-' + (v || "").toUpperCase() + '-'); }
3316
3387
  },
3317
3388
 
3318
3389
  split: function(expression) {
@@ -3386,7 +3457,7 @@ var Form = {
3386
3457
  var data = elements.inject({ }, function(result, element) {
3387
3458
  if (!element.disabled && element.name) {
3388
3459
  key = element.name; value = $(element).getValue();
3389
- if (value != null && (element.type != 'submit' || (!submitted &&
3460
+ if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
3390
3461
  submit !== false && (!submit || key == submit) && (submitted = true)))) {
3391
3462
  if (key in result) {
3392
3463
  // a key is already present; construct an array of values
@@ -3547,7 +3618,6 @@ Form.Element.Methods = {
3547
3618
 
3548
3619
  disable: function(element) {
3549
3620
  element = $(element);
3550
- element.blur();
3551
3621
  element.disabled = true;
3552
3622
  return element;
3553
3623
  },
@@ -3587,22 +3657,22 @@ Form.Element.Serializers = {
3587
3657
  else element.value = value;
3588
3658
  },
3589
3659
 
3590
- select: function(element, index) {
3591
- if (Object.isUndefined(index))
3660
+ select: function(element, value) {
3661
+ if (Object.isUndefined(value))
3592
3662
  return this[element.type == 'select-one' ?
3593
3663
  'selectOne' : 'selectMany'](element);
3594
3664
  else {
3595
- var opt, value, single = !Object.isArray(index);
3665
+ var opt, currentValue, single = !Object.isArray(value);
3596
3666
  for (var i = 0, length = element.length; i < length; i++) {
3597
3667
  opt = element.options[i];
3598
- value = this.optionValue(opt);
3668
+ currentValue = this.optionValue(opt);
3599
3669
  if (single) {
3600
- if (value == index) {
3670
+ if (currentValue == value) {
3601
3671
  opt.selected = true;
3602
3672
  return;
3603
3673
  }
3604
3674
  }
3605
- else opt.selected = index.include(value);
3675
+ else opt.selected = value.include(currentValue);
3606
3676
  }
3607
3677
  }
3608
3678
  },
@@ -3773,8 +3843,23 @@ Event.Methods = (function() {
3773
3843
  isRightClick: function(event) { return isButton(event, 2) },
3774
3844
 
3775
3845
  element: function(event) {
3776
- var node = Event.extend(event).target;
3777
- 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);
3778
3863
  },
3779
3864
 
3780
3865
  findElement: function(event, expression) {
@@ -3785,11 +3870,15 @@ Event.Methods = (function() {
3785
3870
  },
3786
3871
 
3787
3872
  pointer: function(event) {
3873
+ var docElement = document.documentElement,
3874
+ body = document.body || { scrollLeft: 0, scrollTop: 0 };
3788
3875
  return {
3789
3876
  x: event.pageX || (event.clientX +
3790
- (document.documentElement.scrollLeft || document.body.scrollLeft)),
3877
+ (docElement.scrollLeft || body.scrollLeft) -
3878
+ (docElement.clientLeft || 0)),
3791
3879
  y: event.pageY || (event.clientY +
3792
- (document.documentElement.scrollTop || document.body.scrollTop))
3880
+ (docElement.scrollTop || body.scrollTop) -
3881
+ (docElement.clientTop || 0))
3793
3882
  };
3794
3883
  },
3795
3884
 
@@ -3834,7 +3923,7 @@ Event.extend = (function() {
3834
3923
  };
3835
3924
 
3836
3925
  } else {
3837
- Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__;
3926
+ Event.prototype = Event.prototype || document.createEvent("HTMLEvents")['__proto__'];
3838
3927
  Object.extend(Event.prototype, methods);
3839
3928
  return Prototype.K;
3840
3929
  }
@@ -3899,10 +3988,20 @@ Object.extend(Event, (function() {
3899
3988
  cache[id][eventName] = null;
3900
3989
  }
3901
3990
 
3991
+
3992
+ // Internet Explorer needs to remove event handlers on page unload
3993
+ // in order to avoid memory leaks.
3902
3994
  if (window.attachEvent) {
3903
3995
  window.attachEvent("onunload", destroyCache);
3904
3996
  }
3905
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
+
3906
4005
  return {
3907
4006
  observe: function(element, eventName, handler) {
3908
4007
  element = $(element);