radiant 0.6.3 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of radiant might be problematic. Click here for more details.

Files changed (197) hide show
  1. data/CHANGELOG +61 -7
  2. data/CONTRIBUTORS +15 -0
  3. data/app/controllers/admin/export_controller.rb +1 -1
  4. data/app/controllers/admin/page_controller.rb +1 -0
  5. data/app/controllers/admin/user_controller.rb +2 -1
  6. data/app/controllers/application.rb +7 -8
  7. data/app/helpers/admin/node_helper.rb +84 -0
  8. data/app/helpers/admin/page_helper.rb +1 -19
  9. data/app/helpers/application_helper.rb +15 -9
  10. data/app/models/file_not_found_page.rb +2 -2
  11. data/app/models/page.rb +22 -18
  12. data/app/models/page_context.rb +9 -0
  13. data/app/models/radiant/config.rb +4 -2
  14. data/app/models/response_cache.rb +18 -12
  15. data/app/models/standard_tags.rb +111 -50
  16. data/app/views/admin/extension/index.rhtml +2 -2
  17. data/app/views/admin/layout/edit.rhtml +2 -2
  18. data/app/views/admin/layout/remove.rhtml +2 -2
  19. data/app/views/admin/page/_node.rhtml +4 -26
  20. data/app/views/admin/page/_part.rhtml +9 -14
  21. data/app/views/admin/page/edit.rhtml +38 -121
  22. data/app/views/admin/page/index.rhtml +2 -6
  23. data/app/views/admin/page/remove.rhtml +2 -2
  24. data/app/views/admin/snippet/edit.rhtml +3 -3
  25. data/app/views/admin/snippet/index.rhtml +2 -2
  26. data/app/views/admin/snippet/remove.rhtml +2 -2
  27. data/app/views/admin/user/edit.rhtml +4 -4
  28. data/app/views/admin/user/preferences.rhtml +2 -2
  29. data/app/views/admin/welcome/login.rhtml +1 -1
  30. data/config/environment.rb +79 -78
  31. data/db/schema.rb +2 -0
  32. data/lib/local_time.rb +12 -0
  33. data/lib/plugins/extension_patches/lib/fixture_loading_extension.rb +1 -1
  34. data/lib/plugins/extension_patches/lib/mailer_view_paths_extension.rb +3 -3
  35. data/lib/radiant.rb +1 -1
  36. data/lib/radiant/extension.rb +9 -3
  37. data/lib/radiant/extension_loader.rb +2 -2
  38. data/lib/tasks/extensions.rake +23 -8
  39. data/public/javascripts/admin.js +89 -0
  40. data/public/javascripts/controls.js +486 -354
  41. data/public/javascripts/dragdrop.js +90 -58
  42. data/public/javascripts/effects.js +398 -364
  43. data/public/javascripts/pngfix.js +37 -37
  44. data/public/javascripts/prototype.js +2764 -1095
  45. data/public/javascripts/ruledtable.js +10 -25
  46. data/public/javascripts/sitemap.js +74 -112
  47. data/public/javascripts/string.js +1 -7
  48. data/public/javascripts/tabcontrol.js +71 -86
  49. data/public/javascripts/tag_reference_search.js +19 -26
  50. data/public/stylesheets/admin/main.css +11 -5
  51. data/test/fixtures/extensions/01_basic/lib/new_module.rb +2 -0
  52. data/test/fixtures/page_parts.yml +16 -1
  53. data/test/fixtures/pages.yml +47 -84
  54. data/test/functional/extension_initialization_test.rb +11 -0
  55. data/test/helpers/login_test_helper.rb +12 -1
  56. data/test/helpers/page_test_helper.rb +6 -0
  57. data/test/helpers/render_test_helper.rb +11 -8
  58. data/test/test_helper.rb +1 -12
  59. data/test/unit/file_not_found_page_test.rb +5 -1
  60. data/test/unit/local_time_test.rb +45 -0
  61. data/test/unit/page_context_test.rb +32 -1
  62. data/test/unit/page_test.rb +45 -11
  63. data/test/unit/radiant/config_test.rb +1 -1
  64. data/test/unit/response_cache_test.rb +27 -2
  65. data/test/unit/standard_tags_test.rb +60 -15
  66. data/vendor/extensions/archive/README +29 -0
  67. data/vendor/extensions/archive/Rakefile +25 -0
  68. data/{app → vendor/extensions/archive/app}/models/archive_day_index_page.rb +0 -0
  69. data/{app → vendor/extensions/archive/app}/models/archive_finder.rb +8 -6
  70. data/{app → vendor/extensions/archive/app}/models/archive_month_index_page.rb +0 -0
  71. data/{app → vendor/extensions/archive/app}/models/archive_page.rb +0 -0
  72. data/{app → vendor/extensions/archive/app}/models/archive_year_index_page.rb +0 -0
  73. data/vendor/extensions/archive/archive_extension.rb +19 -0
  74. data/{lib → vendor/extensions/archive/lib}/archive_index_tags_and_methods.rb +0 -0
  75. data/vendor/extensions/archive/lib/tasks/archive_extension_tasks.rake +28 -0
  76. data/vendor/extensions/archive/test/fixtures/pages.yml +397 -0
  77. data/vendor/extensions/archive/test/functional/archive_extension_test.rb +16 -0
  78. data/{test → vendor/extensions/archive/test}/helpers/archive_index_test_helper.rb +0 -0
  79. data/vendor/extensions/archive/test/test_helper.rb +19 -0
  80. data/{test → vendor/extensions/archive/test}/unit/archive_day_index_page_test.rb +0 -0
  81. data/{test → vendor/extensions/archive/test}/unit/archive_month_index_page_test.rb +0 -0
  82. data/{test → vendor/extensions/archive/test}/unit/archive_page_test.rb +7 -1
  83. data/{test → vendor/extensions/archive/test}/unit/archive_year_index_page_test.rb +0 -0
  84. data/vendor/rails/actionmailer/CHANGELOG +10 -0
  85. data/vendor/rails/actionmailer/Rakefile +1 -1
  86. data/vendor/rails/actionmailer/lib/action_mailer/version.rb +1 -1
  87. data/vendor/rails/actionpack/CHANGELOG +51 -2
  88. data/vendor/rails/actionpack/Rakefile +1 -1
  89. data/vendor/rails/actionpack/lib/action_controller/assertions/dom_assertions.rb +2 -2
  90. data/vendor/rails/actionpack/lib/action_controller/assertions/model_assertions.rb +1 -1
  91. data/vendor/rails/actionpack/lib/action_controller/assertions/response_assertions.rb +3 -0
  92. data/vendor/rails/actionpack/lib/action_controller/assertions/routing_assertions.rb +1 -0
  93. data/vendor/rails/actionpack/lib/action_controller/assertions/selector_assertions.rb +2 -0
  94. data/vendor/rails/actionpack/lib/action_controller/base.rb +7 -1
  95. data/vendor/rails/actionpack/lib/action_controller/caching.rb +39 -38
  96. data/vendor/rails/actionpack/lib/action_controller/cgi_ext/pstore_performance_fix.rb +30 -0
  97. data/vendor/rails/actionpack/lib/action_controller/cgi_ext/raw_post_data_fix.rb +1 -1
  98. data/vendor/rails/actionpack/lib/action_controller/cgi_process.rb +13 -4
  99. data/vendor/rails/actionpack/lib/action_controller/cookies.rb +5 -3
  100. data/vendor/rails/actionpack/lib/action_controller/filters.rb +176 -77
  101. data/vendor/rails/actionpack/lib/action_controller/integration.rb +31 -21
  102. data/vendor/rails/actionpack/lib/action_controller/macros/in_place_editing.rb +1 -1
  103. data/vendor/rails/actionpack/lib/action_controller/pagination.rb +7 -1
  104. data/vendor/rails/actionpack/lib/action_controller/resources.rb +117 -32
  105. data/vendor/rails/actionpack/lib/action_controller/routing.rb +56 -23
  106. data/vendor/rails/actionpack/lib/action_controller/test_process.rb +5 -2
  107. data/vendor/rails/actionpack/lib/action_controller/url_rewriter.rb +4 -1
  108. data/vendor/rails/actionpack/lib/action_controller/verification.rb +1 -0
  109. data/vendor/rails/actionpack/lib/action_pack/version.rb +1 -1
  110. data/vendor/rails/actionpack/lib/action_view/base.rb +25 -19
  111. data/vendor/rails/actionpack/lib/action_view/compiled_templates.rb +2 -2
  112. data/vendor/rails/actionpack/lib/action_view/helpers/active_record_helper.rb +18 -18
  113. data/vendor/rails/actionpack/lib/action_view/helpers/debug_helper.rb +10 -0
  114. data/vendor/rails/actionpack/lib/action_view/helpers/deprecated_helper.rb +3 -0
  115. data/vendor/rails/actionpack/lib/action_view/helpers/prototype_helper.rb +33 -17
  116. data/vendor/rails/actionpack/test/activerecord/pagination_test.rb +9 -0
  117. data/vendor/rails/actionpack/test/controller/action_pack_assertions_test.rb +13 -0
  118. data/vendor/rails/actionpack/test/controller/addresses_render_test.rb +4 -1
  119. data/vendor/rails/actionpack/test/controller/base_test.rb +1 -1
  120. data/vendor/rails/actionpack/test/controller/caching_test.rb +3 -2
  121. data/vendor/rails/actionpack/test/controller/cookie_test.rb +11 -0
  122. data/vendor/rails/actionpack/test/controller/deprecation/deprecated_base_methods_test.rb +18 -0
  123. data/vendor/rails/actionpack/test/controller/filter_params_test.rb +1 -0
  124. data/vendor/rails/actionpack/test/controller/filters_test.rb +149 -26
  125. data/vendor/rails/actionpack/test/controller/integration_test.rb +93 -8
  126. data/vendor/rails/actionpack/test/controller/resources_test.rb +215 -36
  127. data/vendor/rails/actionpack/test/controller/routing_test.rb +2 -2
  128. data/vendor/rails/actionpack/test/controller/test_test.rb +16 -0
  129. data/vendor/rails/actionpack/test/controller/url_rewriter_test.rb +66 -10
  130. data/vendor/rails/actionpack/test/controller/verification_test.rb +15 -0
  131. data/vendor/rails/actionpack/test/fixtures/test/hello_world.rxml +2 -1
  132. data/vendor/rails/actionpack/test/template/asset_tag_helper_test.rb +5 -0
  133. data/vendor/rails/actionpack/test/template/compiled_templates_test.rb +29 -17
  134. data/vendor/rails/actionpack/test/template/javascript_helper_test.rb +4 -4
  135. data/vendor/rails/actionpack/test/template/number_helper_test.rb +1 -1
  136. data/vendor/rails/actionpack/test/template/prototype_helper_test.rb +13 -13
  137. data/vendor/rails/actionwebservice/CHANGELOG +14 -0
  138. data/vendor/rails/actionwebservice/Rakefile +2 -2
  139. data/vendor/rails/actionwebservice/lib/action_web_service/version.rb +1 -1
  140. data/vendor/rails/activerecord/CHANGELOG +34 -0
  141. data/vendor/rails/activerecord/Rakefile +1 -1
  142. data/vendor/rails/activerecord/lib/active_record/acts/list.rb +14 -2
  143. data/vendor/rails/activerecord/lib/active_record/acts/tree.rb +7 -0
  144. data/vendor/rails/activerecord/lib/active_record/associations.rb +29 -14
  145. data/vendor/rails/activerecord/lib/active_record/associations/association_collection.rb +5 -1
  146. data/vendor/rails/activerecord/lib/active_record/associations/has_many_association.rb +2 -2
  147. data/vendor/rails/activerecord/lib/active_record/associations/has_many_through_association.rb +10 -0
  148. data/vendor/rails/activerecord/lib/active_record/base.rb +12 -3
  149. data/vendor/rails/activerecord/lib/active_record/calculations.rb +2 -2
  150. data/vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
  151. data/vendor/rails/activerecord/lib/active_record/connection_adapters/oracle_adapter.rb +1 -0
  152. data/vendor/rails/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +2 -2
  153. data/vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb +54 -38
  154. data/vendor/rails/activerecord/lib/active_record/deprecated_finders.rb +3 -3
  155. data/vendor/rails/activerecord/lib/active_record/fixtures.rb +1 -1
  156. data/vendor/rails/activerecord/lib/active_record/timestamp.rb +0 -9
  157. data/vendor/rails/activerecord/lib/active_record/version.rb +1 -1
  158. data/vendor/rails/activerecord/test/associations/eager_test.rb +13 -0
  159. data/vendor/rails/activerecord/test/associations/join_model_test.rb +10 -1
  160. data/vendor/rails/activerecord/test/associations_test.rb +36 -3
  161. data/vendor/rails/activerecord/test/base_test.rb +17 -4
  162. data/vendor/rails/activerecord/test/defaults_test.rb +15 -0
  163. data/vendor/rails/activerecord/test/fixtures/author.rb +1 -0
  164. data/vendor/rails/activerecord/test/fixtures/binaries.yml +437 -0
  165. data/vendor/rails/activerecord/test/fixtures/db_definitions/schema.rb +13 -0
  166. data/vendor/rails/activerecord/test/fixtures/developer.rb +10 -0
  167. data/vendor/rails/activerecord/test/fixtures_test.rb +9 -5
  168. data/vendor/rails/activerecord/test/migration_test.rb +9 -10
  169. data/vendor/rails/activerecord/test/mixin_test.rb +47 -0
  170. data/vendor/rails/activerecord/test/validations_test.rb +2 -2
  171. data/vendor/rails/activesupport/CHANGELOG +16 -0
  172. data/vendor/rails/activesupport/lib/active_support/core_ext/blank.rb +9 -3
  173. data/vendor/rails/activesupport/lib/active_support/core_ext/hash/conversions.rb +48 -3
  174. data/vendor/rails/activesupport/lib/active_support/core_ext/module/introspection.rb +14 -0
  175. data/vendor/rails/activesupport/lib/active_support/dependencies.rb +3 -3
  176. data/vendor/rails/activesupport/lib/active_support/json/encoders/core.rb +5 -3
  177. data/vendor/rails/activesupport/lib/active_support/multibyte/chars.rb +6 -6
  178. data/vendor/rails/activesupport/lib/active_support/version.rb +1 -1
  179. data/vendor/rails/activesupport/test/core_ext/hash_ext_test.rb +37 -0
  180. data/vendor/rails/activesupport/test/core_ext/module_test.rb +8 -0
  181. data/vendor/rails/activesupport/test/dependencies_test.rb +11 -0
  182. data/vendor/rails/activesupport/test/{json.rb → json_test.rb} +15 -5
  183. data/vendor/rails/railties/CHANGELOG +25 -1
  184. data/vendor/rails/railties/README +32 -3
  185. data/vendor/rails/railties/Rakefile +5 -5
  186. data/vendor/rails/railties/environments/boot.rb +12 -18
  187. data/vendor/rails/railties/environments/environment.rb +15 -15
  188. data/vendor/rails/railties/lib/dispatcher.rb +1 -2
  189. data/vendor/rails/railties/lib/initializer.rb +33 -9
  190. data/vendor/rails/railties/lib/rails/version.rb +1 -1
  191. data/vendor/rails/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb +1 -1
  192. data/vendor/rails/railties/lib/rails_generator/generators/components/scaffold_resource/scaffold_resource_generator.rb +1 -0
  193. data/vendor/rails/railties/lib/railties_path.rb +1 -1
  194. data/vendor/rails/railties/lib/tasks/framework.rake +4 -4
  195. data/vendor/rails/railties/lib/tasks/routes.rake +17 -0
  196. data/vendor/rails/release.rb +2 -2
  197. metadata +1877 -1848
@@ -1,39 +1,39 @@
1
- /*
2
-
3
- Correctly handle PNG transparency in Win IE 5.5 & 6.
4
- http://homepage.ntlworld.com/bobosola. Updated 18-Jan-2006.
1
+ /**
2
+ * Correctly handle PNG transparency in Win IE 5.5 & 6.
3
+ * http://homepage.ntlworld.com/bobosola. Updated 18-Jan-2006.
4
+ *
5
+ * Use in <HEAD> with DEFER keyword wrapped in conditional comments:
6
+ *
7
+ * <!--[if lt IE 7]>
8
+ * <script defer type="text/javascript" src="pngfix.js"></script>
9
+ * <![endif]-->
10
+ *
11
+ */
5
12
 
6
- Use in <HEAD> with DEFER keyword wrapped in conditional comments:
7
- <!--[if lt IE 7]>
8
- <script defer type="text/javascript" src="pngfix.js"></script>
9
- <![endif]-->
13
+ var arVersion = navigator.appVersion.split("MSIE"),
14
+ version = parseFloat(arVersion[1]),
15
+ filters = false;
16
+
17
+ try { filters = !!document.body.filters }
18
+ catch (e) {}
10
19
 
11
- */
12
-
13
- var arVersion = navigator.appVersion.split("MSIE")
14
- var version = parseFloat(arVersion[1])
15
-
16
- if ((version >= 5.5) && (document.body.filters))
17
- {
18
- for(var i=0; i<document.images.length; i++)
19
- {
20
- var img = document.images[i]
21
- var imgName = img.src.toUpperCase()
22
- if (imgName.substring(imgName.length-3, imgName.length) == "PNG")
23
- {
24
- var imgID = (img.id) ? "id='" + img.id + "' " : ""
25
- var imgClass = (img.className) ? "class='" + img.className + "' " : ""
26
- var imgTitle = (img.title) ? "title='" + img.title + "' " : "title='" + img.alt + "' "
27
- var imgStyle = "display:inline-block;" + img.style.cssText
28
- if (img.align == "left") imgStyle = "float:left;" + imgStyle
29
- if (img.align == "right") imgStyle = "float:right;" + imgStyle
30
- if (img.parentElement.href) imgStyle = "cursor:hand;" + imgStyle
31
- var strNewHTML = "<span " + imgID + imgClass + imgTitle
32
- + " style=\"" + "width:" + img.width + "px; height:" + img.height + "px;" + imgStyle + ";"
33
- + "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader"
34
- + "(src=\'" + img.src + "\', sizingMethod='scale');\"></span>"
35
- img.outerHTML = strNewHTML
36
- i = i-1
37
- }
38
- }
39
- }
20
+ if (version >= 5.5 && filters) {
21
+ $A(document.images).each(function(img) {
22
+ if (!img.src.toLowerCase().endsWith('png')) return;
23
+
24
+ var span = new Element('span', { id: img.id, className: img.className, title: (img.title || img.alt) }).
25
+ setStyle({
26
+ display: 'inline-block',
27
+ width: img.width + 'px',
28
+ height: img.height + 'px',
29
+ filter: 'progid:DXImageTransform.Microsoft.AplhaImageLoader(src="' + img.src + '", sizingMethod="scale")'
30
+ }).
31
+ setStyle(img.style.cssText);
32
+
33
+ if (img.align == "left") span.setStyle("float: left");
34
+ else if (img.align == "right") span.setStyle("float: right");
35
+ if (img.parentElement.href) span.setStyle("cursor: hand");
36
+
37
+ $(img).replace(span);
38
+ });
39
+ }
@@ -1,38 +1,111 @@
1
- /* Prototype JavaScript framework, version 1.5.0
1
+ /* Prototype JavaScript framework, version 1.6.0
2
2
  * (c) 2005-2007 Sam Stephenson
3
3
  *
4
4
  * Prototype is freely distributable under the terms of an MIT-style license.
5
- * For details, see the Prototype web site: http://prototype.conio.net/
5
+ * For details, see the Prototype web site: http://www.prototypejs.org/
6
6
  *
7
- /*--------------------------------------------------------------------------*/
7
+ *--------------------------------------------------------------------------*/
8
8
 
9
9
  var Prototype = {
10
- Version: '1.5.0',
10
+ Version: '1.6.0',
11
+
12
+ Browser: {
13
+ IE: !!(window.attachEvent && !window.opera),
14
+ Opera: !!window.opera,
15
+ WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
16
+ Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
17
+ MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
18
+ },
19
+
11
20
  BrowserFeatures: {
12
- XPath: !!document.evaluate
21
+ XPath: !!document.evaluate,
22
+ ElementExtensions: !!window.HTMLElement,
23
+ SpecificElementExtensions:
24
+ document.createElement('div').__proto__ &&
25
+ document.createElement('div').__proto__ !==
26
+ document.createElement('form').__proto__
13
27
  },
14
28
 
15
- ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
16
- emptyFunction: function() {},
29
+ ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
30
+ JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
31
+
32
+ emptyFunction: function() { },
17
33
  K: function(x) { return x }
18
- }
34
+ };
35
+
36
+ if (Prototype.Browser.MobileSafari)
37
+ Prototype.BrowserFeatures.SpecificElementExtensions = false;
19
38
 
39
+ if (Prototype.Browser.WebKit)
40
+ Prototype.BrowserFeatures.XPath = false;
41
+
42
+ /* Based on Alex Arnell's inheritance implementation. */
20
43
  var Class = {
21
44
  create: function() {
22
- return function() {
45
+ var parent = null, properties = $A(arguments);
46
+ if (Object.isFunction(properties[0]))
47
+ parent = properties.shift();
48
+
49
+ function klass() {
23
50
  this.initialize.apply(this, arguments);
24
51
  }
52
+
53
+ Object.extend(klass, Class.Methods);
54
+ klass.superclass = parent;
55
+ klass.subclasses = [];
56
+
57
+ if (parent) {
58
+ var subclass = function() { };
59
+ subclass.prototype = parent.prototype;
60
+ klass.prototype = new subclass;
61
+ parent.subclasses.push(klass);
62
+ }
63
+
64
+ for (var i = 0; i < properties.length; i++)
65
+ klass.addMethods(properties[i]);
66
+
67
+ if (!klass.prototype.initialize)
68
+ klass.prototype.initialize = Prototype.emptyFunction;
69
+
70
+ klass.prototype.constructor = klass;
71
+
72
+ return klass;
73
+ }
74
+ };
75
+
76
+ Class.Methods = {
77
+ addMethods: function(source) {
78
+ var ancestor = this.superclass && this.superclass.prototype;
79
+ var properties = Object.keys(source);
80
+
81
+ if (!Object.keys({ toString: true }).length)
82
+ properties.push("toString", "valueOf");
83
+
84
+ for (var i = 0, length = properties.length; i < length; i++) {
85
+ var property = properties[i], value = source[property];
86
+ if (ancestor && Object.isFunction(value) &&
87
+ value.argumentNames().first() == "$super") {
88
+ var method = value, value = Object.extend((function(m) {
89
+ return function() { return ancestor[m].apply(this, arguments) };
90
+ })(property).wrap(method), {
91
+ valueOf: function() { return method },
92
+ toString: function() { return method.toString() }
93
+ });
94
+ }
95
+ this.prototype[property] = value;
96
+ }
97
+
98
+ return this;
25
99
  }
26
- }
100
+ };
27
101
 
28
- var Abstract = new Object();
102
+ var Abstract = { };
29
103
 
30
104
  Object.extend = function(destination, source) {
31
- for (var property in source) {
105
+ for (var property in source)
32
106
  destination[property] = source[property];
33
- }
34
107
  return destination;
35
- }
108
+ };
36
109
 
37
110
  Object.extend(Object, {
38
111
  inspect: function(object) {
@@ -46,6 +119,37 @@ Object.extend(Object, {
46
119
  }
47
120
  },
48
121
 
122
+ toJSON: function(object) {
123
+ var type = typeof object;
124
+ switch (type) {
125
+ case 'undefined':
126
+ case 'function':
127
+ case 'unknown': return;
128
+ case 'boolean': return object.toString();
129
+ }
130
+
131
+ if (object === null) return 'null';
132
+ if (object.toJSON) return object.toJSON();
133
+ if (Object.isElement(object)) return;
134
+
135
+ var results = [];
136
+ for (var property in object) {
137
+ var value = Object.toJSON(object[property]);
138
+ if (value !== undefined)
139
+ results.push(property.toJSON() + ': ' + value);
140
+ }
141
+
142
+ return '{' + results.join(', ') + '}';
143
+ },
144
+
145
+ toQueryString: function(object) {
146
+ return $H(object).toQueryString();
147
+ },
148
+
149
+ toHTML: function(object) {
150
+ return object && object.toHTML ? object.toHTML() : String.interpret(object);
151
+ },
152
+
49
153
  keys: function(object) {
50
154
  var keys = [];
51
155
  for (var property in object)
@@ -61,41 +165,101 @@ Object.extend(Object, {
61
165
  },
62
166
 
63
167
  clone: function(object) {
64
- return Object.extend({}, object);
168
+ return Object.extend({ }, object);
169
+ },
170
+
171
+ isElement: function(object) {
172
+ return object && object.nodeType == 1;
173
+ },
174
+
175
+ isArray: function(object) {
176
+ return object && object.constructor === Array;
177
+ },
178
+
179
+ isHash: function(object) {
180
+ return object instanceof Hash;
181
+ },
182
+
183
+ isFunction: function(object) {
184
+ return typeof object == "function";
185
+ },
186
+
187
+ isString: function(object) {
188
+ return typeof object == "string";
189
+ },
190
+
191
+ isNumber: function(object) {
192
+ return typeof object == "number";
193
+ },
194
+
195
+ isUndefined: function(object) {
196
+ return typeof object == "undefined";
65
197
  }
66
198
  });
67
199
 
68
- Function.prototype.bind = function() {
69
- var __method = this, args = $A(arguments), object = args.shift();
70
- return function() {
71
- return __method.apply(object, args.concat($A(arguments)));
72
- }
73
- }
200
+ Object.extend(Function.prototype, {
201
+ argumentNames: function() {
202
+ var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip");
203
+ return names.length == 1 && !names[0] ? [] : names;
204
+ },
74
205
 
75
- Function.prototype.bindAsEventListener = function(object) {
76
- var __method = this, args = $A(arguments), object = args.shift();
77
- return function(event) {
78
- return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));
79
- }
80
- }
206
+ bind: function() {
207
+ if (arguments.length < 2 && arguments[0] === undefined) return this;
208
+ var __method = this, args = $A(arguments), object = args.shift();
209
+ return function() {
210
+ return __method.apply(object, args.concat($A(arguments)));
211
+ }
212
+ },
81
213
 
82
- Object.extend(Number.prototype, {
83
- toColorPart: function() {
84
- var digits = this.toString(16);
85
- if (this < 16) return '0' + digits;
86
- return digits;
214
+ bindAsEventListener: function() {
215
+ var __method = this, args = $A(arguments), object = args.shift();
216
+ return function(event) {
217
+ return __method.apply(object, [event || window.event].concat(args));
218
+ }
87
219
  },
88
220
 
89
- succ: function() {
90
- return this + 1;
221
+ curry: function() {
222
+ if (!arguments.length) return this;
223
+ var __method = this, args = $A(arguments);
224
+ return function() {
225
+ return __method.apply(this, args.concat($A(arguments)));
226
+ }
91
227
  },
92
228
 
93
- times: function(iterator) {
94
- $R(0, this, true).each(iterator);
95
- return this;
229
+ delay: function() {
230
+ var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
231
+ return window.setTimeout(function() {
232
+ return __method.apply(__method, args);
233
+ }, timeout);
234
+ },
235
+
236
+ wrap: function(wrapper) {
237
+ var __method = this;
238
+ return function() {
239
+ return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
240
+ }
241
+ },
242
+
243
+ methodize: function() {
244
+ if (this._methodized) return this._methodized;
245
+ var __method = this;
246
+ return this._methodized = function() {
247
+ return __method.apply(null, [this].concat($A(arguments)));
248
+ };
96
249
  }
97
250
  });
98
251
 
252
+ Function.prototype.defer = Function.prototype.delay.curry(0.01);
253
+
254
+ Date.prototype.toJSON = function() {
255
+ return '"' + this.getUTCFullYear() + '-' +
256
+ (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
257
+ this.getUTCDate().toPaddedString(2) + 'T' +
258
+ this.getUTCHours().toPaddedString(2) + ':' +
259
+ this.getUTCMinutes().toPaddedString(2) + ':' +
260
+ this.getUTCSeconds().toPaddedString(2) + 'Z"';
261
+ };
262
+
99
263
  var Try = {
100
264
  these: function() {
101
265
  var returnValue;
@@ -105,17 +269,22 @@ var Try = {
105
269
  try {
106
270
  returnValue = lambda();
107
271
  break;
108
- } catch (e) {}
272
+ } catch (e) { }
109
273
  }
110
274
 
111
275
  return returnValue;
112
276
  }
113
- }
277
+ };
278
+
279
+ RegExp.prototype.match = RegExp.prototype.test;
280
+
281
+ RegExp.escape = function(str) {
282
+ return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
283
+ };
114
284
 
115
285
  /*--------------------------------------------------------------------------*/
116
286
 
117
- var PeriodicalExecuter = Class.create();
118
- PeriodicalExecuter.prototype = {
287
+ var PeriodicalExecuter = Class.create({
119
288
  initialize: function(callback, frequency) {
120
289
  this.callback = callback;
121
290
  this.frequency = frequency;
@@ -128,6 +297,10 @@ PeriodicalExecuter.prototype = {
128
297
  this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
129
298
  },
130
299
 
300
+ execute: function() {
301
+ this.callback(this);
302
+ },
303
+
131
304
  stop: function() {
132
305
  if (!this.timer) return;
133
306
  clearInterval(this.timer);
@@ -138,16 +311,26 @@ PeriodicalExecuter.prototype = {
138
311
  if (!this.currentlyExecuting) {
139
312
  try {
140
313
  this.currentlyExecuting = true;
141
- this.callback(this);
314
+ this.execute();
142
315
  } finally {
143
316
  this.currentlyExecuting = false;
144
317
  }
145
318
  }
146
319
  }
147
- }
148
- String.interpret = function(value){
149
- return value == null ? '' : String(value);
150
- }
320
+ });
321
+ Object.extend(String, {
322
+ interpret: function(value) {
323
+ return value == null ? '' : String(value);
324
+ },
325
+ specialChar: {
326
+ '\b': '\\b',
327
+ '\t': '\\t',
328
+ '\n': '\\n',
329
+ '\f': '\\f',
330
+ '\r': '\\r',
331
+ '\\': '\\\\'
332
+ }
333
+ });
151
334
 
152
335
  Object.extend(String.prototype, {
153
336
  gsub: function(pattern, replacement) {
@@ -178,14 +361,14 @@ Object.extend(String.prototype, {
178
361
 
179
362
  scan: function(pattern, iterator) {
180
363
  this.gsub(pattern, iterator);
181
- return this;
364
+ return String(this);
182
365
  },
183
366
 
184
367
  truncate: function(length, truncation) {
185
368
  length = length || 30;
186
369
  truncation = truncation === undefined ? '...' : truncation;
187
370
  return this.length > length ?
188
- this.slice(0, length - truncation.length) + truncation : this;
371
+ this.slice(0, length - truncation.length) + truncation : String(this);
189
372
  },
190
373
 
191
374
  strip: function() {
@@ -213,35 +396,34 @@ Object.extend(String.prototype, {
213
396
  },
214
397
 
215
398
  escapeHTML: function() {
216
- var div = document.createElement('div');
217
- var text = document.createTextNode(this);
218
- div.appendChild(text);
219
- return div.innerHTML;
399
+ var self = arguments.callee;
400
+ self.text.data = this;
401
+ return self.div.innerHTML;
220
402
  },
221
403
 
222
404
  unescapeHTML: function() {
223
- var div = document.createElement('div');
405
+ var div = new Element('div');
224
406
  div.innerHTML = this.stripTags();
225
407
  return div.childNodes[0] ? (div.childNodes.length > 1 ?
226
- $A(div.childNodes).inject('',function(memo,node){ return memo+node.nodeValue }) :
408
+ $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
227
409
  div.childNodes[0].nodeValue) : '';
228
410
  },
229
411
 
230
412
  toQueryParams: function(separator) {
231
413
  var match = this.strip().match(/([^?#]*)(#.*)?$/);
232
- if (!match) return {};
414
+ if (!match) return { };
233
415
 
234
- return match[1].split(separator || '&').inject({}, function(hash, pair) {
416
+ return match[1].split(separator || '&').inject({ }, function(hash, pair) {
235
417
  if ((pair = pair.split('='))[0]) {
236
- var name = decodeURIComponent(pair[0]);
237
- var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
418
+ var key = decodeURIComponent(pair.shift());
419
+ var value = pair.length > 1 ? pair.join('=') : pair[0];
420
+ if (value != undefined) value = decodeURIComponent(value);
238
421
 
239
- if (hash[name] !== undefined) {
240
- if (hash[name].constructor != Array)
241
- hash[name] = [hash[name]];
242
- if (value) hash[name].push(value);
422
+ if (key in hash) {
423
+ if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
424
+ hash[key].push(value);
243
425
  }
244
- else hash[name] = value;
426
+ else hash[key] = value;
245
427
  }
246
428
  return hash;
247
429
  });
@@ -256,6 +438,10 @@ Object.extend(String.prototype, {
256
438
  String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
257
439
  },
258
440
 
441
+ times: function(count) {
442
+ return count < 1 ? '' : new Array(count + 1).join(this);
443
+ },
444
+
259
445
  camelize: function() {
260
446
  var parts = this.split('-'), len = parts.length;
261
447
  if (len == 1) return parts[0];
@@ -270,7 +456,7 @@ Object.extend(String.prototype, {
270
456
  return camelized;
271
457
  },
272
458
 
273
- capitalize: function(){
459
+ capitalize: function() {
274
460
  return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
275
461
  },
276
462
 
@@ -283,52 +469,128 @@ Object.extend(String.prototype, {
283
469
  },
284
470
 
285
471
  inspect: function(useDoubleQuotes) {
286
- var escapedString = this.replace(/\\/g, '\\\\');
287
- if (useDoubleQuotes)
288
- return '"' + escapedString.replace(/"/g, '\\"') + '"';
289
- else
290
- return "'" + escapedString.replace(/'/g, '\\\'') + "'";
472
+ var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
473
+ var character = String.specialChar[match[0]];
474
+ return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
475
+ });
476
+ if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
477
+ return "'" + escapedString.replace(/'/g, '\\\'') + "'";
478
+ },
479
+
480
+ toJSON: function() {
481
+ return this.inspect(true);
482
+ },
483
+
484
+ unfilterJSON: function(filter) {
485
+ return this.sub(filter || Prototype.JSONFilter, '#{1}');
486
+ },
487
+
488
+ isJSON: function() {
489
+ var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
490
+ return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
491
+ },
492
+
493
+ evalJSON: function(sanitize) {
494
+ var json = this.unfilterJSON();
495
+ try {
496
+ if (!sanitize || json.isJSON()) return eval('(' + json + ')');
497
+ } catch (e) { }
498
+ throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
499
+ },
500
+
501
+ include: function(pattern) {
502
+ return this.indexOf(pattern) > -1;
503
+ },
504
+
505
+ startsWith: function(pattern) {
506
+ return this.indexOf(pattern) === 0;
507
+ },
508
+
509
+ endsWith: function(pattern) {
510
+ var d = this.length - pattern.length;
511
+ return d >= 0 && this.lastIndexOf(pattern) === d;
512
+ },
513
+
514
+ empty: function() {
515
+ return this == '';
516
+ },
517
+
518
+ blank: function() {
519
+ return /^\s*$/.test(this);
520
+ },
521
+
522
+ interpolate: function(object, pattern) {
523
+ return new Template(this, pattern).evaluate(object);
524
+ }
525
+ });
526
+
527
+ if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
528
+ escapeHTML: function() {
529
+ return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
530
+ },
531
+ unescapeHTML: function() {
532
+ return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
291
533
  }
292
534
  });
293
535
 
294
536
  String.prototype.gsub.prepareReplacement = function(replacement) {
295
- if (typeof replacement == 'function') return replacement;
537
+ if (Object.isFunction(replacement)) return replacement;
296
538
  var template = new Template(replacement);
297
539
  return function(match) { return template.evaluate(match) };
298
- }
540
+ };
299
541
 
300
542
  String.prototype.parseQuery = String.prototype.toQueryParams;
301
543
 
302
- var Template = Class.create();
303
- Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
304
- Template.prototype = {
544
+ Object.extend(String.prototype.escapeHTML, {
545
+ div: document.createElement('div'),
546
+ text: document.createTextNode('')
547
+ });
548
+
549
+ with (String.prototype.escapeHTML) div.appendChild(text);
550
+
551
+ var Template = Class.create({
305
552
  initialize: function(template, pattern) {
306
553
  this.template = template.toString();
307
- this.pattern = pattern || Template.Pattern;
554
+ this.pattern = pattern || Template.Pattern;
308
555
  },
309
556
 
310
557
  evaluate: function(object) {
558
+ if (Object.isFunction(object.toTemplateReplacements))
559
+ object = object.toTemplateReplacements();
560
+
311
561
  return this.template.gsub(this.pattern, function(match) {
312
- var before = match[1];
562
+ if (object == null) return '';
563
+
564
+ var before = match[1] || '';
313
565
  if (before == '\\') return match[2];
314
- return before + String.interpret(object[match[3]]);
315
- });
566
+
567
+ var ctx = object, expr = match[3];
568
+ var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/, match = pattern.exec(expr);
569
+ if (match == null) return before;
570
+
571
+ while (match != null) {
572
+ var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
573
+ ctx = ctx[comp];
574
+ if (null == ctx || '' == match[3]) break;
575
+ expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
576
+ match = pattern.exec(expr);
577
+ }
578
+
579
+ return before + String.interpret(ctx);
580
+ }.bind(this));
316
581
  }
317
- }
582
+ });
583
+ Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
318
584
 
319
- var $break = new Object();
320
- var $continue = new Object();
585
+ var $break = { };
321
586
 
322
587
  var Enumerable = {
323
- each: function(iterator) {
588
+ each: function(iterator, context) {
324
589
  var index = 0;
590
+ iterator = iterator.bind(context);
325
591
  try {
326
592
  this._each(function(value) {
327
- try {
328
- iterator(value, index++);
329
- } catch (e) {
330
- if (e != $continue) throw e;
331
- }
593
+ iterator(value, index++);
332
594
  });
333
595
  } catch (e) {
334
596
  if (e != $break) throw e;
@@ -336,40 +598,45 @@ var Enumerable = {
336
598
  return this;
337
599
  },
338
600
 
339
- eachSlice: function(number, iterator) {
601
+ eachSlice: function(number, iterator, context) {
602
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
340
603
  var index = -number, slices = [], array = this.toArray();
341
604
  while ((index += number) < array.length)
342
605
  slices.push(array.slice(index, index+number));
343
- return slices.map(iterator);
606
+ return slices.collect(iterator, context);
344
607
  },
345
608
 
346
- all: function(iterator) {
609
+ all: function(iterator, context) {
610
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
347
611
  var result = true;
348
612
  this.each(function(value, index) {
349
- result = result && !!(iterator || Prototype.K)(value, index);
613
+ result = result && !!iterator(value, index);
350
614
  if (!result) throw $break;
351
615
  });
352
616
  return result;
353
617
  },
354
618
 
355
- any: function(iterator) {
619
+ any: function(iterator, context) {
620
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
356
621
  var result = false;
357
622
  this.each(function(value, index) {
358
- if (result = !!(iterator || Prototype.K)(value, index))
623
+ if (result = !!iterator(value, index))
359
624
  throw $break;
360
625
  });
361
626
  return result;
362
627
  },
363
628
 
364
- collect: function(iterator) {
629
+ collect: function(iterator, context) {
630
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
365
631
  var results = [];
366
632
  this.each(function(value, index) {
367
- results.push((iterator || Prototype.K)(value, index));
633
+ results.push(iterator(value, index));
368
634
  });
369
635
  return results;
370
636
  },
371
637
 
372
- detect: function(iterator) {
638
+ detect: function(iterator, context) {
639
+ iterator = iterator.bind(context);
373
640
  var result;
374
641
  this.each(function(value, index) {
375
642
  if (iterator(value, index)) {
@@ -380,7 +647,8 @@ var Enumerable = {
380
647
  return result;
381
648
  },
382
649
 
383
- findAll: function(iterator) {
650
+ findAll: function(iterator, context) {
651
+ iterator = iterator.bind(context);
384
652
  var results = [];
385
653
  this.each(function(value, index) {
386
654
  if (iterator(value, index))
@@ -389,17 +657,24 @@ var Enumerable = {
389
657
  return results;
390
658
  },
391
659
 
392
- grep: function(pattern, iterator) {
660
+ grep: function(filter, iterator, context) {
661
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
393
662
  var results = [];
663
+
664
+ if (Object.isString(filter))
665
+ filter = new RegExp(filter);
666
+
394
667
  this.each(function(value, index) {
395
- var stringValue = value.toString();
396
- if (stringValue.match(pattern))
397
- results.push((iterator || Prototype.K)(value, index));
398
- })
668
+ if (filter.match(value))
669
+ results.push(iterator(value, index));
670
+ });
399
671
  return results;
400
672
  },
401
673
 
402
674
  include: function(object) {
675
+ if (Object.isFunction(this.indexOf))
676
+ if (this.indexOf(object) != -1) return true;
677
+
403
678
  var found = false;
404
679
  this.each(function(value) {
405
680
  if (value == object) {
@@ -418,7 +693,8 @@ var Enumerable = {
418
693
  });
419
694
  },
420
695
 
421
- inject: function(memo, iterator) {
696
+ inject: function(memo, iterator, context) {
697
+ iterator = iterator.bind(context);
422
698
  this.each(function(value, index) {
423
699
  memo = iterator(memo, value, index);
424
700
  });
@@ -432,30 +708,33 @@ var Enumerable = {
432
708
  });
433
709
  },
434
710
 
435
- max: function(iterator) {
711
+ max: function(iterator, context) {
712
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
436
713
  var result;
437
714
  this.each(function(value, index) {
438
- value = (iterator || Prototype.K)(value, index);
715
+ value = iterator(value, index);
439
716
  if (result == undefined || value >= result)
440
717
  result = value;
441
718
  });
442
719
  return result;
443
720
  },
444
721
 
445
- min: function(iterator) {
722
+ min: function(iterator, context) {
723
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
446
724
  var result;
447
725
  this.each(function(value, index) {
448
- value = (iterator || Prototype.K)(value, index);
726
+ value = iterator(value, index);
449
727
  if (result == undefined || value < result)
450
728
  result = value;
451
729
  });
452
730
  return result;
453
731
  },
454
732
 
455
- partition: function(iterator) {
733
+ partition: function(iterator, context) {
734
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
456
735
  var trues = [], falses = [];
457
736
  this.each(function(value, index) {
458
- ((iterator || Prototype.K)(value, index) ?
737
+ (iterator(value, index) ?
459
738
  trues : falses).push(value);
460
739
  });
461
740
  return [trues, falses];
@@ -463,13 +742,14 @@ var Enumerable = {
463
742
 
464
743
  pluck: function(property) {
465
744
  var results = [];
466
- this.each(function(value, index) {
745
+ this.each(function(value) {
467
746
  results.push(value[property]);
468
747
  });
469
748
  return results;
470
749
  },
471
750
 
472
- reject: function(iterator) {
751
+ reject: function(iterator, context) {
752
+ iterator = iterator.bind(context);
473
753
  var results = [];
474
754
  this.each(function(value, index) {
475
755
  if (!iterator(value, index))
@@ -478,7 +758,8 @@ var Enumerable = {
478
758
  return results;
479
759
  },
480
760
 
481
- sortBy: function(iterator) {
761
+ sortBy: function(iterator, context) {
762
+ iterator = iterator.bind(context);
482
763
  return this.map(function(value, index) {
483
764
  return {value: value, criteria: iterator(value, index)};
484
765
  }).sort(function(left, right) {
@@ -493,7 +774,7 @@ var Enumerable = {
493
774
 
494
775
  zip: function() {
495
776
  var iterator = Prototype.K, args = $A(arguments);
496
- if (typeof args.last() == 'function')
777
+ if (Object.isFunction(args.last()))
497
778
  iterator = args.pop();
498
779
 
499
780
  var collections = [this].concat(args).map($A);
@@ -509,31 +790,42 @@ var Enumerable = {
509
790
  inspect: function() {
510
791
  return '#<Enumerable:' + this.toArray().inspect() + '>';
511
792
  }
512
- }
793
+ };
513
794
 
514
795
  Object.extend(Enumerable, {
515
796
  map: Enumerable.collect,
516
797
  find: Enumerable.detect,
517
798
  select: Enumerable.findAll,
799
+ filter: Enumerable.findAll,
518
800
  member: Enumerable.include,
519
- entries: Enumerable.toArray
801
+ entries: Enumerable.toArray,
802
+ every: Enumerable.all,
803
+ some: Enumerable.any
520
804
  });
521
- var $A = Array.from = function(iterable) {
805
+ function $A(iterable) {
522
806
  if (!iterable) return [];
523
- if (iterable.toArray) {
524
- return iterable.toArray();
525
- } else {
526
- var results = [];
527
- for (var i = 0, length = iterable.length; i < length; i++)
528
- results.push(iterable[i]);
807
+ if (iterable.toArray) return iterable.toArray();
808
+ var length = iterable.length, results = new Array(length);
809
+ while (length--) results[length] = iterable[length];
810
+ return results;
811
+ }
812
+
813
+ if (Prototype.Browser.WebKit) {
814
+ function $A(iterable) {
815
+ if (!iterable) return [];
816
+ if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
817
+ iterable.toArray) return iterable.toArray();
818
+ var length = iterable.length, results = new Array(length);
819
+ while (length--) results[length] = iterable[length];
529
820
  return results;
530
821
  }
531
822
  }
532
823
 
824
+ Array.from = $A;
825
+
533
826
  Object.extend(Array.prototype, Enumerable);
534
827
 
535
- if (!Array.prototype._reverse)
536
- Array.prototype._reverse = Array.prototype.reverse;
828
+ if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;
537
829
 
538
830
  Object.extend(Array.prototype, {
539
831
  _each: function(iterator) {
@@ -562,7 +854,7 @@ Object.extend(Array.prototype, {
562
854
 
563
855
  flatten: function() {
564
856
  return this.inject([], function(array, value) {
565
- return array.concat(value && value.constructor == Array ?
857
+ return array.concat(Object.isArray(value) ?
566
858
  value.flatten() : [value]);
567
859
  });
568
860
  },
@@ -574,12 +866,6 @@ Object.extend(Array.prototype, {
574
866
  });
575
867
  },
576
868
 
577
- indexOf: function(object) {
578
- for (var i = 0, length = this.length; i < length; i++)
579
- if (this[i] == object) return i;
580
- return -1;
581
- },
582
-
583
869
  reverse: function(inline) {
584
870
  return (inline !== false ? this : this.toArray())._reverse();
585
871
  },
@@ -588,9 +874,17 @@ Object.extend(Array.prototype, {
588
874
  return this.length > 1 ? this : this[0];
589
875
  },
590
876
 
591
- uniq: function() {
592
- return this.inject([], function(array, value) {
593
- return array.include(value) ? array : array.concat([value]);
877
+ uniq: function(sorted) {
878
+ return this.inject([], function(array, value, index) {
879
+ if (0 == index || (sorted ? array.last() != value : !array.include(value)))
880
+ array.push(value);
881
+ return array;
882
+ });
883
+ },
884
+
885
+ intersect: function(array) {
886
+ return this.uniq().findAll(function(item) {
887
+ return array.detect(function(value) { return item === value });
594
888
  });
595
889
  },
596
890
 
@@ -604,125 +898,208 @@ Object.extend(Array.prototype, {
604
898
 
605
899
  inspect: function() {
606
900
  return '[' + this.map(Object.inspect).join(', ') + ']';
901
+ },
902
+
903
+ toJSON: function() {
904
+ var results = [];
905
+ this.each(function(object) {
906
+ var value = Object.toJSON(object);
907
+ if (value !== undefined) results.push(value);
908
+ });
909
+ return '[' + results.join(', ') + ']';
607
910
  }
608
911
  });
609
912
 
913
+ // use native browser JS 1.6 implementation if available
914
+ if (Object.isFunction(Array.prototype.forEach))
915
+ Array.prototype._each = Array.prototype.forEach;
916
+
917
+ if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {
918
+ i || (i = 0);
919
+ var length = this.length;
920
+ if (i < 0) i = length + i;
921
+ for (; i < length; i++)
922
+ if (this[i] === item) return i;
923
+ return -1;
924
+ };
925
+
926
+ if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {
927
+ i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
928
+ var n = this.slice(0, i).reverse().indexOf(item);
929
+ return (n < 0) ? n : i - n - 1;
930
+ };
931
+
610
932
  Array.prototype.toArray = Array.prototype.clone;
611
933
 
612
- function $w(string){
934
+ function $w(string) {
935
+ if (!Object.isString(string)) return [];
613
936
  string = string.strip();
614
937
  return string ? string.split(/\s+/) : [];
615
938
  }
616
939
 
617
- if(window.opera){
618
- Array.prototype.concat = function(){
940
+ if (Prototype.Browser.Opera){
941
+ Array.prototype.concat = function() {
619
942
  var array = [];
620
- for(var i = 0, length = this.length; i < length; i++) array.push(this[i]);
621
- for(var i = 0, length = arguments.length; i < length; i++) {
622
- if(arguments[i].constructor == Array) {
623
- for(var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
943
+ for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
944
+ for (var i = 0, length = arguments.length; i < length; i++) {
945
+ if (Object.isArray(arguments[i])) {
946
+ for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
624
947
  array.push(arguments[i][j]);
625
948
  } else {
626
949
  array.push(arguments[i]);
627
950
  }
628
951
  }
629
952
  return array;
630
- }
953
+ };
631
954
  }
632
- var Hash = function(obj) {
633
- Object.extend(this, obj || {});
634
- };
955
+ Object.extend(Number.prototype, {
956
+ toColorPart: function() {
957
+ return this.toPaddedString(2, 16);
958
+ },
635
959
 
636
- Object.extend(Hash, {
637
- toQueryString: function(obj) {
638
- var parts = [];
639
-
640
- this.prototype._each.call(obj, function(pair) {
641
- if (!pair.key) return;
642
-
643
- if (pair.value && pair.value.constructor == Array) {
644
- var values = pair.value.compact();
645
- if (values.length < 2) pair.value = values.reduce();
646
- else {
647
- key = encodeURIComponent(pair.key);
648
- values.each(function(value) {
649
- value = value != undefined ? encodeURIComponent(value) : '';
650
- parts.push(key + '=' + encodeURIComponent(value));
651
- });
652
- return;
653
- }
654
- }
655
- if (pair.value == undefined) pair[1] = '';
656
- parts.push(pair.map(encodeURIComponent).join('='));
657
- });
960
+ succ: function() {
961
+ return this + 1;
962
+ },
963
+
964
+ times: function(iterator) {
965
+ $R(0, this, true).each(iterator);
966
+ return this;
967
+ },
658
968
 
659
- return parts.join('&');
969
+ toPaddedString: function(length, radix) {
970
+ var string = this.toString(radix || 10);
971
+ return '0'.times(length - string.length) + string;
972
+ },
973
+
974
+ toJSON: function() {
975
+ return isFinite(this) ? this.toString() : 'null';
660
976
  }
661
977
  });
662
978
 
663
- Object.extend(Hash.prototype, Enumerable);
664
- Object.extend(Hash.prototype, {
665
- _each: function(iterator) {
666
- for (var key in this) {
667
- var value = this[key];
668
- if (value && value == Hash.prototype[key]) continue;
979
+ $w('abs round ceil floor').each(function(method){
980
+ Number.prototype[method] = Math[method].methodize();
981
+ });
982
+ function $H(object) {
983
+ return new Hash(object);
984
+ };
669
985
 
670
- var pair = [key, value];
671
- pair.key = key;
672
- pair.value = value;
673
- iterator(pair);
986
+ var Hash = Class.create(Enumerable, (function() {
987
+ if (function() {
988
+ var i = 0, Test = function(value) { this.key = value };
989
+ Test.prototype.key = 'foo';
990
+ for (var property in new Test('bar')) i++;
991
+ return i > 1;
992
+ }()) {
993
+ function each(iterator) {
994
+ var cache = [];
995
+ for (var key in this._object) {
996
+ var value = this._object[key];
997
+ if (cache.include(key)) continue;
998
+ cache.push(key);
999
+ var pair = [key, value];
1000
+ pair.key = key;
1001
+ pair.value = value;
1002
+ iterator(pair);
1003
+ }
674
1004
  }
675
- },
1005
+ } else {
1006
+ function each(iterator) {
1007
+ for (var key in this._object) {
1008
+ var value = this._object[key], pair = [key, value];
1009
+ pair.key = key;
1010
+ pair.value = value;
1011
+ iterator(pair);
1012
+ }
1013
+ }
1014
+ }
676
1015
 
677
- keys: function() {
678
- return this.pluck('key');
679
- },
1016
+ function toQueryPair(key, value) {
1017
+ if (Object.isUndefined(value)) return key;
1018
+ return key + '=' + encodeURIComponent(String.interpret(value));
1019
+ }
680
1020
 
681
- values: function() {
682
- return this.pluck('value');
683
- },
1021
+ return {
1022
+ initialize: function(object) {
1023
+ this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
1024
+ },
684
1025
 
685
- merge: function(hash) {
686
- return $H(hash).inject(this, function(mergedHash, pair) {
687
- mergedHash[pair.key] = pair.value;
688
- return mergedHash;
689
- });
690
- },
1026
+ _each: each,
691
1027
 
692
- remove: function() {
693
- var result;
694
- for(var i = 0, length = arguments.length; i < length; i++) {
695
- var value = this[arguments[i]];
696
- if (value !== undefined){
697
- if (result === undefined) result = value;
698
- else {
699
- if (result.constructor != Array) result = [result];
700
- result.push(value)
701
- }
702
- }
703
- delete this[arguments[i]];
704
- }
705
- return result;
706
- },
1028
+ set: function(key, value) {
1029
+ return this._object[key] = value;
1030
+ },
707
1031
 
708
- toQueryString: function() {
709
- return Hash.toQueryString(this);
710
- },
1032
+ get: function(key) {
1033
+ return this._object[key];
1034
+ },
711
1035
 
712
- inspect: function() {
713
- return '#<Hash:{' + this.map(function(pair) {
714
- return pair.map(Object.inspect).join(': ');
715
- }).join(', ') + '}>';
1036
+ unset: function(key) {
1037
+ var value = this._object[key];
1038
+ delete this._object[key];
1039
+ return value;
1040
+ },
1041
+
1042
+ toObject: function() {
1043
+ return Object.clone(this._object);
1044
+ },
1045
+
1046
+ keys: function() {
1047
+ return this.pluck('key');
1048
+ },
1049
+
1050
+ values: function() {
1051
+ return this.pluck('value');
1052
+ },
1053
+
1054
+ index: function(value) {
1055
+ var match = this.detect(function(pair) {
1056
+ return pair.value === value;
1057
+ });
1058
+ return match && match.key;
1059
+ },
1060
+
1061
+ merge: function(object) {
1062
+ return this.clone().update(object);
1063
+ },
1064
+
1065
+ update: function(object) {
1066
+ return new Hash(object).inject(this, function(result, pair) {
1067
+ result.set(pair.key, pair.value);
1068
+ return result;
1069
+ });
1070
+ },
1071
+
1072
+ toQueryString: function() {
1073
+ return this.map(function(pair) {
1074
+ var key = encodeURIComponent(pair.key), values = pair.value;
1075
+
1076
+ if (values && typeof values == 'object') {
1077
+ if (Object.isArray(values))
1078
+ return values.map(toQueryPair.curry(key)).join('&');
1079
+ }
1080
+ return toQueryPair(key, values);
1081
+ }).join('&');
1082
+ },
1083
+
1084
+ inspect: function() {
1085
+ return '#<Hash:{' + this.map(function(pair) {
1086
+ return pair.map(Object.inspect).join(': ');
1087
+ }).join(', ') + '}>';
1088
+ },
1089
+
1090
+ toJSON: function() {
1091
+ return Object.toJSON(this.toObject());
1092
+ },
1093
+
1094
+ clone: function() {
1095
+ return new Hash(this);
1096
+ }
716
1097
  }
717
- });
1098
+ })());
718
1099
 
719
- function $H(object) {
720
- if (object && object.constructor == Hash) return object;
721
- return new Hash(object);
722
- };
723
- ObjectRange = Class.create();
724
- Object.extend(ObjectRange.prototype, Enumerable);
725
- Object.extend(ObjectRange.prototype, {
1100
+ Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;
1101
+ Hash.from = $H;
1102
+ var ObjectRange = Class.create(Enumerable, {
726
1103
  initialize: function(start, end, exclusive) {
727
1104
  this.start = start;
728
1105
  this.end = end;
@@ -748,7 +1125,7 @@ Object.extend(ObjectRange.prototype, {
748
1125
 
749
1126
  var $R = function(start, end, exclusive) {
750
1127
  return new ObjectRange(start, end, exclusive);
751
- }
1128
+ };
752
1129
 
753
1130
  var Ajax = {
754
1131
  getTransport: function() {
@@ -760,7 +1137,7 @@ var Ajax = {
760
1137
  },
761
1138
 
762
1139
  activeRequestCount: 0
763
- }
1140
+ };
764
1141
 
765
1142
  Ajax.Responders = {
766
1143
  responders: [],
@@ -780,10 +1157,10 @@ Ajax.Responders = {
780
1157
 
781
1158
  dispatch: function(callback, request, transport, json) {
782
1159
  this.each(function(responder) {
783
- if (typeof responder[callback] == 'function') {
1160
+ if (Object.isFunction(responder[callback])) {
784
1161
  try {
785
1162
  responder[callback].apply(responder, [request, transport, json]);
786
- } catch (e) {}
1163
+ } catch (e) { }
787
1164
  }
788
1165
  });
789
1166
  }
@@ -792,49 +1169,42 @@ Ajax.Responders = {
792
1169
  Object.extend(Ajax.Responders, Enumerable);
793
1170
 
794
1171
  Ajax.Responders.register({
795
- onCreate: function() {
796
- Ajax.activeRequestCount++;
797
- },
798
- onComplete: function() {
799
- Ajax.activeRequestCount--;
800
- }
1172
+ onCreate: function() { Ajax.activeRequestCount++ },
1173
+ onComplete: function() { Ajax.activeRequestCount-- }
801
1174
  });
802
1175
 
803
- Ajax.Base = function() {};
804
- Ajax.Base.prototype = {
805
- setOptions: function(options) {
1176
+ Ajax.Base = Class.create({
1177
+ initialize: function(options) {
806
1178
  this.options = {
807
1179
  method: 'post',
808
1180
  asynchronous: true,
809
1181
  contentType: 'application/x-www-form-urlencoded',
810
1182
  encoding: 'UTF-8',
811
- parameters: ''
812
- }
813
- Object.extend(this.options, options || {});
1183
+ parameters: '',
1184
+ evalJSON: true,
1185
+ evalJS: true
1186
+ };
1187
+ Object.extend(this.options, options || { });
814
1188
 
815
1189
  this.options.method = this.options.method.toLowerCase();
816
- if (typeof this.options.parameters == 'string')
1190
+ if (Object.isString(this.options.parameters))
817
1191
  this.options.parameters = this.options.parameters.toQueryParams();
818
1192
  }
819
- }
820
-
821
- Ajax.Request = Class.create();
822
- Ajax.Request.Events =
823
- ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
1193
+ });
824
1194
 
825
- Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
1195
+ Ajax.Request = Class.create(Ajax.Base, {
826
1196
  _complete: false,
827
1197
 
828
- initialize: function(url, options) {
1198
+ initialize: function($super, url, options) {
1199
+ $super(options);
829
1200
  this.transport = Ajax.getTransport();
830
- this.setOptions(options);
831
1201
  this.request(url);
832
1202
  },
833
1203
 
834
1204
  request: function(url) {
835
1205
  this.url = url;
836
1206
  this.method = this.options.method;
837
- var params = this.options.parameters;
1207
+ var params = Object.clone(this.options.parameters);
838
1208
 
839
1209
  if (!['get', 'post'].include(this.method)) {
840
1210
  // simulate other verbs over post
@@ -842,28 +1212,31 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
842
1212
  this.method = 'post';
843
1213
  }
844
1214
 
845
- params = Hash.toQueryString(params);
846
- if (params && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_='
1215
+ this.parameters = params;
847
1216
 
848
- // when GET, append parameters to URL
849
- if (this.method == 'get' && params)
850
- this.url += (this.url.indexOf('?') > -1 ? '&' : '?') + params;
1217
+ if (params = Object.toQueryString(params)) {
1218
+ // when GET, append parameters to URL
1219
+ if (this.method == 'get')
1220
+ this.url += (this.url.include('?') ? '&' : '?') + params;
1221
+ else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
1222
+ params += '&_=';
1223
+ }
851
1224
 
852
1225
  try {
853
- Ajax.Responders.dispatch('onCreate', this, this.transport);
1226
+ var response = new Ajax.Response(this);
1227
+ if (this.options.onCreate) this.options.onCreate(response);
1228
+ Ajax.Responders.dispatch('onCreate', this, response);
854
1229
 
855
1230
  this.transport.open(this.method.toUpperCase(), this.url,
856
1231
  this.options.asynchronous);
857
1232
 
858
- if (this.options.asynchronous)
859
- setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
1233
+ if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
860
1234
 
861
1235
  this.transport.onreadystatechange = this.onStateChange.bind(this);
862
1236
  this.setRequestHeaders();
863
1237
 
864
- var body = this.method == 'post' ? (this.options.postBody || params) : null;
865
-
866
- this.transport.send(body);
1238
+ this.body = this.method == 'post' ? (this.options.postBody || params) : null;
1239
+ this.transport.send(this.body);
867
1240
 
868
1241
  /* Force Firefox to handle ready state 4 for synchronous requests */
869
1242
  if (!this.options.asynchronous && this.transport.overrideMimeType)
@@ -905,7 +1278,7 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
905
1278
  if (typeof this.options.requestHeaders == 'object') {
906
1279
  var extras = this.options.requestHeaders;
907
1280
 
908
- if (typeof extras.push == 'function')
1281
+ if (Object.isFunction(extras.push))
909
1282
  for (var i = 0, length = extras.length; i < length; i += 2)
910
1283
  headers[extras[i]] = extras[i+1];
911
1284
  else
@@ -917,32 +1290,39 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
917
1290
  },
918
1291
 
919
1292
  success: function() {
920
- return !this.transport.status
921
- || (this.transport.status >= 200 && this.transport.status < 300);
1293
+ var status = this.getStatus();
1294
+ return !status || (status >= 200 && status < 300);
1295
+ },
1296
+
1297
+ getStatus: function() {
1298
+ try {
1299
+ return this.transport.status || 0;
1300
+ } catch (e) { return 0 }
922
1301
  },
923
1302
 
924
1303
  respondToReadyState: function(readyState) {
925
- var state = Ajax.Request.Events[readyState];
926
- var transport = this.transport, json = this.evalJSON();
1304
+ var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
927
1305
 
928
1306
  if (state == 'Complete') {
929
1307
  try {
930
1308
  this._complete = true;
931
- (this.options['on' + this.transport.status]
1309
+ (this.options['on' + response.status]
932
1310
  || this.options['on' + (this.success() ? 'Success' : 'Failure')]
933
- || Prototype.emptyFunction)(transport, json);
1311
+ || Prototype.emptyFunction)(response, response.headerJSON);
934
1312
  } catch (e) {
935
1313
  this.dispatchException(e);
936
1314
  }
937
1315
 
938
- if ((this.getHeader('Content-type') || 'text/javascript').strip().
939
- match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
940
- this.evalResponse();
1316
+ var contentType = response.getHeader('Content-type');
1317
+ if (this.options.evalJS == 'force'
1318
+ || (this.options.evalJS && contentType
1319
+ && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
1320
+ this.evalResponse();
941
1321
  }
942
1322
 
943
1323
  try {
944
- (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
945
- Ajax.Responders.dispatch('on' + state, this, transport, json);
1324
+ (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
1325
+ Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
946
1326
  } catch (e) {
947
1327
  this.dispatchException(e);
948
1328
  }
@@ -959,16 +1339,9 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
959
1339
  } catch (e) { return null }
960
1340
  },
961
1341
 
962
- evalJSON: function() {
963
- try {
964
- var json = this.getHeader('X-JSON');
965
- return json ? eval('(' + json + ')') : null;
966
- } catch (e) { return null }
967
- },
968
-
969
1342
  evalResponse: function() {
970
1343
  try {
971
- return eval(this.transport.responseText);
1344
+ return eval((this.transport.responseText || '').unfilterJSON());
972
1345
  } catch (e) {
973
1346
  this.dispatchException(e);
974
1347
  }
@@ -980,57 +1353,129 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
980
1353
  }
981
1354
  });
982
1355
 
983
- Ajax.Updater = Class.create();
1356
+ Ajax.Request.Events =
1357
+ ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
1358
+
1359
+ Ajax.Response = Class.create({
1360
+ initialize: function(request){
1361
+ this.request = request;
1362
+ var transport = this.transport = request.transport,
1363
+ readyState = this.readyState = transport.readyState;
1364
+
1365
+ if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
1366
+ this.status = this.getStatus();
1367
+ this.statusText = this.getStatusText();
1368
+ this.responseText = String.interpret(transport.responseText);
1369
+ this.headerJSON = this._getHeaderJSON();
1370
+ }
1371
+
1372
+ if(readyState == 4) {
1373
+ var xml = transport.responseXML;
1374
+ this.responseXML = xml === undefined ? null : xml;
1375
+ this.responseJSON = this._getResponseJSON();
1376
+ }
1377
+ },
1378
+
1379
+ status: 0,
1380
+ statusText: '',
1381
+
1382
+ getStatus: Ajax.Request.prototype.getStatus,
1383
+
1384
+ getStatusText: function() {
1385
+ try {
1386
+ return this.transport.statusText || '';
1387
+ } catch (e) { return '' }
1388
+ },
1389
+
1390
+ getHeader: Ajax.Request.prototype.getHeader,
1391
+
1392
+ getAllHeaders: function() {
1393
+ try {
1394
+ return this.getAllResponseHeaders();
1395
+ } catch (e) { return null }
1396
+ },
1397
+
1398
+ getResponseHeader: function(name) {
1399
+ return this.transport.getResponseHeader(name);
1400
+ },
1401
+
1402
+ getAllResponseHeaders: function() {
1403
+ return this.transport.getAllResponseHeaders();
1404
+ },
1405
+
1406
+ _getHeaderJSON: function() {
1407
+ var json = this.getHeader('X-JSON');
1408
+ if (!json) return null;
1409
+ json = decodeURIComponent(escape(json));
1410
+ try {
1411
+ return json.evalJSON(this.request.options.sanitizeJSON);
1412
+ } catch (e) {
1413
+ this.request.dispatchException(e);
1414
+ }
1415
+ },
1416
+
1417
+ _getResponseJSON: function() {
1418
+ var options = this.request.options;
1419
+ if (!options.evalJSON || (options.evalJSON != 'force' &&
1420
+ !(this.getHeader('Content-type') || '').include('application/json')))
1421
+ return null;
1422
+ try {
1423
+ return this.transport.responseText.evalJSON(options.sanitizeJSON);
1424
+ } catch (e) {
1425
+ this.request.dispatchException(e);
1426
+ }
1427
+ }
1428
+ });
984
1429
 
985
- Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
986
- initialize: function(container, url, options) {
1430
+ Ajax.Updater = Class.create(Ajax.Request, {
1431
+ initialize: function($super, container, url, options) {
987
1432
  this.container = {
988
1433
  success: (container.success || container),
989
1434
  failure: (container.failure || (container.success ? null : container))
990
- }
991
-
992
- this.transport = Ajax.getTransport();
993
- this.setOptions(options);
1435
+ };
994
1436
 
995
- var onComplete = this.options.onComplete || Prototype.emptyFunction;
996
- this.options.onComplete = (function(transport, param) {
997
- this.updateContent();
998
- onComplete(transport, param);
1437
+ options = options || { };
1438
+ var onComplete = options.onComplete;
1439
+ options.onComplete = (function(response, param) {
1440
+ this.updateContent(response.responseText);
1441
+ if (Object.isFunction(onComplete)) onComplete(response, param);
999
1442
  }).bind(this);
1000
1443
 
1001
- this.request(url);
1444
+ $super(url, options);
1002
1445
  },
1003
1446
 
1004
- updateContent: function() {
1005
- var receiver = this.container[this.success() ? 'success' : 'failure'];
1006
- var response = this.transport.responseText;
1447
+ updateContent: function(responseText) {
1448
+ var receiver = this.container[this.success() ? 'success' : 'failure'],
1449
+ options = this.options;
1007
1450
 
1008
- if (!this.options.evalScripts) response = response.stripScripts();
1451
+ if (!options.evalScripts) responseText = responseText.stripScripts();
1009
1452
 
1010
1453
  if (receiver = $(receiver)) {
1011
- if (this.options.insertion)
1012
- new this.options.insertion(receiver, response);
1013
- else
1014
- receiver.update(response);
1454
+ if (options.insertion) {
1455
+ if (Object.isString(options.insertion)) {
1456
+ var insertion = { }; insertion[options.insertion] = responseText;
1457
+ receiver.insert(insertion);
1458
+ }
1459
+ else options.insertion(receiver, responseText);
1460
+ }
1461
+ else receiver.update(responseText);
1015
1462
  }
1016
1463
 
1017
1464
  if (this.success()) {
1018
- if (this.onComplete)
1019
- setTimeout(this.onComplete.bind(this), 10);
1465
+ if (this.onComplete) this.onComplete.bind(this).defer();
1020
1466
  }
1021
1467
  }
1022
1468
  });
1023
1469
 
1024
- Ajax.PeriodicalUpdater = Class.create();
1025
- Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
1026
- initialize: function(container, url, options) {
1027
- this.setOptions(options);
1470
+ Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
1471
+ initialize: function($super, container, url, options) {
1472
+ $super(options);
1028
1473
  this.onComplete = this.options.onComplete;
1029
1474
 
1030
1475
  this.frequency = (this.options.frequency || 2);
1031
1476
  this.decay = (this.options.decay || 1);
1032
1477
 
1033
- this.updater = {};
1478
+ this.updater = { };
1034
1479
  this.container = container;
1035
1480
  this.url = url;
1036
1481
 
@@ -1048,15 +1493,14 @@ Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
1048
1493
  (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
1049
1494
  },
1050
1495
 
1051
- updateComplete: function(request) {
1496
+ updateComplete: function(response) {
1052
1497
  if (this.options.decay) {
1053
- this.decay = (request.responseText == this.lastText ?
1498
+ this.decay = (response.responseText == this.lastText ?
1054
1499
  this.decay * this.options.decay : 1);
1055
1500
 
1056
- this.lastText = request.responseText;
1501
+ this.lastText = response.responseText;
1057
1502
  }
1058
- this.timer = setTimeout(this.onTimerEvent.bind(this),
1059
- this.decay * this.frequency * 1000);
1503
+ this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
1060
1504
  },
1061
1505
 
1062
1506
  onTimerEvent: function() {
@@ -1069,7 +1513,7 @@ function $(element) {
1069
1513
  elements.push($(arguments[i]));
1070
1514
  return elements;
1071
1515
  }
1072
- if (typeof element == 'string')
1516
+ if (Object.isString(element))
1073
1517
  element = document.getElementById(element);
1074
1518
  return Element.extend(element);
1075
1519
  }
@@ -1080,63 +1524,51 @@ if (Prototype.BrowserFeatures.XPath) {
1080
1524
  var query = document.evaluate(expression, $(parentElement) || document,
1081
1525
  null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
1082
1526
  for (var i = 0, length = query.snapshotLength; i < length; i++)
1083
- results.push(query.snapshotItem(i));
1527
+ results.push(Element.extend(query.snapshotItem(i)));
1084
1528
  return results;
1085
1529
  };
1086
1530
  }
1087
1531
 
1088
- document.getElementsByClassName = function(className, parentElement) {
1089
- if (Prototype.BrowserFeatures.XPath) {
1090
- var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
1091
- return document._getElementsByXPath(q, parentElement);
1092
- } else {
1093
- var children = ($(parentElement) || document.body).getElementsByTagName('*');
1094
- var elements = [], child;
1095
- for (var i = 0, length = children.length; i < length; i++) {
1096
- child = children[i];
1097
- if (Element.hasClassName(child, className))
1098
- elements.push(Element.extend(child));
1099
- }
1100
- return elements;
1101
- }
1102
- };
1103
-
1104
1532
  /*--------------------------------------------------------------------------*/
1105
1533
 
1106
- if (!window.Element)
1107
- var Element = new Object();
1108
-
1109
- Element.extend = function(element) {
1110
- if (!element || _nativeExtensions || element.nodeType == 3) return element;
1111
-
1112
- if (!element._extended && element.tagName && element != window) {
1113
- var methods = Object.clone(Element.Methods), cache = Element.extend.cache;
1114
-
1115
- if (element.tagName == 'FORM')
1116
- Object.extend(methods, Form.Methods);
1117
- if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
1118
- Object.extend(methods, Form.Element.Methods);
1119
-
1120
- Object.extend(methods, Element.Methods.Simulated);
1534
+ if (!window.Node) var Node = { };
1535
+
1536
+ if (!Node.ELEMENT_NODE) {
1537
+ // DOM level 2 ECMAScript Language Binding
1538
+ Object.extend(Node, {
1539
+ ELEMENT_NODE: 1,
1540
+ ATTRIBUTE_NODE: 2,
1541
+ TEXT_NODE: 3,
1542
+ CDATA_SECTION_NODE: 4,
1543
+ ENTITY_REFERENCE_NODE: 5,
1544
+ ENTITY_NODE: 6,
1545
+ PROCESSING_INSTRUCTION_NODE: 7,
1546
+ COMMENT_NODE: 8,
1547
+ DOCUMENT_NODE: 9,
1548
+ DOCUMENT_TYPE_NODE: 10,
1549
+ DOCUMENT_FRAGMENT_NODE: 11,
1550
+ NOTATION_NODE: 12
1551
+ });
1552
+ }
1121
1553
 
1122
- for (var property in methods) {
1123
- var value = methods[property];
1124
- if (typeof value == 'function' && !(property in element))
1125
- element[property] = cache.findOrStore(value);
1554
+ (function() {
1555
+ var element = this.Element;
1556
+ this.Element = function(tagName, attributes) {
1557
+ attributes = attributes || { };
1558
+ tagName = tagName.toLowerCase();
1559
+ var cache = Element.cache;
1560
+ if (Prototype.Browser.IE && attributes.name) {
1561
+ tagName = '<' + tagName + ' name="' + attributes.name + '">';
1562
+ delete attributes.name;
1563
+ return Element.writeAttribute(document.createElement(tagName), attributes);
1126
1564
  }
1127
- }
1128
-
1129
- element._extended = true;
1130
- return element;
1131
- };
1565
+ if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
1566
+ return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
1567
+ };
1568
+ Object.extend(this.Element, element || { });
1569
+ }).call(window);
1132
1570
 
1133
- Element.extend.cache = {
1134
- findOrStore: function(value) {
1135
- return this[value] = this[value] || function() {
1136
- return value.apply(null, [this].concat($A(arguments)));
1137
- }
1138
- }
1139
- };
1571
+ Element.cache = { };
1140
1572
 
1141
1573
  Element.Methods = {
1142
1574
  visible: function(element) {
@@ -1165,28 +1597,74 @@ Element.Methods = {
1165
1597
  return element;
1166
1598
  },
1167
1599
 
1168
- update: function(element, html) {
1169
- html = typeof html == 'undefined' ? '' : html.toString();
1170
- $(element).innerHTML = html.stripScripts();
1171
- setTimeout(function() {html.evalScripts()}, 10);
1600
+ update: function(element, content) {
1601
+ element = $(element);
1602
+ if (content && content.toElement) content = content.toElement();
1603
+ if (Object.isElement(content)) return element.update().insert(content);
1604
+ content = Object.toHTML(content);
1605
+ element.innerHTML = content.stripScripts();
1606
+ content.evalScripts.bind(content).defer();
1172
1607
  return element;
1173
1608
  },
1174
1609
 
1175
- replace: function(element, html) {
1610
+ replace: function(element, content) {
1176
1611
  element = $(element);
1177
- html = typeof html == 'undefined' ? '' : html.toString();
1178
- if (element.outerHTML) {
1179
- element.outerHTML = html.stripScripts();
1180
- } else {
1612
+ if (content && content.toElement) content = content.toElement();
1613
+ else if (!Object.isElement(content)) {
1614
+ content = Object.toHTML(content);
1181
1615
  var range = element.ownerDocument.createRange();
1182
- range.selectNodeContents(element);
1183
- element.parentNode.replaceChild(
1184
- range.createContextualFragment(html.stripScripts()), element);
1616
+ range.selectNode(element);
1617
+ content.evalScripts.bind(content).defer();
1618
+ content = range.createContextualFragment(content.stripScripts());
1619
+ }
1620
+ element.parentNode.replaceChild(content, element);
1621
+ return element;
1622
+ },
1623
+
1624
+ insert: function(element, insertions) {
1625
+ element = $(element);
1626
+
1627
+ if (Object.isString(insertions) || Object.isNumber(insertions) ||
1628
+ Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
1629
+ insertions = {bottom:insertions};
1630
+
1631
+ var content, t, range;
1632
+
1633
+ for (position in insertions) {
1634
+ content = insertions[position];
1635
+ position = position.toLowerCase();
1636
+ t = Element._insertionTranslations[position];
1637
+
1638
+ if (content && content.toElement) content = content.toElement();
1639
+ if (Object.isElement(content)) {
1640
+ t.insert(element, content);
1641
+ continue;
1642
+ }
1643
+
1644
+ content = Object.toHTML(content);
1645
+
1646
+ range = element.ownerDocument.createRange();
1647
+ t.initializeRange(element, range);
1648
+ t.insert(element, range.createContextualFragment(content.stripScripts()));
1649
+
1650
+ content.evalScripts.bind(content).defer();
1185
1651
  }
1186
- setTimeout(function() {html.evalScripts()}, 10);
1652
+
1187
1653
  return element;
1188
1654
  },
1189
1655
 
1656
+ wrap: function(element, wrapper, attributes) {
1657
+ element = $(element);
1658
+ if (Object.isElement(wrapper))
1659
+ $(wrapper).writeAttribute(attributes || { });
1660
+ else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
1661
+ else wrapper = new Element('div', wrapper);
1662
+ if (element.parentNode)
1663
+ element.parentNode.replaceChild(wrapper, element);
1664
+ wrapper.appendChild(element);
1665
+ return wrapper;
1666
+ },
1667
+
1190
1668
  inspect: function(element) {
1191
1669
  element = $(element);
1192
1670
  var result = '<' + element.tagName.toLowerCase();
@@ -1212,7 +1690,13 @@ Element.Methods = {
1212
1690
  },
1213
1691
 
1214
1692
  descendants: function(element) {
1215
- return $A($(element).getElementsByTagName('*'));
1693
+ return $A($(element).getElementsByTagName('*')).each(Element.extend);
1694
+ },
1695
+
1696
+ firstDescendant: function(element) {
1697
+ element = $(element).firstChild;
1698
+ while (element && element.nodeType != 1) element = element.nextSibling;
1699
+ return $(element);
1216
1700
  },
1217
1701
 
1218
1702
  immediateDescendants: function(element) {
@@ -1236,48 +1720,95 @@ Element.Methods = {
1236
1720
  },
1237
1721
 
1238
1722
  match: function(element, selector) {
1239
- if (typeof selector == 'string')
1723
+ if (Object.isString(selector))
1240
1724
  selector = new Selector(selector);
1241
1725
  return selector.match($(element));
1242
1726
  },
1243
1727
 
1244
1728
  up: function(element, expression, index) {
1245
- return Selector.findElement($(element).ancestors(), expression, index);
1729
+ element = $(element);
1730
+ if (arguments.length == 1) return $(element.parentNode);
1731
+ var ancestors = element.ancestors();
1732
+ return expression ? Selector.findElement(ancestors, expression, index) :
1733
+ ancestors[index || 0];
1246
1734
  },
1247
1735
 
1248
1736
  down: function(element, expression, index) {
1249
- return Selector.findElement($(element).descendants(), expression, index);
1737
+ element = $(element);
1738
+ if (arguments.length == 1) return element.firstDescendant();
1739
+ var descendants = element.descendants();
1740
+ return expression ? Selector.findElement(descendants, expression, index) :
1741
+ descendants[index || 0];
1250
1742
  },
1251
1743
 
1252
1744
  previous: function(element, expression, index) {
1253
- return Selector.findElement($(element).previousSiblings(), expression, index);
1745
+ element = $(element);
1746
+ if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
1747
+ var previousSiblings = element.previousSiblings();
1748
+ return expression ? Selector.findElement(previousSiblings, expression, index) :
1749
+ previousSiblings[index || 0];
1254
1750
  },
1255
1751
 
1256
1752
  next: function(element, expression, index) {
1257
- return Selector.findElement($(element).nextSiblings(), expression, index);
1753
+ element = $(element);
1754
+ if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
1755
+ var nextSiblings = element.nextSiblings();
1756
+ return expression ? Selector.findElement(nextSiblings, expression, index) :
1757
+ nextSiblings[index || 0];
1258
1758
  },
1259
1759
 
1260
- getElementsBySelector: function() {
1760
+ select: function() {
1261
1761
  var args = $A(arguments), element = $(args.shift());
1262
1762
  return Selector.findChildElements(element, args);
1263
1763
  },
1264
1764
 
1265
- getElementsByClassName: function(element, className) {
1266
- return document.getElementsByClassName(className, element);
1765
+ adjacent: function() {
1766
+ var args = $A(arguments), element = $(args.shift());
1767
+ return Selector.findChildElements(element.parentNode, args).without(element);
1768
+ },
1769
+
1770
+ identify: function(element) {
1771
+ element = $(element);
1772
+ var id = element.readAttribute('id'), self = arguments.callee;
1773
+ if (id) return id;
1774
+ do { id = 'anonymous_element_' + self.counter++ } while ($(id));
1775
+ element.writeAttribute('id', id);
1776
+ return id;
1267
1777
  },
1268
1778
 
1269
1779
  readAttribute: function(element, name) {
1270
1780
  element = $(element);
1271
- if (document.all && !window.opera) {
1272
- var t = Element._attributeTranslations;
1781
+ if (Prototype.Browser.IE) {
1782
+ var t = Element._attributeTranslations.read;
1273
1783
  if (t.values[name]) return t.values[name](element, name);
1274
- if (t.names[name]) name = t.names[name];
1275
- var attribute = element.attributes[name];
1276
- if(attribute) return attribute.nodeValue;
1784
+ if (t.names[name]) name = t.names[name];
1785
+ if (name.include(':')) {
1786
+ return (!element.attributes || !element.attributes[name]) ? null :
1787
+ element.attributes[name].value;
1788
+ }
1277
1789
  }
1278
1790
  return element.getAttribute(name);
1279
1791
  },
1280
1792
 
1793
+ writeAttribute: function(element, name, value) {
1794
+ element = $(element);
1795
+ var attributes = { }, t = Element._attributeTranslations.write;
1796
+
1797
+ if (typeof name == 'object') attributes = name;
1798
+ else attributes[name] = value === undefined ? true : value;
1799
+
1800
+ for (var attr in attributes) {
1801
+ var name = t.names[attr] || attr, value = attributes[attr];
1802
+ if (t.values[attr]) name = t.values[attr](element, value);
1803
+ if (value === false || value === null)
1804
+ element.removeAttribute(name);
1805
+ else if (value === true)
1806
+ element.setAttribute(name, name);
1807
+ else element.setAttribute(name, value);
1808
+ }
1809
+ return element;
1810
+ },
1811
+
1281
1812
  getHeight: function(element) {
1282
1813
  return $(element).getDimensions().height;
1283
1814
  },
@@ -1293,39 +1824,28 @@ Element.Methods = {
1293
1824
  hasClassName: function(element, className) {
1294
1825
  if (!(element = $(element))) return;
1295
1826
  var elementClassName = element.className;
1296
- if (elementClassName.length == 0) return false;
1297
- if (elementClassName == className ||
1298
- elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
1299
- return true;
1300
- return false;
1827
+ return (elementClassName.length > 0 && (elementClassName == className ||
1828
+ new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
1301
1829
  },
1302
1830
 
1303
1831
  addClassName: function(element, className) {
1304
1832
  if (!(element = $(element))) return;
1305
- Element.classNames(element).add(className);
1833
+ if (!element.hasClassName(className))
1834
+ element.className += (element.className ? ' ' : '') + className;
1306
1835
  return element;
1307
1836
  },
1308
1837
 
1309
1838
  removeClassName: function(element, className) {
1310
1839
  if (!(element = $(element))) return;
1311
- Element.classNames(element).remove(className);
1840
+ element.className = element.className.replace(
1841
+ new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
1312
1842
  return element;
1313
1843
  },
1314
1844
 
1315
1845
  toggleClassName: function(element, className) {
1316
1846
  if (!(element = $(element))) return;
1317
- Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
1318
- return element;
1319
- },
1320
-
1321
- observe: function() {
1322
- Event.observe.apply(Event, arguments);
1323
- return $A(arguments).first();
1324
- },
1325
-
1326
- stopObserving: function() {
1327
- Event.stopObserving.apply(Event, arguments);
1328
- return $A(arguments).first();
1847
+ return element[element.hasClassName(className) ?
1848
+ 'removeClassName' : 'addClassName'](className);
1329
1849
  },
1330
1850
 
1331
1851
  // removes whitespace-only text node children
@@ -1342,11 +1862,25 @@ Element.Methods = {
1342
1862
  },
1343
1863
 
1344
1864
  empty: function(element) {
1345
- return $(element).innerHTML.match(/^\s*$/);
1865
+ return $(element).innerHTML.blank();
1346
1866
  },
1347
1867
 
1348
1868
  descendantOf: function(element, ancestor) {
1349
1869
  element = $(element), ancestor = $(ancestor);
1870
+
1871
+ if (element.compareDocumentPosition)
1872
+ return (element.compareDocumentPosition(ancestor) & 8) === 8;
1873
+
1874
+ if (element.sourceIndex && !Prototype.Browser.Opera) {
1875
+ var e = element.sourceIndex, a = ancestor.sourceIndex,
1876
+ nextAncestor = ancestor.nextSibling;
1877
+ if (!nextAncestor) {
1878
+ do { ancestor = ancestor.parentNode; }
1879
+ while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);
1880
+ }
1881
+ if (nextAncestor) return (e > a && e < nextAncestor.sourceIndex);
1882
+ }
1883
+
1350
1884
  while (element = element.parentNode)
1351
1885
  if (element == ancestor) return true;
1352
1886
  return false;
@@ -1354,62 +1888,49 @@ Element.Methods = {
1354
1888
 
1355
1889
  scrollTo: function(element) {
1356
1890
  element = $(element);
1357
- var pos = Position.cumulativeOffset(element);
1891
+ var pos = element.cumulativeOffset();
1358
1892
  window.scrollTo(pos[0], pos[1]);
1359
1893
  return element;
1360
1894
  },
1361
1895
 
1362
1896
  getStyle: function(element, style) {
1363
1897
  element = $(element);
1364
- if (['float','cssFloat'].include(style))
1365
- style = (typeof element.style.styleFloat != 'undefined' ? 'styleFloat' : 'cssFloat');
1366
- style = style.camelize();
1898
+ style = style == 'float' ? 'cssFloat' : style.camelize();
1367
1899
  var value = element.style[style];
1368
1900
  if (!value) {
1369
- if (document.defaultView && document.defaultView.getComputedStyle) {
1370
- var css = document.defaultView.getComputedStyle(element, null);
1371
- value = css ? css[style] : null;
1372
- } else if (element.currentStyle) {
1373
- value = element.currentStyle[style];
1374
- }
1901
+ var css = document.defaultView.getComputedStyle(element, null);
1902
+ value = css ? css[style] : null;
1375
1903
  }
1904
+ if (style == 'opacity') return value ? parseFloat(value) : 1.0;
1905
+ return value == 'auto' ? null : value;
1906
+ },
1376
1907
 
1377
- if((value == 'auto') && ['width','height'].include(style) && (element.getStyle('display') != 'none'))
1378
- value = element['offset'+style.capitalize()] + 'px';
1908
+ getOpacity: function(element) {
1909
+ return $(element).getStyle('opacity');
1910
+ },
1379
1911
 
1380
- if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
1381
- if (Element.getStyle(element, 'position') == 'static') value = 'auto';
1382
- if(style == 'opacity') {
1383
- if(value) return parseFloat(value);
1384
- if(value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
1385
- if(value[1]) return parseFloat(value[1]) / 100;
1386
- return 1.0;
1912
+ setStyle: function(element, styles) {
1913
+ element = $(element);
1914
+ var elementStyle = element.style, match;
1915
+ if (Object.isString(styles)) {
1916
+ element.style.cssText += ';' + styles;
1917
+ return styles.include('opacity') ?
1918
+ element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
1387
1919
  }
1388
- return value == 'auto' ? null : value;
1920
+ for (var property in styles)
1921
+ if (property == 'opacity') element.setOpacity(styles[property]);
1922
+ else
1923
+ elementStyle[(property == 'float' || property == 'cssFloat') ?
1924
+ (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
1925
+ property] = styles[property];
1926
+
1927
+ return element;
1389
1928
  },
1390
1929
 
1391
- setStyle: function(element, style) {
1930
+ setOpacity: function(element, value) {
1392
1931
  element = $(element);
1393
- for (var name in style) {
1394
- var value = style[name];
1395
- if(name == 'opacity') {
1396
- if (value == 1) {
1397
- value = (/Gecko/.test(navigator.userAgent) &&
1398
- !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : 1.0;
1399
- if(/MSIE/.test(navigator.userAgent) && !window.opera)
1400
- element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
1401
- } else if(value == '') {
1402
- if(/MSIE/.test(navigator.userAgent) && !window.opera)
1403
- element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
1404
- } else {
1405
- if(value < 0.00001) value = 0;
1406
- if(/MSIE/.test(navigator.userAgent) && !window.opera)
1407
- element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') +
1408
- 'alpha(opacity='+value*100+')';
1409
- }
1410
- } else if(['float','cssFloat'].include(name)) name = (typeof element.style.styleFloat != 'undefined') ? 'styleFloat' : 'cssFloat';
1411
- element.style[name.camelize()] = value;
1412
- }
1932
+ element.style.opacity = (value == 1 || value === '') ? '' :
1933
+ (value < 0.00001) ? 0 : value;
1413
1934
  return element;
1414
1935
  },
1415
1936
 
@@ -1468,8 +1989,8 @@ Element.Methods = {
1468
1989
  makeClipping: function(element) {
1469
1990
  element = $(element);
1470
1991
  if (element._overflow) return element;
1471
- element._overflow = element.style.overflow || 'auto';
1472
- if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
1992
+ element._overflow = Element.getStyle(element, 'overflow') || 'auto';
1993
+ if (element._overflow !== 'hidden')
1473
1994
  element.style.overflow = 'hidden';
1474
1995
  return element;
1475
1996
  },
@@ -1480,390 +2001,1338 @@ Element.Methods = {
1480
2001
  element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
1481
2002
  element._overflow = null;
1482
2003
  return element;
1483
- }
1484
- };
1485
-
1486
- Object.extend(Element.Methods, {childOf: Element.Methods.descendantOf});
1487
-
1488
- Element._attributeTranslations = {};
1489
-
1490
- Element._attributeTranslations.names = {
1491
- colspan: "colSpan",
1492
- rowspan: "rowSpan",
1493
- valign: "vAlign",
1494
- datetime: "dateTime",
1495
- accesskey: "accessKey",
1496
- tabindex: "tabIndex",
1497
- enctype: "encType",
1498
- maxlength: "maxLength",
1499
- readonly: "readOnly",
1500
- longdesc: "longDesc"
1501
- };
1502
-
1503
- Element._attributeTranslations.values = {
1504
- _getAttr: function(element, attribute) {
1505
- return element.getAttribute(attribute, 2);
1506
2004
  },
1507
2005
 
1508
- _flag: function(element, attribute) {
1509
- return $(element).hasAttribute(attribute) ? attribute : null;
2006
+ cumulativeOffset: function(element) {
2007
+ var valueT = 0, valueL = 0;
2008
+ do {
2009
+ valueT += element.offsetTop || 0;
2010
+ valueL += element.offsetLeft || 0;
2011
+ element = element.offsetParent;
2012
+ } while (element);
2013
+ return Element._returnOffset(valueL, valueT);
1510
2014
  },
1511
2015
 
1512
- style: function(element) {
1513
- return element.style.cssText.toLowerCase();
2016
+ positionedOffset: function(element) {
2017
+ var valueT = 0, valueL = 0;
2018
+ do {
2019
+ valueT += element.offsetTop || 0;
2020
+ valueL += element.offsetLeft || 0;
2021
+ element = element.offsetParent;
2022
+ if (element) {
2023
+ if (element.tagName == 'BODY') break;
2024
+ var p = Element.getStyle(element, 'position');
2025
+ if (p == 'relative' || p == 'absolute') break;
2026
+ }
2027
+ } while (element);
2028
+ return Element._returnOffset(valueL, valueT);
1514
2029
  },
1515
2030
 
1516
- title: function(element) {
1517
- var node = element.getAttributeNode('title');
1518
- return node.specified ? node.nodeValue : null;
1519
- }
1520
- };
1521
-
1522
- Object.extend(Element._attributeTranslations.values, {
1523
- href: Element._attributeTranslations.values._getAttr,
1524
- src: Element._attributeTranslations.values._getAttr,
1525
- disabled: Element._attributeTranslations.values._flag,
1526
- checked: Element._attributeTranslations.values._flag,
1527
- readonly: Element._attributeTranslations.values._flag,
1528
- multiple: Element._attributeTranslations.values._flag
1529
- });
2031
+ absolutize: function(element) {
2032
+ element = $(element);
2033
+ if (element.getStyle('position') == 'absolute') return;
2034
+ // Position.prepare(); // To be done manually by Scripty when it needs it.
1530
2035
 
1531
- Element.Methods.Simulated = {
1532
- hasAttribute: function(element, attribute) {
1533
- var t = Element._attributeTranslations;
1534
- attribute = t.names[attribute] || attribute;
1535
- return $(element).getAttributeNode(attribute).specified;
1536
- }
1537
- };
2036
+ var offsets = element.positionedOffset();
2037
+ var top = offsets[1];
2038
+ var left = offsets[0];
2039
+ var width = element.clientWidth;
2040
+ var height = element.clientHeight;
1538
2041
 
1539
- // IE is missing .innerHTML support for TABLE-related elements
1540
- if (document.all && !window.opera){
1541
- Element.Methods.update = function(element, html) {
1542
- element = $(element);
1543
- html = typeof html == 'undefined' ? '' : html.toString();
1544
- var tagName = element.tagName.toUpperCase();
1545
- if (['THEAD','TBODY','TR','TD'].include(tagName)) {
1546
- var div = document.createElement('div');
1547
- switch (tagName) {
1548
- case 'THEAD':
1549
- case 'TBODY':
1550
- div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>';
1551
- depth = 2;
1552
- break;
1553
- case 'TR':
1554
- div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>';
1555
- depth = 3;
1556
- break;
1557
- case 'TD':
1558
- div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>';
1559
- depth = 4;
1560
- }
1561
- $A(element.childNodes).each(function(node){
1562
- element.removeChild(node)
1563
- });
1564
- depth.times(function(){ div = div.firstChild });
2042
+ element._originalLeft = left - parseFloat(element.style.left || 0);
2043
+ element._originalTop = top - parseFloat(element.style.top || 0);
2044
+ element._originalWidth = element.style.width;
2045
+ element._originalHeight = element.style.height;
1565
2046
 
1566
- $A(div.childNodes).each(
1567
- function(node){ element.appendChild(node) });
1568
- } else {
1569
- element.innerHTML = html.stripScripts();
1570
- }
1571
- setTimeout(function() {html.evalScripts()}, 10);
2047
+ element.style.position = 'absolute';
2048
+ element.style.top = top + 'px';
2049
+ element.style.left = left + 'px';
2050
+ element.style.width = width + 'px';
2051
+ element.style.height = height + 'px';
1572
2052
  return element;
1573
- }
1574
- };
2053
+ },
1575
2054
 
1576
- Object.extend(Element, Element.Methods);
2055
+ relativize: function(element) {
2056
+ element = $(element);
2057
+ if (element.getStyle('position') == 'relative') return;
2058
+ // Position.prepare(); // To be done manually by Scripty when it needs it.
1577
2059
 
1578
- var _nativeExtensions = false;
2060
+ element.style.position = 'relative';
2061
+ var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
2062
+ var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
1579
2063
 
1580
- if(/Konqueror|Safari|KHTML/.test(navigator.userAgent))
1581
- ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) {
1582
- var className = 'HTML' + tag + 'Element';
1583
- if(window[className]) return;
1584
- var klass = window[className] = {};
1585
- klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__;
1586
- });
2064
+ element.style.top = top + 'px';
2065
+ element.style.left = left + 'px';
2066
+ element.style.height = element._originalHeight;
2067
+ element.style.width = element._originalWidth;
2068
+ return element;
2069
+ },
1587
2070
 
1588
- Element.addMethods = function(methods) {
1589
- Object.extend(Element.Methods, methods || {});
2071
+ cumulativeScrollOffset: function(element) {
2072
+ var valueT = 0, valueL = 0;
2073
+ do {
2074
+ valueT += element.scrollTop || 0;
2075
+ valueL += element.scrollLeft || 0;
2076
+ element = element.parentNode;
2077
+ } while (element);
2078
+ return Element._returnOffset(valueL, valueT);
2079
+ },
1590
2080
 
1591
- function copy(methods, destination, onlyIfAbsent) {
1592
- onlyIfAbsent = onlyIfAbsent || false;
1593
- var cache = Element.extend.cache;
1594
- for (var property in methods) {
1595
- var value = methods[property];
1596
- if (!onlyIfAbsent || !(property in destination))
1597
- destination[property] = cache.findOrStore(value);
1598
- }
1599
- }
2081
+ getOffsetParent: function(element) {
2082
+ if (element.offsetParent) return $(element.offsetParent);
2083
+ if (element == document.body) return $(element);
1600
2084
 
1601
- if (typeof HTMLElement != 'undefined') {
1602
- copy(Element.Methods, HTMLElement.prototype);
1603
- copy(Element.Methods.Simulated, HTMLElement.prototype, true);
1604
- copy(Form.Methods, HTMLFormElement.prototype);
1605
- [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
1606
- copy(Form.Element.Methods, klass.prototype);
1607
- });
1608
- _nativeExtensions = true;
1609
- }
1610
- }
2085
+ while ((element = element.parentNode) && element != document.body)
2086
+ if (Element.getStyle(element, 'position') != 'static')
2087
+ return $(element);
1611
2088
 
1612
- var Toggle = new Object();
1613
- Toggle.display = Element.toggle;
2089
+ return $(document.body);
2090
+ },
1614
2091
 
1615
- /*--------------------------------------------------------------------------*/
2092
+ viewportOffset: function(forElement) {
2093
+ var valueT = 0, valueL = 0;
1616
2094
 
1617
- Abstract.Insertion = function(adjacency) {
1618
- this.adjacency = adjacency;
1619
- }
2095
+ var element = forElement;
2096
+ do {
2097
+ valueT += element.offsetTop || 0;
2098
+ valueL += element.offsetLeft || 0;
1620
2099
 
1621
- Abstract.Insertion.prototype = {
1622
- initialize: function(element, content) {
1623
- this.element = $(element);
1624
- this.content = content.stripScripts();
2100
+ // Safari fix
2101
+ if (element.offsetParent == document.body &&
2102
+ Element.getStyle(element, 'position') == 'absolute') break;
1625
2103
 
1626
- if (this.adjacency && this.element.insertAdjacentHTML) {
1627
- try {
1628
- this.element.insertAdjacentHTML(this.adjacency, this.content);
1629
- } catch (e) {
1630
- var tagName = this.element.tagName.toUpperCase();
1631
- if (['TBODY', 'TR'].include(tagName)) {
1632
- this.insertContent(this.contentFromAnonymousTable());
1633
- } else {
1634
- throw e;
1635
- }
2104
+ } while (element = element.offsetParent);
2105
+
2106
+ element = forElement;
2107
+ do {
2108
+ if (!Prototype.Browser.Opera || element.tagName == 'BODY') {
2109
+ valueT -= element.scrollTop || 0;
2110
+ valueL -= element.scrollLeft || 0;
1636
2111
  }
1637
- } else {
1638
- this.range = this.element.ownerDocument.createRange();
1639
- if (this.initializeRange) this.initializeRange();
1640
- this.insertContent([this.range.createContextualFragment(this.content)]);
1641
- }
2112
+ } while (element = element.parentNode);
1642
2113
 
1643
- setTimeout(function() {content.evalScripts()}, 10);
2114
+ return Element._returnOffset(valueL, valueT);
1644
2115
  },
1645
2116
 
1646
- contentFromAnonymousTable: function() {
1647
- var div = document.createElement('div');
1648
- div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
1649
- return $A(div.childNodes[0].childNodes[0].childNodes);
1650
- }
1651
- }
2117
+ clonePosition: function(element, source) {
2118
+ var options = Object.extend({
2119
+ setLeft: true,
2120
+ setTop: true,
2121
+ setWidth: true,
2122
+ setHeight: true,
2123
+ offsetTop: 0,
2124
+ offsetLeft: 0
2125
+ }, arguments[2] || { });
1652
2126
 
1653
- var Insertion = new Object();
2127
+ // find page position of source
2128
+ source = $(source);
2129
+ var p = source.viewportOffset();
1654
2130
 
1655
- Insertion.Before = Class.create();
1656
- Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
1657
- initializeRange: function() {
1658
- this.range.setStartBefore(this.element);
1659
- },
2131
+ // find coordinate system to use
2132
+ element = $(element);
2133
+ var delta = [0, 0];
2134
+ var parent = null;
2135
+ // delta [0,0] will do fine with position: fixed elements,
2136
+ // position:absolute needs offsetParent deltas
2137
+ if (Element.getStyle(element, 'position') == 'absolute') {
2138
+ parent = element.getOffsetParent();
2139
+ delta = parent.viewportOffset();
2140
+ }
1660
2141
 
1661
- insertContent: function(fragments) {
1662
- fragments.each((function(fragment) {
1663
- this.element.parentNode.insertBefore(fragment, this.element);
1664
- }).bind(this));
2142
+ // correct by body offsets (fixes Safari)
2143
+ if (parent == document.body) {
2144
+ delta[0] -= document.body.offsetLeft;
2145
+ delta[1] -= document.body.offsetTop;
2146
+ }
2147
+
2148
+ // set position
2149
+ if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
2150
+ if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
2151
+ if (options.setWidth) element.style.width = source.offsetWidth + 'px';
2152
+ if (options.setHeight) element.style.height = source.offsetHeight + 'px';
2153
+ return element;
1665
2154
  }
2155
+ };
2156
+
2157
+ Element.Methods.identify.counter = 1;
2158
+
2159
+ Object.extend(Element.Methods, {
2160
+ getElementsBySelector: Element.Methods.select,
2161
+ childElements: Element.Methods.immediateDescendants
1666
2162
  });
1667
2163
 
1668
- Insertion.Top = Class.create();
1669
- Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
1670
- initializeRange: function() {
1671
- this.range.selectNodeContents(this.element);
1672
- this.range.collapse(true);
2164
+ Element._attributeTranslations = {
2165
+ write: {
2166
+ names: {
2167
+ className: 'class',
2168
+ htmlFor: 'for'
2169
+ },
2170
+ values: { }
2171
+ }
2172
+ };
2173
+
2174
+
2175
+ if (!document.createRange || Prototype.Browser.Opera) {
2176
+ Element.Methods.insert = function(element, insertions) {
2177
+ element = $(element);
2178
+
2179
+ if (Object.isString(insertions) || Object.isNumber(insertions) ||
2180
+ Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
2181
+ insertions = { bottom: insertions };
2182
+
2183
+ var t = Element._insertionTranslations, content, position, pos, tagName;
2184
+
2185
+ for (position in insertions) {
2186
+ content = insertions[position];
2187
+ position = position.toLowerCase();
2188
+ pos = t[position];
2189
+
2190
+ if (content && content.toElement) content = content.toElement();
2191
+ if (Object.isElement(content)) {
2192
+ pos.insert(element, content);
2193
+ continue;
2194
+ }
2195
+
2196
+ content = Object.toHTML(content);
2197
+ tagName = ((position == 'before' || position == 'after')
2198
+ ? element.parentNode : element).tagName.toUpperCase();
2199
+
2200
+ if (t.tags[tagName]) {
2201
+ var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
2202
+ if (position == 'top' || position == 'after') fragments.reverse();
2203
+ fragments.each(pos.insert.curry(element));
2204
+ }
2205
+ else element.insertAdjacentHTML(pos.adjacency, content.stripScripts());
2206
+
2207
+ content.evalScripts.bind(content).defer();
2208
+ }
2209
+
2210
+ return element;
2211
+ };
2212
+ }
2213
+
2214
+ if (Prototype.Browser.Opera) {
2215
+ Element.Methods._getStyle = Element.Methods.getStyle;
2216
+ Element.Methods.getStyle = function(element, style) {
2217
+ switch(style) {
2218
+ case 'left':
2219
+ case 'top':
2220
+ case 'right':
2221
+ case 'bottom':
2222
+ if (Element._getStyle(element, 'position') == 'static') return null;
2223
+ default: return Element._getStyle(element, style);
2224
+ }
2225
+ };
2226
+ Element.Methods._readAttribute = Element.Methods.readAttribute;
2227
+ Element.Methods.readAttribute = function(element, attribute) {
2228
+ if (attribute == 'title') return element.title;
2229
+ return Element._readAttribute(element, attribute);
2230
+ };
2231
+ }
2232
+
2233
+ else if (Prototype.Browser.IE) {
2234
+ $w('positionedOffset getOffsetParent viewportOffset').each(function(method) {
2235
+ Element.Methods[method] = Element.Methods[method].wrap(
2236
+ function(proceed, element) {
2237
+ element = $(element);
2238
+ var position = element.getStyle('position');
2239
+ if (position != 'static') return proceed(element);
2240
+ element.setStyle({ position: 'relative' });
2241
+ var value = proceed(element);
2242
+ element.setStyle({ position: position });
2243
+ return value;
2244
+ }
2245
+ );
2246
+ });
2247
+
2248
+ Element.Methods.getStyle = function(element, style) {
2249
+ element = $(element);
2250
+ style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
2251
+ var value = element.style[style];
2252
+ if (!value && element.currentStyle) value = element.currentStyle[style];
2253
+
2254
+ if (style == 'opacity') {
2255
+ if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
2256
+ if (value[1]) return parseFloat(value[1]) / 100;
2257
+ return 1.0;
2258
+ }
2259
+
2260
+ if (value == 'auto') {
2261
+ if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
2262
+ return element['offset' + style.capitalize()] + 'px';
2263
+ return null;
2264
+ }
2265
+ return value;
2266
+ };
2267
+
2268
+ Element.Methods.setOpacity = function(element, value) {
2269
+ function stripAlpha(filter){
2270
+ return filter.replace(/alpha\([^\)]*\)/gi,'');
2271
+ }
2272
+ element = $(element);
2273
+ var currentStyle = element.currentStyle;
2274
+ if ((currentStyle && !currentStyle.hasLayout) ||
2275
+ (!currentStyle && element.style.zoom == 'normal'))
2276
+ element.style.zoom = 1;
2277
+
2278
+ var filter = element.getStyle('filter'), style = element.style;
2279
+ if (value == 1 || value === '') {
2280
+ (filter = stripAlpha(filter)) ?
2281
+ style.filter = filter : style.removeAttribute('filter');
2282
+ return element;
2283
+ } else if (value < 0.00001) value = 0;
2284
+ style.filter = stripAlpha(filter) +
2285
+ 'alpha(opacity=' + (value * 100) + ')';
2286
+ return element;
2287
+ };
2288
+
2289
+ Element._attributeTranslations = {
2290
+ read: {
2291
+ names: {
2292
+ 'class': 'className',
2293
+ 'for': 'htmlFor'
2294
+ },
2295
+ values: {
2296
+ _getAttr: function(element, attribute) {
2297
+ return element.getAttribute(attribute, 2);
2298
+ },
2299
+ _getAttrNode: function(element, attribute) {
2300
+ var node = element.getAttributeNode(attribute);
2301
+ return node ? node.value : "";
2302
+ },
2303
+ _getEv: function(element, attribute) {
2304
+ var attribute = element.getAttribute(attribute);
2305
+ return attribute ? attribute.toString().slice(23, -2) : null;
2306
+ },
2307
+ _flag: function(element, attribute) {
2308
+ return $(element).hasAttribute(attribute) ? attribute : null;
2309
+ },
2310
+ style: function(element) {
2311
+ return element.style.cssText.toLowerCase();
2312
+ },
2313
+ title: function(element) {
2314
+ return element.title;
2315
+ }
2316
+ }
2317
+ }
2318
+ };
2319
+
2320
+ Element._attributeTranslations.write = {
2321
+ names: Object.clone(Element._attributeTranslations.read.names),
2322
+ values: {
2323
+ checked: function(element, value) {
2324
+ element.checked = !!value;
2325
+ },
2326
+
2327
+ style: function(element, value) {
2328
+ element.style.cssText = value ? value : '';
2329
+ }
2330
+ }
2331
+ };
2332
+
2333
+ Element._attributeTranslations.has = {};
2334
+
2335
+ $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
2336
+ 'encType maxLength readOnly longDesc').each(function(attr) {
2337
+ Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
2338
+ Element._attributeTranslations.has[attr.toLowerCase()] = attr;
2339
+ });
2340
+
2341
+ (function(v) {
2342
+ Object.extend(v, {
2343
+ href: v._getAttr,
2344
+ src: v._getAttr,
2345
+ type: v._getAttr,
2346
+ action: v._getAttrNode,
2347
+ disabled: v._flag,
2348
+ checked: v._flag,
2349
+ readonly: v._flag,
2350
+ multiple: v._flag,
2351
+ onload: v._getEv,
2352
+ onunload: v._getEv,
2353
+ onclick: v._getEv,
2354
+ ondblclick: v._getEv,
2355
+ onmousedown: v._getEv,
2356
+ onmouseup: v._getEv,
2357
+ onmouseover: v._getEv,
2358
+ onmousemove: v._getEv,
2359
+ onmouseout: v._getEv,
2360
+ onfocus: v._getEv,
2361
+ onblur: v._getEv,
2362
+ onkeypress: v._getEv,
2363
+ onkeydown: v._getEv,
2364
+ onkeyup: v._getEv,
2365
+ onsubmit: v._getEv,
2366
+ onreset: v._getEv,
2367
+ onselect: v._getEv,
2368
+ onchange: v._getEv
2369
+ });
2370
+ })(Element._attributeTranslations.read.values);
2371
+ }
2372
+
2373
+ else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
2374
+ Element.Methods.setOpacity = function(element, value) {
2375
+ element = $(element);
2376
+ element.style.opacity = (value == 1) ? 0.999999 :
2377
+ (value === '') ? '' : (value < 0.00001) ? 0 : value;
2378
+ return element;
2379
+ };
2380
+ }
2381
+
2382
+ else if (Prototype.Browser.WebKit) {
2383
+ Element.Methods.setOpacity = function(element, value) {
2384
+ element = $(element);
2385
+ element.style.opacity = (value == 1 || value === '') ? '' :
2386
+ (value < 0.00001) ? 0 : value;
2387
+
2388
+ if (value == 1)
2389
+ if(element.tagName == 'IMG' && element.width) {
2390
+ element.width++; element.width--;
2391
+ } else try {
2392
+ var n = document.createTextNode(' ');
2393
+ element.appendChild(n);
2394
+ element.removeChild(n);
2395
+ } catch (e) { }
2396
+
2397
+ return element;
2398
+ };
2399
+
2400
+ // Safari returns margins on body which is incorrect if the child is absolutely
2401
+ // positioned. For performance reasons, redefine Position.cumulativeOffset for
2402
+ // KHTML/WebKit only.
2403
+ Element.Methods.cumulativeOffset = function(element) {
2404
+ var valueT = 0, valueL = 0;
2405
+ do {
2406
+ valueT += element.offsetTop || 0;
2407
+ valueL += element.offsetLeft || 0;
2408
+ if (element.offsetParent == document.body)
2409
+ if (Element.getStyle(element, 'position') == 'absolute') break;
2410
+
2411
+ element = element.offsetParent;
2412
+ } while (element);
2413
+
2414
+ return Element._returnOffset(valueL, valueT);
2415
+ };
2416
+ }
2417
+
2418
+ if (Prototype.Browser.IE || Prototype.Browser.Opera) {
2419
+ // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements
2420
+ Element.Methods.update = function(element, content) {
2421
+ element = $(element);
2422
+
2423
+ if (content && content.toElement) content = content.toElement();
2424
+ if (Object.isElement(content)) return element.update().insert(content);
2425
+
2426
+ content = Object.toHTML(content);
2427
+ var tagName = element.tagName.toUpperCase();
2428
+
2429
+ if (tagName in Element._insertionTranslations.tags) {
2430
+ $A(element.childNodes).each(function(node) { element.removeChild(node) });
2431
+ Element._getContentFromAnonymousElement(tagName, content.stripScripts())
2432
+ .each(function(node) { element.appendChild(node) });
2433
+ }
2434
+ else element.innerHTML = content.stripScripts();
2435
+
2436
+ content.evalScripts.bind(content).defer();
2437
+ return element;
2438
+ };
2439
+ }
2440
+
2441
+ if (document.createElement('div').outerHTML) {
2442
+ Element.Methods.replace = function(element, content) {
2443
+ element = $(element);
2444
+
2445
+ if (content && content.toElement) content = content.toElement();
2446
+ if (Object.isElement(content)) {
2447
+ element.parentNode.replaceChild(content, element);
2448
+ return element;
2449
+ }
2450
+
2451
+ content = Object.toHTML(content);
2452
+ var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
2453
+
2454
+ if (Element._insertionTranslations.tags[tagName]) {
2455
+ var nextSibling = element.next();
2456
+ var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
2457
+ parent.removeChild(element);
2458
+ if (nextSibling)
2459
+ fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
2460
+ else
2461
+ fragments.each(function(node) { parent.appendChild(node) });
2462
+ }
2463
+ else element.outerHTML = content.stripScripts();
2464
+
2465
+ content.evalScripts.bind(content).defer();
2466
+ return element;
2467
+ };
2468
+ }
2469
+
2470
+ Element._returnOffset = function(l, t) {
2471
+ var result = [l, t];
2472
+ result.left = l;
2473
+ result.top = t;
2474
+ return result;
2475
+ };
2476
+
2477
+ Element._getContentFromAnonymousElement = function(tagName, html) {
2478
+ var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
2479
+ div.innerHTML = t[0] + html + t[1];
2480
+ t[2].times(function() { div = div.firstChild });
2481
+ return $A(div.childNodes);
2482
+ };
2483
+
2484
+ Element._insertionTranslations = {
2485
+ before: {
2486
+ adjacency: 'beforeBegin',
2487
+ insert: function(element, node) {
2488
+ element.parentNode.insertBefore(node, element);
2489
+ },
2490
+ initializeRange: function(element, range) {
2491
+ range.setStartBefore(element);
2492
+ }
2493
+ },
2494
+ top: {
2495
+ adjacency: 'afterBegin',
2496
+ insert: function(element, node) {
2497
+ element.insertBefore(node, element.firstChild);
2498
+ },
2499
+ initializeRange: function(element, range) {
2500
+ range.selectNodeContents(element);
2501
+ range.collapse(true);
2502
+ }
2503
+ },
2504
+ bottom: {
2505
+ adjacency: 'beforeEnd',
2506
+ insert: function(element, node) {
2507
+ element.appendChild(node);
2508
+ }
2509
+ },
2510
+ after: {
2511
+ adjacency: 'afterEnd',
2512
+ insert: function(element, node) {
2513
+ element.parentNode.insertBefore(node, element.nextSibling);
2514
+ },
2515
+ initializeRange: function(element, range) {
2516
+ range.setStartAfter(element);
2517
+ }
1673
2518
  },
2519
+ tags: {
2520
+ TABLE: ['<table>', '</table>', 1],
2521
+ TBODY: ['<table><tbody>', '</tbody></table>', 2],
2522
+ TR: ['<table><tbody><tr>', '</tr></tbody></table>', 3],
2523
+ TD: ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
2524
+ SELECT: ['<select>', '</select>', 1]
2525
+ }
2526
+ };
2527
+
2528
+ (function() {
2529
+ this.bottom.initializeRange = this.top.initializeRange;
2530
+ Object.extend(this.tags, {
2531
+ THEAD: this.tags.TBODY,
2532
+ TFOOT: this.tags.TBODY,
2533
+ TH: this.tags.TD
2534
+ });
2535
+ }).call(Element._insertionTranslations);
1674
2536
 
1675
- insertContent: function(fragments) {
1676
- fragments.reverse(false).each((function(fragment) {
1677
- this.element.insertBefore(fragment, this.element.firstChild);
1678
- }).bind(this));
2537
+ Element.Methods.Simulated = {
2538
+ hasAttribute: function(element, attribute) {
2539
+ attribute = Element._attributeTranslations.has[attribute] || attribute;
2540
+ var node = $(element).getAttributeNode(attribute);
2541
+ return node && node.specified;
1679
2542
  }
1680
- });
2543
+ };
1681
2544
 
1682
- Insertion.Bottom = Class.create();
1683
- Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
1684
- initializeRange: function() {
1685
- this.range.selectNodeContents(this.element);
1686
- this.range.collapse(this.element);
1687
- },
2545
+ Element.Methods.ByTag = { };
2546
+
2547
+ Object.extend(Element, Element.Methods);
2548
+
2549
+ if (!Prototype.BrowserFeatures.ElementExtensions &&
2550
+ document.createElement('div').__proto__) {
2551
+ window.HTMLElement = { };
2552
+ window.HTMLElement.prototype = document.createElement('div').__proto__;
2553
+ Prototype.BrowserFeatures.ElementExtensions = true;
2554
+ }
2555
+
2556
+ Element.extend = (function() {
2557
+ if (Prototype.BrowserFeatures.SpecificElementExtensions)
2558
+ return Prototype.K;
1688
2559
 
1689
- insertContent: function(fragments) {
1690
- fragments.each((function(fragment) {
1691
- this.element.appendChild(fragment);
1692
- }).bind(this));
2560
+ var Methods = { }, ByTag = Element.Methods.ByTag;
2561
+
2562
+ var extend = Object.extend(function(element) {
2563
+ if (!element || element._extendedByPrototype ||
2564
+ element.nodeType != 1 || element == window) return element;
2565
+
2566
+ var methods = Object.clone(Methods),
2567
+ tagName = element.tagName, property, value;
2568
+
2569
+ // extend methods for specific tags
2570
+ if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
2571
+
2572
+ for (property in methods) {
2573
+ value = methods[property];
2574
+ if (Object.isFunction(value) && !(property in element))
2575
+ element[property] = value.methodize();
2576
+ }
2577
+
2578
+ element._extendedByPrototype = Prototype.emptyFunction;
2579
+ return element;
2580
+
2581
+ }, {
2582
+ refresh: function() {
2583
+ // extend methods for all tags (Safari doesn't need this)
2584
+ if (!Prototype.BrowserFeatures.ElementExtensions) {
2585
+ Object.extend(Methods, Element.Methods);
2586
+ Object.extend(Methods, Element.Methods.Simulated);
2587
+ }
2588
+ }
2589
+ });
2590
+
2591
+ extend.refresh();
2592
+ return extend;
2593
+ })();
2594
+
2595
+ Element.hasAttribute = function(element, attribute) {
2596
+ if (element.hasAttribute) return element.hasAttribute(attribute);
2597
+ return Element.Methods.Simulated.hasAttribute(element, attribute);
2598
+ };
2599
+
2600
+ Element.addMethods = function(methods) {
2601
+ var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
2602
+
2603
+ if (!methods) {
2604
+ Object.extend(Form, Form.Methods);
2605
+ Object.extend(Form.Element, Form.Element.Methods);
2606
+ Object.extend(Element.Methods.ByTag, {
2607
+ "FORM": Object.clone(Form.Methods),
2608
+ "INPUT": Object.clone(Form.Element.Methods),
2609
+ "SELECT": Object.clone(Form.Element.Methods),
2610
+ "TEXTAREA": Object.clone(Form.Element.Methods)
2611
+ });
1693
2612
  }
1694
- });
1695
2613
 
1696
- Insertion.After = Class.create();
1697
- Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
1698
- initializeRange: function() {
1699
- this.range.setStartAfter(this.element);
1700
- },
2614
+ if (arguments.length == 2) {
2615
+ var tagName = methods;
2616
+ methods = arguments[1];
2617
+ }
1701
2618
 
1702
- insertContent: function(fragments) {
1703
- fragments.each((function(fragment) {
1704
- this.element.parentNode.insertBefore(fragment,
1705
- this.element.nextSibling);
1706
- }).bind(this));
2619
+ if (!tagName) Object.extend(Element.Methods, methods || { });
2620
+ else {
2621
+ if (Object.isArray(tagName)) tagName.each(extend);
2622
+ else extend(tagName);
1707
2623
  }
1708
- });
1709
2624
 
1710
- /*--------------------------------------------------------------------------*/
2625
+ function extend(tagName) {
2626
+ tagName = tagName.toUpperCase();
2627
+ if (!Element.Methods.ByTag[tagName])
2628
+ Element.Methods.ByTag[tagName] = { };
2629
+ Object.extend(Element.Methods.ByTag[tagName], methods);
2630
+ }
1711
2631
 
1712
- Element.ClassNames = Class.create();
1713
- Element.ClassNames.prototype = {
1714
- initialize: function(element) {
1715
- this.element = $(element);
1716
- },
2632
+ function copy(methods, destination, onlyIfAbsent) {
2633
+ onlyIfAbsent = onlyIfAbsent || false;
2634
+ for (var property in methods) {
2635
+ var value = methods[property];
2636
+ if (!Object.isFunction(value)) continue;
2637
+ if (!onlyIfAbsent || !(property in destination))
2638
+ destination[property] = value.methodize();
2639
+ }
2640
+ }
1717
2641
 
1718
- _each: function(iterator) {
1719
- this.element.className.split(/\s+/).select(function(name) {
1720
- return name.length > 0;
1721
- })._each(iterator);
1722
- },
2642
+ function findDOMClass(tagName) {
2643
+ var klass;
2644
+ var trans = {
2645
+ "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
2646
+ "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
2647
+ "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
2648
+ "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
2649
+ "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
2650
+ "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
2651
+ "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
2652
+ "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
2653
+ "FrameSet", "IFRAME": "IFrame"
2654
+ };
2655
+ if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
2656
+ if (window[klass]) return window[klass];
2657
+ klass = 'HTML' + tagName + 'Element';
2658
+ if (window[klass]) return window[klass];
2659
+ klass = 'HTML' + tagName.capitalize() + 'Element';
2660
+ if (window[klass]) return window[klass];
2661
+
2662
+ window[klass] = { };
2663
+ window[klass].prototype = document.createElement(tagName).__proto__;
2664
+ return window[klass];
2665
+ }
1723
2666
 
1724
- set: function(className) {
1725
- this.element.className = className;
2667
+ if (F.ElementExtensions) {
2668
+ copy(Element.Methods, HTMLElement.prototype);
2669
+ copy(Element.Methods.Simulated, HTMLElement.prototype, true);
2670
+ }
2671
+
2672
+ if (F.SpecificElementExtensions) {
2673
+ for (var tag in Element.Methods.ByTag) {
2674
+ var klass = findDOMClass(tag);
2675
+ if (Object.isUndefined(klass)) continue;
2676
+ copy(T[tag], klass.prototype);
2677
+ }
2678
+ }
2679
+
2680
+ Object.extend(Element, Element.Methods);
2681
+ delete Element.ByTag;
2682
+
2683
+ if (Element.extend.refresh) Element.extend.refresh();
2684
+ Element.cache = { };
2685
+ };
2686
+
2687
+ document.viewport = {
2688
+ getDimensions: function() {
2689
+ var dimensions = { };
2690
+ $w('width height').each(function(d) {
2691
+ var D = d.capitalize();
2692
+ dimensions[d] = self['inner' + D] ||
2693
+ (document.documentElement['client' + D] || document.body['client' + D]);
2694
+ });
2695
+ return dimensions;
1726
2696
  },
1727
2697
 
1728
- add: function(classNameToAdd) {
1729
- if (this.include(classNameToAdd)) return;
1730
- this.set($A(this).concat(classNameToAdd).join(' '));
2698
+ getWidth: function() {
2699
+ return this.getDimensions().width;
1731
2700
  },
1732
2701
 
1733
- remove: function(classNameToRemove) {
1734
- if (!this.include(classNameToRemove)) return;
1735
- this.set($A(this).without(classNameToRemove).join(' '));
2702
+ getHeight: function() {
2703
+ return this.getDimensions().height;
1736
2704
  },
1737
2705
 
1738
- toString: function() {
1739
- return $A(this).join(' ');
2706
+ getScrollOffsets: function() {
2707
+ return Element._returnOffset(
2708
+ window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
2709
+ window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
1740
2710
  }
1741
2711
  };
2712
+ /* Portions of the Selector class are derived from Jack Slocum’s DomQuery,
2713
+ * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
2714
+ * license. Please see http://www.yui-ext.com/ for more information. */
1742
2715
 
1743
- Object.extend(Element.ClassNames.prototype, Enumerable);
1744
- var Selector = Class.create();
1745
- Selector.prototype = {
2716
+ var Selector = Class.create({
1746
2717
  initialize: function(expression) {
1747
- this.params = {classNames: []};
1748
- this.expression = expression.toString().strip();
1749
- this.parseExpression();
2718
+ this.expression = expression.strip();
1750
2719
  this.compileMatcher();
1751
2720
  },
1752
2721
 
1753
- parseExpression: function() {
1754
- function abort(message) { throw 'Parse error in selector: ' + message; }
2722
+ compileMatcher: function() {
2723
+ // Selectors with namespaced attributes can't use the XPath version
2724
+ if (Prototype.BrowserFeatures.XPath && !(/(\[[\w-]*?:|:checked)/).test(this.expression))
2725
+ return this.compileXPathMatcher();
1755
2726
 
1756
- if (this.expression == '') abort('empty expression');
2727
+ var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
2728
+ c = Selector.criteria, le, p, m;
1757
2729
 
1758
- var params = this.params, expr = this.expression, match, modifier, clause, rest;
1759
- while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
1760
- params.attributes = params.attributes || [];
1761
- params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
1762
- expr = match[1];
2730
+ if (Selector._cache[e]) {
2731
+ this.matcher = Selector._cache[e];
2732
+ return;
1763
2733
  }
1764
2734
 
1765
- if (expr == '*') return this.params.wildcard = true;
1766
-
1767
- while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
1768
- modifier = match[1], clause = match[2], rest = match[3];
1769
- switch (modifier) {
1770
- case '#': params.id = clause; break;
1771
- case '.': params.classNames.push(clause); break;
1772
- case '':
1773
- case undefined: params.tagName = clause.toUpperCase(); break;
1774
- default: abort(expr.inspect());
2735
+ this.matcher = ["this.matcher = function(root) {",
2736
+ "var r = root, h = Selector.handlers, c = false, n;"];
2737
+
2738
+ while (e && le != e && (/\S/).test(e)) {
2739
+ le = e;
2740
+ for (var i in ps) {
2741
+ p = ps[i];
2742
+ if (m = e.match(p)) {
2743
+ this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
2744
+ new Template(c[i]).evaluate(m));
2745
+ e = e.replace(m[0], '');
2746
+ break;
2747
+ }
1775
2748
  }
1776
- expr = rest;
1777
2749
  }
1778
2750
 
1779
- if (expr.length > 0) abort(expr.inspect());
2751
+ this.matcher.push("return h.unique(n);\n}");
2752
+ eval(this.matcher.join('\n'));
2753
+ Selector._cache[this.expression] = this.matcher;
1780
2754
  },
1781
2755
 
1782
- buildMatchExpression: function() {
1783
- var params = this.params, conditions = [], clause;
2756
+ compileXPathMatcher: function() {
2757
+ var e = this.expression, ps = Selector.patterns,
2758
+ x = Selector.xpath, le, m;
1784
2759
 
1785
- if (params.wildcard)
1786
- conditions.push('true');
1787
- if (clause = params.id)
1788
- conditions.push('element.readAttribute("id") == ' + clause.inspect());
1789
- if (clause = params.tagName)
1790
- conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
1791
- if ((clause = params.classNames).length > 0)
1792
- for (var i = 0, length = clause.length; i < length; i++)
1793
- conditions.push('element.hasClassName(' + clause[i].inspect() + ')');
1794
- if (clause = params.attributes) {
1795
- clause.each(function(attribute) {
1796
- var value = 'element.readAttribute(' + attribute.name.inspect() + ')';
1797
- var splitValueBy = function(delimiter) {
1798
- return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
1799
- }
2760
+ if (Selector._cache[e]) {
2761
+ this.xpath = Selector._cache[e]; return;
2762
+ }
1800
2763
 
1801
- switch (attribute.operator) {
1802
- case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break;
1803
- case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
1804
- case '|=': conditions.push(
1805
- splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
1806
- ); break;
1807
- case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break;
1808
- case '':
1809
- case undefined: conditions.push('element.hasAttribute(' + attribute.name.inspect() + ')'); break;
1810
- default: throw 'Unknown operator ' + attribute.operator + ' in selector';
2764
+ this.matcher = ['.//*'];
2765
+ while (e && le != e && (/\S/).test(e)) {
2766
+ le = e;
2767
+ for (var i in ps) {
2768
+ if (m = e.match(ps[i])) {
2769
+ this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :
2770
+ new Template(x[i]).evaluate(m));
2771
+ e = e.replace(m[0], '');
2772
+ break;
1811
2773
  }
1812
- });
2774
+ }
1813
2775
  }
1814
2776
 
1815
- return conditions.join(' && ');
2777
+ this.xpath = this.matcher.join('');
2778
+ Selector._cache[this.expression] = this.xpath;
1816
2779
  },
1817
2780
 
1818
- compileMatcher: function() {
1819
- this.match = new Function('element', 'if (!element.tagName) return false; \
1820
- element = $(element); \
1821
- return ' + this.buildMatchExpression());
2781
+ findElements: function(root) {
2782
+ root = root || document;
2783
+ if (this.xpath) return document._getElementsByXPath(this.xpath, root);
2784
+ return this.matcher(root);
1822
2785
  },
1823
2786
 
1824
- findElements: function(scope) {
1825
- var element;
2787
+ match: function(element) {
2788
+ this.tokens = [];
1826
2789
 
1827
- if (element = $(this.params.id))
1828
- if (this.match(element))
1829
- if (!scope || Element.childOf(element, scope))
1830
- return [element];
2790
+ var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
2791
+ var le, p, m;
1831
2792
 
1832
- scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
2793
+ while (e && le !== e && (/\S/).test(e)) {
2794
+ le = e;
2795
+ for (var i in ps) {
2796
+ p = ps[i];
2797
+ if (m = e.match(p)) {
2798
+ // use the Selector.assertions methods unless the selector
2799
+ // is too complex.
2800
+ if (as[i]) {
2801
+ this.tokens.push([i, Object.clone(m)]);
2802
+ e = e.replace(m[0], '');
2803
+ } else {
2804
+ // reluctantly do a document-wide search
2805
+ // and look for a match in the array
2806
+ return this.findElements(document).include(element);
2807
+ }
2808
+ }
2809
+ }
2810
+ }
1833
2811
 
1834
- var results = [];
1835
- for (var i = 0, length = scope.length; i < length; i++)
1836
- if (this.match(element = scope[i]))
1837
- results.push(Element.extend(element));
2812
+ var match = true, name, matches;
2813
+ for (var i = 0, token; token = this.tokens[i]; i++) {
2814
+ name = token[0], matches = token[1];
2815
+ if (!Selector.assertions[name](element, matches)) {
2816
+ match = false; break;
2817
+ }
2818
+ }
1838
2819
 
1839
- return results;
2820
+ return match;
1840
2821
  },
1841
2822
 
1842
2823
  toString: function() {
1843
2824
  return this.expression;
2825
+ },
2826
+
2827
+ inspect: function() {
2828
+ return "#<Selector:" + this.expression.inspect() + ">";
1844
2829
  }
1845
- }
2830
+ });
1846
2831
 
1847
2832
  Object.extend(Selector, {
2833
+ _cache: { },
2834
+
2835
+ xpath: {
2836
+ descendant: "//*",
2837
+ child: "/*",
2838
+ adjacent: "/following-sibling::*[1]",
2839
+ laterSibling: '/following-sibling::*',
2840
+ tagName: function(m) {
2841
+ if (m[1] == '*') return '';
2842
+ return "[local-name()='" + m[1].toLowerCase() +
2843
+ "' or local-name()='" + m[1].toUpperCase() + "']";
2844
+ },
2845
+ className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
2846
+ id: "[@id='#{1}']",
2847
+ attrPresence: "[@#{1}]",
2848
+ attr: function(m) {
2849
+ m[3] = m[5] || m[6];
2850
+ return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
2851
+ },
2852
+ pseudo: function(m) {
2853
+ var h = Selector.xpath.pseudos[m[1]];
2854
+ if (!h) return '';
2855
+ if (Object.isFunction(h)) return h(m);
2856
+ return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
2857
+ },
2858
+ operators: {
2859
+ '=': "[@#{1}='#{3}']",
2860
+ '!=': "[@#{1}!='#{3}']",
2861
+ '^=': "[starts-with(@#{1}, '#{3}')]",
2862
+ '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
2863
+ '*=': "[contains(@#{1}, '#{3}')]",
2864
+ '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
2865
+ '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
2866
+ },
2867
+ pseudos: {
2868
+ 'first-child': '[not(preceding-sibling::*)]',
2869
+ 'last-child': '[not(following-sibling::*)]',
2870
+ 'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
2871
+ 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
2872
+ 'checked': "[@checked]",
2873
+ 'disabled': "[@disabled]",
2874
+ 'enabled': "[not(@disabled)]",
2875
+ 'not': function(m) {
2876
+ var e = m[6], p = Selector.patterns,
2877
+ x = Selector.xpath, le, m, v;
2878
+
2879
+ var exclusion = [];
2880
+ while (e && le != e && (/\S/).test(e)) {
2881
+ le = e;
2882
+ for (var i in p) {
2883
+ if (m = e.match(p[i])) {
2884
+ v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);
2885
+ exclusion.push("(" + v.substring(1, v.length - 1) + ")");
2886
+ e = e.replace(m[0], '');
2887
+ break;
2888
+ }
2889
+ }
2890
+ }
2891
+ return "[not(" + exclusion.join(" and ") + ")]";
2892
+ },
2893
+ 'nth-child': function(m) {
2894
+ return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
2895
+ },
2896
+ 'nth-last-child': function(m) {
2897
+ return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
2898
+ },
2899
+ 'nth-of-type': function(m) {
2900
+ return Selector.xpath.pseudos.nth("position() ", m);
2901
+ },
2902
+ 'nth-last-of-type': function(m) {
2903
+ return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
2904
+ },
2905
+ 'first-of-type': function(m) {
2906
+ m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
2907
+ },
2908
+ 'last-of-type': function(m) {
2909
+ m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
2910
+ },
2911
+ 'only-of-type': function(m) {
2912
+ var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
2913
+ },
2914
+ nth: function(fragment, m) {
2915
+ var mm, formula = m[6], predicate;
2916
+ if (formula == 'even') formula = '2n+0';
2917
+ if (formula == 'odd') formula = '2n+1';
2918
+ if (mm = formula.match(/^(\d+)$/)) // digit only
2919
+ return '[' + fragment + "= " + mm[1] + ']';
2920
+ if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
2921
+ if (mm[1] == "-") mm[1] = -1;
2922
+ var a = mm[1] ? Number(mm[1]) : 1;
2923
+ var b = mm[2] ? Number(mm[2]) : 0;
2924
+ predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
2925
+ "((#{fragment} - #{b}) div #{a} >= 0)]";
2926
+ return new Template(predicate).evaluate({
2927
+ fragment: fragment, a: a, b: b });
2928
+ }
2929
+ }
2930
+ }
2931
+ },
2932
+
2933
+ criteria: {
2934
+ tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
2935
+ className: 'n = h.className(n, r, "#{1}", c); c = false;',
2936
+ id: 'n = h.id(n, r, "#{1}", c); c = false;',
2937
+ attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
2938
+ attr: function(m) {
2939
+ m[3] = (m[5] || m[6]);
2940
+ return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
2941
+ },
2942
+ pseudo: function(m) {
2943
+ if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
2944
+ return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
2945
+ },
2946
+ descendant: 'c = "descendant";',
2947
+ child: 'c = "child";',
2948
+ adjacent: 'c = "adjacent";',
2949
+ laterSibling: 'c = "laterSibling";'
2950
+ },
2951
+
2952
+ patterns: {
2953
+ // combinators must be listed first
2954
+ // (and descendant needs to be last combinator)
2955
+ laterSibling: /^\s*~\s*/,
2956
+ child: /^\s*>\s*/,
2957
+ adjacent: /^\s*\+\s*/,
2958
+ descendant: /^\s/,
2959
+
2960
+ // selectors follow
2961
+ tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
2962
+ id: /^#([\w\-\*]+)(\b|$)/,
2963
+ className: /^\.([\w\-\*]+)(\b|$)/,
2964
+ pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s)|(?=:))/,
2965
+ attrPresence: /^\[([\w]+)\]/,
2966
+ attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
2967
+ },
2968
+
2969
+ // for Selector.match and Element#match
2970
+ assertions: {
2971
+ tagName: function(element, matches) {
2972
+ return matches[1].toUpperCase() == element.tagName.toUpperCase();
2973
+ },
2974
+
2975
+ className: function(element, matches) {
2976
+ return Element.hasClassName(element, matches[1]);
2977
+ },
2978
+
2979
+ id: function(element, matches) {
2980
+ return element.id === matches[1];
2981
+ },
2982
+
2983
+ attrPresence: function(element, matches) {
2984
+ return Element.hasAttribute(element, matches[1]);
2985
+ },
2986
+
2987
+ attr: function(element, matches) {
2988
+ var nodeValue = Element.readAttribute(element, matches[1]);
2989
+ return Selector.operators[matches[2]](nodeValue, matches[3]);
2990
+ }
2991
+ },
2992
+
2993
+ handlers: {
2994
+ // UTILITY FUNCTIONS
2995
+ // joins two collections
2996
+ concat: function(a, b) {
2997
+ for (var i = 0, node; node = b[i]; i++)
2998
+ a.push(node);
2999
+ return a;
3000
+ },
3001
+
3002
+ // marks an array of nodes for counting
3003
+ mark: function(nodes) {
3004
+ for (var i = 0, node; node = nodes[i]; i++)
3005
+ node._counted = true;
3006
+ return nodes;
3007
+ },
3008
+
3009
+ unmark: function(nodes) {
3010
+ for (var i = 0, node; node = nodes[i]; i++)
3011
+ node._counted = undefined;
3012
+ return nodes;
3013
+ },
3014
+
3015
+ // mark each child node with its position (for nth calls)
3016
+ // "ofType" flag indicates whether we're indexing for nth-of-type
3017
+ // rather than nth-child
3018
+ index: function(parentNode, reverse, ofType) {
3019
+ parentNode._counted = true;
3020
+ if (reverse) {
3021
+ for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
3022
+ var node = nodes[i];
3023
+ if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
3024
+ }
3025
+ } else {
3026
+ for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
3027
+ if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
3028
+ }
3029
+ },
3030
+
3031
+ // filters out duplicates and extends all nodes
3032
+ unique: function(nodes) {
3033
+ if (nodes.length == 0) return nodes;
3034
+ var results = [], n;
3035
+ for (var i = 0, l = nodes.length; i < l; i++)
3036
+ if (!(n = nodes[i])._counted) {
3037
+ n._counted = true;
3038
+ results.push(Element.extend(n));
3039
+ }
3040
+ return Selector.handlers.unmark(results);
3041
+ },
3042
+
3043
+ // COMBINATOR FUNCTIONS
3044
+ descendant: function(nodes) {
3045
+ var h = Selector.handlers;
3046
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
3047
+ h.concat(results, node.getElementsByTagName('*'));
3048
+ return results;
3049
+ },
3050
+
3051
+ child: function(nodes) {
3052
+ var h = Selector.handlers;
3053
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
3054
+ for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
3055
+ if (child.nodeType == 1 && child.tagName != '!') results.push(child);
3056
+ }
3057
+ return results;
3058
+ },
3059
+
3060
+ adjacent: function(nodes) {
3061
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
3062
+ var next = this.nextElementSibling(node);
3063
+ if (next) results.push(next);
3064
+ }
3065
+ return results;
3066
+ },
3067
+
3068
+ laterSibling: function(nodes) {
3069
+ var h = Selector.handlers;
3070
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
3071
+ h.concat(results, Element.nextSiblings(node));
3072
+ return results;
3073
+ },
3074
+
3075
+ nextElementSibling: function(node) {
3076
+ while (node = node.nextSibling)
3077
+ if (node.nodeType == 1) return node;
3078
+ return null;
3079
+ },
3080
+
3081
+ previousElementSibling: function(node) {
3082
+ while (node = node.previousSibling)
3083
+ if (node.nodeType == 1) return node;
3084
+ return null;
3085
+ },
3086
+
3087
+ // TOKEN FUNCTIONS
3088
+ tagName: function(nodes, root, tagName, combinator) {
3089
+ tagName = tagName.toUpperCase();
3090
+ var results = [], h = Selector.handlers;
3091
+ if (nodes) {
3092
+ if (combinator) {
3093
+ // fastlane for ordinary descendant combinators
3094
+ if (combinator == "descendant") {
3095
+ for (var i = 0, node; node = nodes[i]; i++)
3096
+ h.concat(results, node.getElementsByTagName(tagName));
3097
+ return results;
3098
+ } else nodes = this[combinator](nodes);
3099
+ if (tagName == "*") return nodes;
3100
+ }
3101
+ for (var i = 0, node; node = nodes[i]; i++)
3102
+ if (node.tagName.toUpperCase() == tagName) results.push(node);
3103
+ return results;
3104
+ } else return root.getElementsByTagName(tagName);
3105
+ },
3106
+
3107
+ id: function(nodes, root, id, combinator) {
3108
+ var targetNode = $(id), h = Selector.handlers;
3109
+ if (!targetNode) return [];
3110
+ if (!nodes && root == document) return [targetNode];
3111
+ if (nodes) {
3112
+ if (combinator) {
3113
+ if (combinator == 'child') {
3114
+ for (var i = 0, node; node = nodes[i]; i++)
3115
+ if (targetNode.parentNode == node) return [targetNode];
3116
+ } else if (combinator == 'descendant') {
3117
+ for (var i = 0, node; node = nodes[i]; i++)
3118
+ if (Element.descendantOf(targetNode, node)) return [targetNode];
3119
+ } else if (combinator == 'adjacent') {
3120
+ for (var i = 0, node; node = nodes[i]; i++)
3121
+ if (Selector.handlers.previousElementSibling(targetNode) == node)
3122
+ return [targetNode];
3123
+ } else nodes = h[combinator](nodes);
3124
+ }
3125
+ for (var i = 0, node; node = nodes[i]; i++)
3126
+ if (node == targetNode) return [targetNode];
3127
+ return [];
3128
+ }
3129
+ return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
3130
+ },
3131
+
3132
+ className: function(nodes, root, className, combinator) {
3133
+ if (nodes && combinator) nodes = this[combinator](nodes);
3134
+ return Selector.handlers.byClassName(nodes, root, className);
3135
+ },
3136
+
3137
+ byClassName: function(nodes, root, className) {
3138
+ if (!nodes) nodes = Selector.handlers.descendant([root]);
3139
+ var needle = ' ' + className + ' ';
3140
+ for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
3141
+ nodeClassName = node.className;
3142
+ if (nodeClassName.length == 0) continue;
3143
+ if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
3144
+ results.push(node);
3145
+ }
3146
+ return results;
3147
+ },
3148
+
3149
+ attrPresence: function(nodes, root, attr) {
3150
+ if (!nodes) nodes = root.getElementsByTagName("*");
3151
+ var results = [];
3152
+ for (var i = 0, node; node = nodes[i]; i++)
3153
+ if (Element.hasAttribute(node, attr)) results.push(node);
3154
+ return results;
3155
+ },
3156
+
3157
+ attr: function(nodes, root, attr, value, operator) {
3158
+ if (!nodes) nodes = root.getElementsByTagName("*");
3159
+ var handler = Selector.operators[operator], results = [];
3160
+ for (var i = 0, node; node = nodes[i]; i++) {
3161
+ var nodeValue = Element.readAttribute(node, attr);
3162
+ if (nodeValue === null) continue;
3163
+ if (handler(nodeValue, value)) results.push(node);
3164
+ }
3165
+ return results;
3166
+ },
3167
+
3168
+ pseudo: function(nodes, name, value, root, combinator) {
3169
+ if (nodes && combinator) nodes = this[combinator](nodes);
3170
+ if (!nodes) nodes = root.getElementsByTagName("*");
3171
+ return Selector.pseudos[name](nodes, value, root);
3172
+ }
3173
+ },
3174
+
3175
+ pseudos: {
3176
+ 'first-child': function(nodes, value, root) {
3177
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
3178
+ if (Selector.handlers.previousElementSibling(node)) continue;
3179
+ results.push(node);
3180
+ }
3181
+ return results;
3182
+ },
3183
+ 'last-child': function(nodes, value, root) {
3184
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
3185
+ if (Selector.handlers.nextElementSibling(node)) continue;
3186
+ results.push(node);
3187
+ }
3188
+ return results;
3189
+ },
3190
+ 'only-child': function(nodes, value, root) {
3191
+ var h = Selector.handlers;
3192
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
3193
+ if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
3194
+ results.push(node);
3195
+ return results;
3196
+ },
3197
+ 'nth-child': function(nodes, formula, root) {
3198
+ return Selector.pseudos.nth(nodes, formula, root);
3199
+ },
3200
+ 'nth-last-child': function(nodes, formula, root) {
3201
+ return Selector.pseudos.nth(nodes, formula, root, true);
3202
+ },
3203
+ 'nth-of-type': function(nodes, formula, root) {
3204
+ return Selector.pseudos.nth(nodes, formula, root, false, true);
3205
+ },
3206
+ 'nth-last-of-type': function(nodes, formula, root) {
3207
+ return Selector.pseudos.nth(nodes, formula, root, true, true);
3208
+ },
3209
+ 'first-of-type': function(nodes, formula, root) {
3210
+ return Selector.pseudos.nth(nodes, "1", root, false, true);
3211
+ },
3212
+ 'last-of-type': function(nodes, formula, root) {
3213
+ return Selector.pseudos.nth(nodes, "1", root, true, true);
3214
+ },
3215
+ 'only-of-type': function(nodes, formula, root) {
3216
+ var p = Selector.pseudos;
3217
+ return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
3218
+ },
3219
+
3220
+ // handles the an+b logic
3221
+ getIndices: function(a, b, total) {
3222
+ if (a == 0) return b > 0 ? [b] : [];
3223
+ return $R(1, total).inject([], function(memo, i) {
3224
+ if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
3225
+ return memo;
3226
+ });
3227
+ },
3228
+
3229
+ // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
3230
+ nth: function(nodes, formula, root, reverse, ofType) {
3231
+ if (nodes.length == 0) return [];
3232
+ if (formula == 'even') formula = '2n+0';
3233
+ if (formula == 'odd') formula = '2n+1';
3234
+ var h = Selector.handlers, results = [], indexed = [], m;
3235
+ h.mark(nodes);
3236
+ for (var i = 0, node; node = nodes[i]; i++) {
3237
+ if (!node.parentNode._counted) {
3238
+ h.index(node.parentNode, reverse, ofType);
3239
+ indexed.push(node.parentNode);
3240
+ }
3241
+ }
3242
+ if (formula.match(/^\d+$/)) { // just a number
3243
+ formula = Number(formula);
3244
+ for (var i = 0, node; node = nodes[i]; i++)
3245
+ if (node.nodeIndex == formula) results.push(node);
3246
+ } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
3247
+ if (m[1] == "-") m[1] = -1;
3248
+ var a = m[1] ? Number(m[1]) : 1;
3249
+ var b = m[2] ? Number(m[2]) : 0;
3250
+ var indices = Selector.pseudos.getIndices(a, b, nodes.length);
3251
+ for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
3252
+ for (var j = 0; j < l; j++)
3253
+ if (node.nodeIndex == indices[j]) results.push(node);
3254
+ }
3255
+ }
3256
+ h.unmark(nodes);
3257
+ h.unmark(indexed);
3258
+ return results;
3259
+ },
3260
+
3261
+ 'empty': function(nodes, value, root) {
3262
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
3263
+ // IE treats comments as element nodes
3264
+ if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
3265
+ results.push(node);
3266
+ }
3267
+ return results;
3268
+ },
3269
+
3270
+ 'not': function(nodes, selector, root) {
3271
+ var h = Selector.handlers, selectorType, m;
3272
+ var exclusions = new Selector(selector).findElements(root);
3273
+ h.mark(exclusions);
3274
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
3275
+ if (!node._counted) results.push(node);
3276
+ h.unmark(exclusions);
3277
+ return results;
3278
+ },
3279
+
3280
+ 'enabled': function(nodes, value, root) {
3281
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
3282
+ if (!node.disabled) results.push(node);
3283
+ return results;
3284
+ },
3285
+
3286
+ 'disabled': function(nodes, value, root) {
3287
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
3288
+ if (node.disabled) results.push(node);
3289
+ return results;
3290
+ },
3291
+
3292
+ 'checked': function(nodes, value, root) {
3293
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
3294
+ if (node.checked) results.push(node);
3295
+ return results;
3296
+ }
3297
+ },
3298
+
3299
+ operators: {
3300
+ '=': function(nv, v) { return nv == v; },
3301
+ '!=': function(nv, v) { return nv != v; },
3302
+ '^=': function(nv, v) { return nv.startsWith(v); },
3303
+ '$=': function(nv, v) { return nv.endsWith(v); },
3304
+ '*=': function(nv, v) { return nv.include(v); },
3305
+ '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
3306
+ '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
3307
+ },
3308
+
1848
3309
  matchElements: function(elements, expression) {
1849
- var selector = new Selector(expression);
1850
- return elements.select(selector.match.bind(selector)).map(Element.extend);
3310
+ var matches = new Selector(expression).findElements(), h = Selector.handlers;
3311
+ h.mark(matches);
3312
+ for (var i = 0, results = [], element; element = elements[i]; i++)
3313
+ if (element._counted) results.push(element);
3314
+ h.unmark(matches);
3315
+ return results;
1851
3316
  },
1852
3317
 
1853
3318
  findElement: function(elements, expression, index) {
1854
- if (typeof expression == 'number') index = expression, expression = false;
3319
+ if (Object.isNumber(expression)) {
3320
+ index = expression; expression = false;
3321
+ }
1855
3322
  return Selector.matchElements(elements, expression || '*')[index || 0];
1856
3323
  },
1857
3324
 
1858
3325
  findChildElements: function(element, expressions) {
1859
- return expressions.map(function(expression) {
1860
- return expression.match(/[^\s"]+(?:"[^"]*"[^\s"]+)*/g).inject([null], function(results, expr) {
1861
- var selector = new Selector(expr);
1862
- return results.inject([], function(elements, result) {
1863
- return elements.concat(selector.findElements(result || element));
1864
- });
1865
- });
1866
- }).flatten();
3326
+ var exprs = expressions.join(','), expressions = [];
3327
+ exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
3328
+ expressions.push(m[1].strip());
3329
+ });
3330
+ var results = [], h = Selector.handlers;
3331
+ for (var i = 0, l = expressions.length, selector; i < l; i++) {
3332
+ selector = new Selector(expressions[i].strip());
3333
+ h.concat(results, selector.findElements(element));
3334
+ }
3335
+ return (l > 1) ? h.unique(results) : results;
1867
3336
  }
1868
3337
  });
1869
3338
 
@@ -1876,13 +3345,19 @@ var Form = {
1876
3345
  return form;
1877
3346
  },
1878
3347
 
1879
- serializeElements: function(elements, getHash) {
1880
- var data = elements.inject({}, function(result, element) {
3348
+ serializeElements: function(elements, options) {
3349
+ if (typeof options != 'object') options = { hash: !!options };
3350
+ else if (options.hash === undefined) options.hash = true;
3351
+ var key, value, submitted = false, submit = options.submit;
3352
+
3353
+ var data = elements.inject({ }, function(result, element) {
1881
3354
  if (!element.disabled && element.name) {
1882
- var key = element.name, value = $(element).getValue();
1883
- if (value != undefined) {
1884
- if (result[key]) {
1885
- if (result[key].constructor != Array) result[key] = [result[key]];
3355
+ key = element.name; value = $(element).getValue();
3356
+ if (value != null && (element.type != 'submit' || (!submitted &&
3357
+ submit !== false && (!submit || key == submit) && (submitted = true)))) {
3358
+ if (key in result) {
3359
+ // a key is already present; construct an array of values
3360
+ if (!Object.isArray(result[key])) result[key] = [result[key]];
1886
3361
  result[key].push(value);
1887
3362
  }
1888
3363
  else result[key] = value;
@@ -1891,13 +3366,13 @@ var Form = {
1891
3366
  return result;
1892
3367
  });
1893
3368
 
1894
- return getHash ? data : Hash.toQueryString(data);
3369
+ return options.hash ? data : Object.toQueryString(data);
1895
3370
  }
1896
3371
  };
1897
3372
 
1898
3373
  Form.Methods = {
1899
- serialize: function(form, getHash) {
1900
- return Form.serializeElements(Form.getElements(form), getHash);
3374
+ serialize: function(form, options) {
3375
+ return Form.serializeElements(Form.getElements(form), options);
1901
3376
  },
1902
3377
 
1903
3378
  getElements: function(form) {
@@ -1928,25 +3403,26 @@ Form.Methods = {
1928
3403
 
1929
3404
  disable: function(form) {
1930
3405
  form = $(form);
1931
- form.getElements().each(function(element) {
1932
- element.blur();
1933
- element.disabled = 'true';
1934
- });
3406
+ Form.getElements(form).invoke('disable');
1935
3407
  return form;
1936
3408
  },
1937
3409
 
1938
3410
  enable: function(form) {
1939
3411
  form = $(form);
1940
- form.getElements().each(function(element) {
1941
- element.disabled = '';
1942
- });
3412
+ Form.getElements(form).invoke('enable');
1943
3413
  return form;
1944
3414
  },
1945
3415
 
1946
3416
  findFirstElement: function(form) {
1947
- return $(form).getElements().find(function(element) {
1948
- return element.type != 'hidden' && !element.disabled &&
1949
- ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
3417
+ var elements = $(form).getElements().findAll(function(element) {
3418
+ return 'hidden' != element.type && !element.disabled;
3419
+ });
3420
+ var firstByIndex = elements.findAll(function(element) {
3421
+ return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
3422
+ }).sortBy(function(element) { return element.tabIndex }).first();
3423
+
3424
+ return firstByIndex ? firstByIndex : elements.find(function(element) {
3425
+ return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
1950
3426
  });
1951
3427
  },
1952
3428
 
@@ -1954,10 +3430,26 @@ Form.Methods = {
1954
3430
  form = $(form);
1955
3431
  form.findFirstElement().activate();
1956
3432
  return form;
1957
- }
1958
- }
3433
+ },
1959
3434
 
1960
- Object.extend(Form, Form.Methods);
3435
+ request: function(form, options) {
3436
+ form = $(form), options = Object.clone(options || { });
3437
+
3438
+ var params = options.parameters, action = form.readAttribute('action') || '';
3439
+ if (action.blank()) action = window.location.href;
3440
+ options.parameters = form.serialize(true);
3441
+
3442
+ if (params) {
3443
+ if (Object.isString(params)) params = params.toQueryParams();
3444
+ Object.extend(options.parameters, params);
3445
+ }
3446
+
3447
+ if (form.hasAttribute('method') && !options.method)
3448
+ options.method = form.method;
3449
+
3450
+ return new Ajax.Request(action, options);
3451
+ }
3452
+ };
1961
3453
 
1962
3454
  /*--------------------------------------------------------------------------*/
1963
3455
 
@@ -1971,7 +3463,7 @@ Form.Element = {
1971
3463
  $(element).select();
1972
3464
  return element;
1973
3465
  }
1974
- }
3466
+ };
1975
3467
 
1976
3468
  Form.Element.Methods = {
1977
3469
  serialize: function(element) {
@@ -1979,9 +3471,9 @@ Form.Element.Methods = {
1979
3471
  if (!element.disabled && element.name) {
1980
3472
  var value = element.getValue();
1981
3473
  if (value != undefined) {
1982
- var pair = {};
3474
+ var pair = { };
1983
3475
  pair[element.name] = value;
1984
- return Hash.toQueryString(pair);
3476
+ return Object.toQueryString(pair);
1985
3477
  }
1986
3478
  }
1987
3479
  return '';
@@ -1993,6 +3485,13 @@ Form.Element.Methods = {
1993
3485
  return Form.Element.Serializers[method](element);
1994
3486
  },
1995
3487
 
3488
+ setValue: function(element, value) {
3489
+ element = $(element);
3490
+ var method = element.tagName.toLowerCase();
3491
+ Form.Element.Serializers[method](element, value);
3492
+ return element;
3493
+ },
3494
+
1996
3495
  clear: function(element) {
1997
3496
  $(element).value = '';
1998
3497
  return element;
@@ -2004,55 +3503,75 @@ Form.Element.Methods = {
2004
3503
 
2005
3504
  activate: function(element) {
2006
3505
  element = $(element);
2007
- element.focus();
2008
- if (element.select && ( element.tagName.toLowerCase() != 'input' ||
2009
- !['button', 'reset', 'submit'].include(element.type) ) )
2010
- element.select();
3506
+ try {
3507
+ element.focus();
3508
+ if (element.select && (element.tagName.toLowerCase() != 'input' ||
3509
+ !['button', 'reset', 'submit'].include(element.type)))
3510
+ element.select();
3511
+ } catch (e) { }
2011
3512
  return element;
2012
3513
  },
2013
3514
 
2014
3515
  disable: function(element) {
2015
3516
  element = $(element);
3517
+ element.blur();
2016
3518
  element.disabled = true;
2017
3519
  return element;
2018
3520
  },
2019
3521
 
2020
3522
  enable: function(element) {
2021
3523
  element = $(element);
2022
- element.blur();
2023
3524
  element.disabled = false;
2024
3525
  return element;
2025
3526
  }
2026
- }
3527
+ };
3528
+
3529
+ /*--------------------------------------------------------------------------*/
2027
3530
 
2028
- Object.extend(Form.Element, Form.Element.Methods);
2029
3531
  var Field = Form.Element;
2030
- var $F = Form.Element.getValue;
3532
+ var $F = Form.Element.Methods.getValue;
2031
3533
 
2032
3534
  /*--------------------------------------------------------------------------*/
2033
3535
 
2034
3536
  Form.Element.Serializers = {
2035
- input: function(element) {
3537
+ input: function(element, value) {
2036
3538
  switch (element.type.toLowerCase()) {
2037
3539
  case 'checkbox':
2038
3540
  case 'radio':
2039
- return Form.Element.Serializers.inputSelector(element);
3541
+ return Form.Element.Serializers.inputSelector(element, value);
2040
3542
  default:
2041
- return Form.Element.Serializers.textarea(element);
3543
+ return Form.Element.Serializers.textarea(element, value);
2042
3544
  }
2043
3545
  },
2044
3546
 
2045
- inputSelector: function(element) {
2046
- return element.checked ? element.value : null;
3547
+ inputSelector: function(element, value) {
3548
+ if (value === undefined) return element.checked ? element.value : null;
3549
+ else element.checked = !!value;
2047
3550
  },
2048
3551
 
2049
- textarea: function(element) {
2050
- return element.value;
3552
+ textarea: function(element, value) {
3553
+ if (value === undefined) return element.value;
3554
+ else element.value = value;
2051
3555
  },
2052
3556
 
2053
- select: function(element) {
2054
- return this[element.type == 'select-one' ?
2055
- 'selectOne' : 'selectMany'](element);
3557
+ select: function(element, index) {
3558
+ if (index === undefined)
3559
+ return this[element.type == 'select-one' ?
3560
+ 'selectOne' : 'selectMany'](element);
3561
+ else {
3562
+ var opt, value, single = !Object.isArray(index);
3563
+ for (var i = 0, length = element.length; i < length; i++) {
3564
+ opt = element.options[i];
3565
+ value = this.optionValue(opt);
3566
+ if (single) {
3567
+ if (value == index) {
3568
+ opt.selected = true;
3569
+ return;
3570
+ }
3571
+ }
3572
+ else opt.selected = index.include(value);
3573
+ }
3574
+ }
2056
3575
  },
2057
3576
 
2058
3577
  selectOne: function(element) {
@@ -2075,219 +3594,436 @@ Form.Element.Serializers = {
2075
3594
  // extend element because hasAttribute may not be native
2076
3595
  return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
2077
3596
  }
2078
- }
3597
+ };
2079
3598
 
2080
3599
  /*--------------------------------------------------------------------------*/
2081
3600
 
2082
- Abstract.TimedObserver = function() {}
2083
- Abstract.TimedObserver.prototype = {
2084
- initialize: function(element, frequency, callback) {
2085
- this.frequency = frequency;
3601
+ Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
3602
+ initialize: function($super, element, frequency, callback) {
3603
+ $super(callback, frequency);
2086
3604
  this.element = $(element);
2087
- this.callback = callback;
2088
-
2089
3605
  this.lastValue = this.getValue();
2090
- this.registerCallback();
2091
3606
  },
2092
3607
 
2093
- registerCallback: function() {
2094
- setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
3608
+ execute: function() {
3609
+ var value = this.getValue();
3610
+ if (Object.isString(this.lastValue) && Object.isString(value) ?
3611
+ this.lastValue != value : String(this.lastValue) != String(value)) {
3612
+ this.callback(this.element, value);
3613
+ this.lastValue = value;
3614
+ }
3615
+ }
3616
+ });
3617
+
3618
+ Form.Element.Observer = Class.create(Abstract.TimedObserver, {
3619
+ getValue: function() {
3620
+ return Form.Element.getValue(this.element);
3621
+ }
3622
+ });
3623
+
3624
+ Form.Observer = Class.create(Abstract.TimedObserver, {
3625
+ getValue: function() {
3626
+ return Form.serialize(this.element);
3627
+ }
3628
+ });
3629
+
3630
+ /*--------------------------------------------------------------------------*/
3631
+
3632
+ Abstract.EventObserver = Class.create({
3633
+ initialize: function(element, callback) {
3634
+ this.element = $(element);
3635
+ this.callback = callback;
3636
+
3637
+ this.lastValue = this.getValue();
3638
+ if (this.element.tagName.toLowerCase() == 'form')
3639
+ this.registerFormCallbacks();
3640
+ else
3641
+ this.registerCallback(this.element);
2095
3642
  },
2096
3643
 
2097
- onTimerEvent: function() {
3644
+ onElementEvent: function() {
2098
3645
  var value = this.getValue();
2099
- var changed = ('string' == typeof this.lastValue && 'string' == typeof value
2100
- ? this.lastValue != value : String(this.lastValue) != String(value));
2101
- if (changed) {
3646
+ if (this.lastValue != value) {
2102
3647
  this.callback(this.element, value);
2103
3648
  this.lastValue = value;
2104
3649
  }
3650
+ },
3651
+
3652
+ registerFormCallbacks: function() {
3653
+ Form.getElements(this.element).each(this.registerCallback, this);
3654
+ },
3655
+
3656
+ registerCallback: function(element) {
3657
+ if (element.type) {
3658
+ switch (element.type.toLowerCase()) {
3659
+ case 'checkbox':
3660
+ case 'radio':
3661
+ Event.observe(element, 'click', this.onElementEvent.bind(this));
3662
+ break;
3663
+ default:
3664
+ Event.observe(element, 'change', this.onElementEvent.bind(this));
3665
+ break;
3666
+ }
3667
+ }
2105
3668
  }
2106
- }
3669
+ });
3670
+
3671
+ Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
3672
+ getValue: function() {
3673
+ return Form.Element.getValue(this.element);
3674
+ }
3675
+ });
3676
+
3677
+ Form.EventObserver = Class.create(Abstract.EventObserver, {
3678
+ getValue: function() {
3679
+ return Form.serialize(this.element);
3680
+ }
3681
+ });
3682
+ if (!window.Event) var Event = { };
3683
+
3684
+ Object.extend(Event, {
3685
+ KEY_BACKSPACE: 8,
3686
+ KEY_TAB: 9,
3687
+ KEY_RETURN: 13,
3688
+ KEY_ESC: 27,
3689
+ KEY_LEFT: 37,
3690
+ KEY_UP: 38,
3691
+ KEY_RIGHT: 39,
3692
+ KEY_DOWN: 40,
3693
+ KEY_DELETE: 46,
3694
+ KEY_HOME: 36,
3695
+ KEY_END: 35,
3696
+ KEY_PAGEUP: 33,
3697
+ KEY_PAGEDOWN: 34,
3698
+ KEY_INSERT: 45,
3699
+
3700
+ cache: { },
3701
+
3702
+ relatedTarget: function(event) {
3703
+ var element;
3704
+ switch(event.type) {
3705
+ case 'mouseover': element = event.fromElement; break;
3706
+ case 'mouseout': element = event.toElement; break;
3707
+ default: return null;
3708
+ }
3709
+ return Element.extend(element);
3710
+ }
3711
+ });
3712
+
3713
+ Event.Methods = (function() {
3714
+ var isButton;
3715
+
3716
+ if (Prototype.Browser.IE) {
3717
+ var buttonMap = { 0: 1, 1: 4, 2: 2 };
3718
+ isButton = function(event, code) {
3719
+ return event.button == buttonMap[code];
3720
+ };
3721
+
3722
+ } else if (Prototype.Browser.WebKit) {
3723
+ isButton = function(event, code) {
3724
+ switch (code) {
3725
+ case 0: return event.which == 1 && !event.metaKey;
3726
+ case 1: return event.which == 1 && event.metaKey;
3727
+ default: return false;
3728
+ }
3729
+ };
3730
+
3731
+ } else {
3732
+ isButton = function(event, code) {
3733
+ return event.which ? (event.which === code + 1) : (event.button === code);
3734
+ };
3735
+ }
3736
+
3737
+ return {
3738
+ isLeftClick: function(event) { return isButton(event, 0) },
3739
+ isMiddleClick: function(event) { return isButton(event, 1) },
3740
+ isRightClick: function(event) { return isButton(event, 2) },
3741
+
3742
+ element: function(event) {
3743
+ var node = Event.extend(event).target;
3744
+ return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node);
3745
+ },
3746
+
3747
+ findElement: function(event, expression) {
3748
+ var element = Event.element(event);
3749
+ return element.match(expression) ? element : element.up(expression);
3750
+ },
3751
+
3752
+ pointer: function(event) {
3753
+ return {
3754
+ x: event.pageX || (event.clientX +
3755
+ (document.documentElement.scrollLeft || document.body.scrollLeft)),
3756
+ y: event.pageY || (event.clientY +
3757
+ (document.documentElement.scrollTop || document.body.scrollTop))
3758
+ };
3759
+ },
3760
+
3761
+ pointerX: function(event) { return Event.pointer(event).x },
3762
+ pointerY: function(event) { return Event.pointer(event).y },
3763
+
3764
+ stop: function(event) {
3765
+ Event.extend(event);
3766
+ event.preventDefault();
3767
+ event.stopPropagation();
3768
+ event.stopped = true;
3769
+ }
3770
+ };
3771
+ })();
3772
+
3773
+ Event.extend = (function() {
3774
+ var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
3775
+ m[name] = Event.Methods[name].methodize();
3776
+ return m;
3777
+ });
3778
+
3779
+ if (Prototype.Browser.IE) {
3780
+ Object.extend(methods, {
3781
+ stopPropagation: function() { this.cancelBubble = true },
3782
+ preventDefault: function() { this.returnValue = false },
3783
+ inspect: function() { return "[object Event]" }
3784
+ });
3785
+
3786
+ return function(event) {
3787
+ if (!event) return false;
3788
+ if (event._extendedByPrototype) return event;
3789
+
3790
+ event._extendedByPrototype = Prototype.emptyFunction;
3791
+ var pointer = Event.pointer(event);
3792
+ Object.extend(event, {
3793
+ target: event.srcElement,
3794
+ relatedTarget: Event.relatedTarget(event),
3795
+ pageX: pointer.x,
3796
+ pageY: pointer.y
3797
+ });
3798
+ return Object.extend(event, methods);
3799
+ };
3800
+
3801
+ } else {
3802
+ Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__;
3803
+ Object.extend(Event.prototype, methods);
3804
+ return Prototype.K;
3805
+ }
3806
+ })();
3807
+
3808
+ Object.extend(Event, (function() {
3809
+ var cache = Event.cache;
3810
+
3811
+ function getEventID(element) {
3812
+ if (element._eventID) return element._eventID;
3813
+ arguments.callee.id = arguments.callee.id || 1;
3814
+ return element._eventID = ++arguments.callee.id;
3815
+ }
3816
+
3817
+ function getDOMEventName(eventName) {
3818
+ if (eventName && eventName.include(':')) return "dataavailable";
3819
+ return eventName;
3820
+ }
3821
+
3822
+ function getCacheForID(id) {
3823
+ return cache[id] = cache[id] || { };
3824
+ }
3825
+
3826
+ function getWrappersForEventName(id, eventName) {
3827
+ var c = getCacheForID(id);
3828
+ return c[eventName] = c[eventName] || [];
3829
+ }
3830
+
3831
+ function createWrapper(element, eventName, handler) {
3832
+ var id = getEventID(element);
3833
+ var c = getWrappersForEventName(id, eventName);
3834
+ if (c.pluck("handler").include(handler)) return false;
3835
+
3836
+ var wrapper = function(event) {
3837
+ if (!Event || !Event.extend ||
3838
+ (event.eventName && event.eventName != eventName))
3839
+ return false;
3840
+
3841
+ Event.extend(event);
3842
+ handler.call(element, event)
3843
+ };
3844
+
3845
+ wrapper.handler = handler;
3846
+ c.push(wrapper);
3847
+ return wrapper;
3848
+ }
3849
+
3850
+ function findWrapper(id, eventName, handler) {
3851
+ var c = getWrappersForEventName(id, eventName);
3852
+ return c.find(function(wrapper) { return wrapper.handler == handler });
3853
+ }
3854
+
3855
+ function destroyWrapper(id, eventName, handler) {
3856
+ var c = getCacheForID(id);
3857
+ if (!c[eventName]) return false;
3858
+ c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
3859
+ }
3860
+
3861
+ function destroyCache() {
3862
+ for (var id in cache)
3863
+ for (var eventName in cache[id])
3864
+ cache[id][eventName] = null;
3865
+ }
3866
+
3867
+ if (window.attachEvent) {
3868
+ window.attachEvent("onunload", destroyCache);
3869
+ }
3870
+
3871
+ return {
3872
+ observe: function(element, eventName, handler) {
3873
+ element = $(element);
3874
+ var name = getDOMEventName(eventName);
3875
+
3876
+ var wrapper = createWrapper(element, eventName, handler);
3877
+ if (!wrapper) return element;
3878
+
3879
+ if (element.addEventListener) {
3880
+ element.addEventListener(name, wrapper, false);
3881
+ } else {
3882
+ element.attachEvent("on" + name, wrapper);
3883
+ }
3884
+
3885
+ return element;
3886
+ },
3887
+
3888
+ stopObserving: function(element, eventName, handler) {
3889
+ element = $(element);
3890
+ var id = getEventID(element), name = getDOMEventName(eventName);
3891
+
3892
+ if (!handler && eventName) {
3893
+ getWrappersForEventName(id, eventName).each(function(wrapper) {
3894
+ element.stopObserving(eventName, wrapper.handler);
3895
+ });
3896
+ return element;
2107
3897
 
2108
- Form.Element.Observer = Class.create();
2109
- Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
2110
- getValue: function() {
2111
- return Form.Element.getValue(this.element);
2112
- }
2113
- });
3898
+ } else if (!eventName) {
3899
+ Object.keys(getCacheForID(id)).each(function(eventName) {
3900
+ element.stopObserving(eventName);
3901
+ });
3902
+ return element;
3903
+ }
2114
3904
 
2115
- Form.Observer = Class.create();
2116
- Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
2117
- getValue: function() {
2118
- return Form.serialize(this.element);
2119
- }
2120
- });
3905
+ var wrapper = findWrapper(id, eventName, handler);
3906
+ if (!wrapper) return element;
2121
3907
 
2122
- /*--------------------------------------------------------------------------*/
3908
+ if (element.removeEventListener) {
3909
+ element.removeEventListener(name, wrapper, false);
3910
+ } else {
3911
+ element.detachEvent("on" + name, wrapper);
3912
+ }
2123
3913
 
2124
- Abstract.EventObserver = function() {}
2125
- Abstract.EventObserver.prototype = {
2126
- initialize: function(element, callback) {
2127
- this.element = $(element);
2128
- this.callback = callback;
3914
+ destroyWrapper(id, eventName, handler);
2129
3915
 
2130
- this.lastValue = this.getValue();
2131
- if (this.element.tagName.toLowerCase() == 'form')
2132
- this.registerFormCallbacks();
2133
- else
2134
- this.registerCallback(this.element);
2135
- },
3916
+ return element;
3917
+ },
2136
3918
 
2137
- onElementEvent: function() {
2138
- var value = this.getValue();
2139
- if (this.lastValue != value) {
2140
- this.callback(this.element, value);
2141
- this.lastValue = value;
2142
- }
2143
- },
3919
+ fire: function(element, eventName, memo) {
3920
+ element = $(element);
3921
+ if (element == document && document.createEvent && !element.dispatchEvent)
3922
+ element = document.documentElement;
2144
3923
 
2145
- registerFormCallbacks: function() {
2146
- Form.getElements(this.element).each(this.registerCallback.bind(this));
2147
- },
3924
+ if (document.createEvent) {
3925
+ var event = document.createEvent("HTMLEvents");
3926
+ event.initEvent("dataavailable", true, true);
3927
+ } else {
3928
+ var event = document.createEventObject();
3929
+ event.eventType = "ondataavailable";
3930
+ }
2148
3931
 
2149
- registerCallback: function(element) {
2150
- if (element.type) {
2151
- switch (element.type.toLowerCase()) {
2152
- case 'checkbox':
2153
- case 'radio':
2154
- Event.observe(element, 'click', this.onElementEvent.bind(this));
2155
- break;
2156
- default:
2157
- Event.observe(element, 'change', this.onElementEvent.bind(this));
2158
- break;
3932
+ event.eventName = eventName;
3933
+ event.memo = memo || { };
3934
+
3935
+ if (document.createEvent) {
3936
+ element.dispatchEvent(event);
3937
+ } else {
3938
+ element.fireEvent(event.eventType, event);
2159
3939
  }
3940
+
3941
+ return event;
2160
3942
  }
2161
- }
2162
- }
3943
+ };
3944
+ })());
2163
3945
 
2164
- Form.Element.EventObserver = Class.create();
2165
- Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
2166
- getValue: function() {
2167
- return Form.Element.getValue(this.element);
2168
- }
3946
+ Object.extend(Event, Event.Methods);
3947
+
3948
+ Element.addMethods({
3949
+ fire: Event.fire,
3950
+ observe: Event.observe,
3951
+ stopObserving: Event.stopObserving
2169
3952
  });
2170
3953
 
2171
- Form.EventObserver = Class.create();
2172
- Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
2173
- getValue: function() {
2174
- return Form.serialize(this.element);
2175
- }
3954
+ Object.extend(document, {
3955
+ fire: Element.Methods.fire.methodize(),
3956
+ observe: Element.Methods.observe.methodize(),
3957
+ stopObserving: Element.Methods.stopObserving.methodize()
2176
3958
  });
2177
- if (!window.Event) {
2178
- var Event = new Object();
2179
- }
2180
3959
 
2181
- Object.extend(Event, {
2182
- KEY_BACKSPACE: 8,
2183
- KEY_TAB: 9,
2184
- KEY_RETURN: 13,
2185
- KEY_ESC: 27,
2186
- KEY_LEFT: 37,
2187
- KEY_UP: 38,
2188
- KEY_RIGHT: 39,
2189
- KEY_DOWN: 40,
2190
- KEY_DELETE: 46,
2191
- KEY_HOME: 36,
2192
- KEY_END: 35,
2193
- KEY_PAGEUP: 33,
2194
- KEY_PAGEDOWN: 34,
3960
+ (function() {
3961
+ /* Support for the DOMContentLoaded event is based on work by Dan Webb,
3962
+ Matthias Miller, Dean Edwards and John Resig. */
2195
3963
 
2196
- element: function(event) {
2197
- return event.target || event.srcElement;
2198
- },
3964
+ var timer, fired = false;
2199
3965
 
2200
- isLeftClick: function(event) {
2201
- return (((event.which) && (event.which == 1)) ||
2202
- ((event.button) && (event.button == 1)));
2203
- },
3966
+ function fireContentLoadedEvent() {
3967
+ if (fired) return;
3968
+ if (timer) window.clearInterval(timer);
3969
+ document.fire("dom:loaded");
3970
+ fired = true;
3971
+ }
2204
3972
 
2205
- pointerX: function(event) {
2206
- return event.pageX || (event.clientX +
2207
- (document.documentElement.scrollLeft || document.body.scrollLeft));
2208
- },
3973
+ if (document.addEventListener) {
3974
+ if (Prototype.Browser.WebKit) {
3975
+ timer = window.setInterval(function() {
3976
+ if (/loaded|complete/.test(document.readyState))
3977
+ fireContentLoadedEvent();
3978
+ }, 0);
2209
3979
 
2210
- pointerY: function(event) {
2211
- return event.pageY || (event.clientY +
2212
- (document.documentElement.scrollTop || document.body.scrollTop));
2213
- },
3980
+ Event.observe(window, "load", fireContentLoadedEvent);
2214
3981
 
2215
- stop: function(event) {
2216
- if (event.preventDefault) {
2217
- event.preventDefault();
2218
- event.stopPropagation();
2219
3982
  } else {
2220
- event.returnValue = false;
2221
- event.cancelBubble = true;
3983
+ document.addEventListener("DOMContentLoaded",
3984
+ fireContentLoadedEvent, false);
2222
3985
  }
2223
- },
2224
-
2225
- // find the first node with the given tagName, starting from the
2226
- // node the event was triggered on; traverses the DOM upwards
2227
- findElement: function(event, tagName) {
2228
- var element = Event.element(event);
2229
- while (element.parentNode && (!element.tagName ||
2230
- (element.tagName.toUpperCase() != tagName.toUpperCase())))
2231
- element = element.parentNode;
2232
- return element;
2233
- },
2234
3986
 
2235
- observers: false,
2236
-
2237
- _observeAndCache: function(element, name, observer, useCapture) {
2238
- if (!this.observers) this.observers = [];
2239
- if (element.addEventListener) {
2240
- this.observers.push([element, name, observer, useCapture]);
2241
- element.addEventListener(name, observer, useCapture);
2242
- } else if (element.attachEvent) {
2243
- this.observers.push([element, name, observer, useCapture]);
2244
- element.attachEvent('on' + name, observer);
2245
- }
2246
- },
3987
+ } else {
3988
+ document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>");
3989
+ $("__onDOMContentLoaded").onreadystatechange = function() {
3990
+ if (this.readyState == "complete") {
3991
+ this.onreadystatechange = null;
3992
+ fireContentLoadedEvent();
3993
+ }
3994
+ };
3995
+ }
3996
+ })();
3997
+ /*------------------------------- DEPRECATED -------------------------------*/
2247
3998
 
2248
- unloadCache: function() {
2249
- if (!Event.observers) return;
2250
- for (var i = 0, length = Event.observers.length; i < length; i++) {
2251
- Event.stopObserving.apply(this, Event.observers[i]);
2252
- Event.observers[i][0] = null;
2253
- }
2254
- Event.observers = false;
2255
- },
3999
+ Hash.toQueryString = Object.toQueryString;
2256
4000
 
2257
- observe: function(element, name, observer, useCapture) {
2258
- element = $(element);
2259
- useCapture = useCapture || false;
4001
+ var Toggle = { display: Element.toggle };
2260
4002
 
2261
- if (name == 'keypress' &&
2262
- (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
2263
- || element.attachEvent))
2264
- name = 'keydown';
4003
+ Element.Methods.childOf = Element.Methods.descendantOf;
2265
4004
 
2266
- Event._observeAndCache(element, name, observer, useCapture);
4005
+ var Insertion = {
4006
+ Before: function(element, content) {
4007
+ return Element.insert(element, {before:content});
2267
4008
  },
2268
4009
 
2269
- stopObserving: function(element, name, observer, useCapture) {
2270
- element = $(element);
2271
- useCapture = useCapture || false;
4010
+ Top: function(element, content) {
4011
+ return Element.insert(element, {top:content});
4012
+ },
2272
4013
 
2273
- if (name == 'keypress' &&
2274
- (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
2275
- || element.detachEvent))
2276
- name = 'keydown';
4014
+ Bottom: function(element, content) {
4015
+ return Element.insert(element, {bottom:content});
4016
+ },
2277
4017
 
2278
- if (element.removeEventListener) {
2279
- element.removeEventListener(name, observer, useCapture);
2280
- } else if (element.detachEvent) {
2281
- try {
2282
- element.detachEvent('on' + name, observer);
2283
- } catch (e) {}
2284
- }
4018
+ After: function(element, content) {
4019
+ return Element.insert(element, {after:content});
2285
4020
  }
2286
- });
4021
+ };
4022
+
4023
+ var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
2287
4024
 
2288
- /* prevent memory leaks in IE */
2289
- if (navigator.appVersion.match(/\bMSIE\b/))
2290
- Event.observe(window, 'unload', Event.unloadCache, false);
4025
+ // This should be moved to script.aculo.us; notice the deprecated methods
4026
+ // further below, that map to the newer Element methods.
2291
4027
  var Position = {
2292
4028
  // set to true if needed, warning: firefox performance problems
2293
4029
  // NOT neeeded for page scrolling, only if draggable contained in
@@ -2307,59 +4043,13 @@ var Position = {
2307
4043
  || 0;
2308
4044
  },
2309
4045
 
2310
- realOffset: function(element) {
2311
- var valueT = 0, valueL = 0;
2312
- do {
2313
- valueT += element.scrollTop || 0;
2314
- valueL += element.scrollLeft || 0;
2315
- element = element.parentNode;
2316
- } while (element);
2317
- return [valueL, valueT];
2318
- },
2319
-
2320
- cumulativeOffset: function(element) {
2321
- var valueT = 0, valueL = 0;
2322
- do {
2323
- valueT += element.offsetTop || 0;
2324
- valueL += element.offsetLeft || 0;
2325
- element = element.offsetParent;
2326
- } while (element);
2327
- return [valueL, valueT];
2328
- },
2329
-
2330
- positionedOffset: function(element) {
2331
- var valueT = 0, valueL = 0;
2332
- do {
2333
- valueT += element.offsetTop || 0;
2334
- valueL += element.offsetLeft || 0;
2335
- element = element.offsetParent;
2336
- if (element) {
2337
- if(element.tagName=='BODY') break;
2338
- var p = Element.getStyle(element, 'position');
2339
- if (p == 'relative' || p == 'absolute') break;
2340
- }
2341
- } while (element);
2342
- return [valueL, valueT];
2343
- },
2344
-
2345
- offsetParent: function(element) {
2346
- if (element.offsetParent) return element.offsetParent;
2347
- if (element == document.body) return element;
2348
-
2349
- while ((element = element.parentNode) && element != document.body)
2350
- if (Element.getStyle(element, 'position') != 'static')
2351
- return element;
2352
-
2353
- return document.body;
2354
- },
2355
-
2356
4046
  // caches x/y coordinate pair to use with overlap
2357
4047
  within: function(element, x, y) {
2358
4048
  if (this.includeScrollOffsets)
2359
4049
  return this.withinIncludingScrolloffsets(element, x, y);
2360
4050
  this.xcomp = x;
2361
4051
  this.ycomp = y;
2362
- this.offset = this.cumulativeOffset(element);
4052
+ this.offset = Element.cumulativeOffset(element);
2363
4053
 
2364
4054
  return (y >= this.offset[1] &&
2365
4055
  y < this.offset[1] + element.offsetHeight &&
@@ -2368,11 +4058,11 @@ var Position = {
2368
4058
  },
2369
4059
 
2370
4060
  withinIncludingScrolloffsets: function(element, x, y) {
2371
- var offsetcache = this.realOffset(element);
4061
+ var offsetcache = Element.cumulativeScrollOffset(element);
2372
4062
 
2373
4063
  this.xcomp = x + offsetcache[0] - this.deltaX;
2374
4064
  this.ycomp = y + offsetcache[1] - this.deltaY;
2375
- this.offset = this.cumulativeOffset(element);
4065
+ this.offset = Element.cumulativeOffset(element);
2376
4066
 
2377
4067
  return (this.ycomp >= this.offset[1] &&
2378
4068
  this.ycomp < this.offset[1] + element.offsetHeight &&
@@ -2391,125 +4081,104 @@ var Position = {
2391
4081
  element.offsetWidth;
2392
4082
  },
2393
4083
 
2394
- page: function(forElement) {
2395
- var valueT = 0, valueL = 0;
2396
-
2397
- var element = forElement;
2398
- do {
2399
- valueT += element.offsetTop || 0;
2400
- valueL += element.offsetLeft || 0;
4084
+ // Deprecation layer -- use newer Element methods now (1.5.2).
2401
4085
 
2402
- // Safari fix
2403
- if (element.offsetParent==document.body)
2404
- if (Element.getStyle(element,'position')=='absolute') break;
4086
+ cumulativeOffset: Element.Methods.cumulativeOffset,
2405
4087
 
2406
- } while (element = element.offsetParent);
4088
+ positionedOffset: Element.Methods.positionedOffset,
2407
4089
 
2408
- element = forElement;
2409
- do {
2410
- if (!window.opera || element.tagName=='BODY') {
2411
- valueT -= element.scrollTop || 0;
2412
- valueL -= element.scrollLeft || 0;
2413
- }
2414
- } while (element = element.parentNode);
4090
+ absolutize: function(element) {
4091
+ Position.prepare();
4092
+ return Element.absolutize(element);
4093
+ },
2415
4094
 
2416
- return [valueL, valueT];
4095
+ relativize: function(element) {
4096
+ Position.prepare();
4097
+ return Element.relativize(element);
2417
4098
  },
2418
4099
 
2419
- clone: function(source, target) {
2420
- var options = Object.extend({
2421
- setLeft: true,
2422
- setTop: true,
2423
- setWidth: true,
2424
- setHeight: true,
2425
- offsetTop: 0,
2426
- offsetLeft: 0
2427
- }, arguments[2] || {})
4100
+ realOffset: Element.Methods.cumulativeScrollOffset,
2428
4101
 
2429
- // find page position of source
2430
- source = $(source);
2431
- var p = Position.page(source);
4102
+ offsetParent: Element.Methods.getOffsetParent,
2432
4103
 
2433
- // find coordinate system to use
2434
- target = $(target);
2435
- var delta = [0, 0];
2436
- var parent = null;
2437
- // delta [0,0] will do fine with position: fixed elements,
2438
- // position:absolute needs offsetParent deltas
2439
- if (Element.getStyle(target,'position') == 'absolute') {
2440
- parent = Position.offsetParent(target);
2441
- delta = Position.page(parent);
2442
- }
4104
+ page: Element.Methods.viewportOffset,
2443
4105
 
2444
- // correct by body offsets (fixes Safari)
2445
- if (parent == document.body) {
2446
- delta[0] -= document.body.offsetLeft;
2447
- delta[1] -= document.body.offsetTop;
4106
+ clone: function(source, target, options) {
4107
+ options = options || { };
4108
+ return Element.clonePosition(target, source, options);
4109
+ }
4110
+ };
4111
+
4112
+ /*--------------------------------------------------------------------------*/
4113
+
4114
+ if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
4115
+ function iter(name) {
4116
+ return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
4117
+ }
4118
+
4119
+ instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
4120
+ function(element, className) {
4121
+ className = className.toString().strip();
4122
+ var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
4123
+ return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
4124
+ } : function(element, className) {
4125
+ className = className.toString().strip();
4126
+ var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
4127
+ if (!classNames && !className) return elements;
4128
+
4129
+ var nodes = $(element).getElementsByTagName('*');
4130
+ className = ' ' + className + ' ';
4131
+
4132
+ for (var i = 0, child, cn; child = nodes[i]; i++) {
4133
+ if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
4134
+ (classNames && classNames.all(function(name) {
4135
+ return !name.toString().blank() && cn.include(' ' + name + ' ');
4136
+ }))))
4137
+ elements.push(Element.extend(child));
2448
4138
  }
4139
+ return elements;
4140
+ };
2449
4141
 
2450
- // set position
2451
- if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
2452
- if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
2453
- if(options.setWidth) target.style.width = source.offsetWidth + 'px';
2454
- if(options.setHeight) target.style.height = source.offsetHeight + 'px';
2455
- },
4142
+ return function(className, parentElement) {
4143
+ return $(parentElement || document.body).getElementsByClassName(className);
4144
+ };
4145
+ }(Element.Methods);
2456
4146
 
2457
- absolutize: function(element) {
2458
- element = $(element);
2459
- if (element.style.position == 'absolute') return;
2460
- Position.prepare();
4147
+ /*--------------------------------------------------------------------------*/
2461
4148
 
2462
- var offsets = Position.positionedOffset(element);
2463
- var top = offsets[1];
2464
- var left = offsets[0];
2465
- var width = element.clientWidth;
2466
- var height = element.clientHeight;
4149
+ Element.ClassNames = Class.create();
4150
+ Element.ClassNames.prototype = {
4151
+ initialize: function(element) {
4152
+ this.element = $(element);
4153
+ },
2467
4154
 
2468
- element._originalLeft = left - parseFloat(element.style.left || 0);
2469
- element._originalTop = top - parseFloat(element.style.top || 0);
2470
- element._originalWidth = element.style.width;
2471
- element._originalHeight = element.style.height;
4155
+ _each: function(iterator) {
4156
+ this.element.className.split(/\s+/).select(function(name) {
4157
+ return name.length > 0;
4158
+ })._each(iterator);
4159
+ },
2472
4160
 
2473
- element.style.position = 'absolute';
2474
- element.style.top = top + 'px';
2475
- element.style.left = left + 'px';
2476
- element.style.width = width + 'px';
2477
- element.style.height = height + 'px';
4161
+ set: function(className) {
4162
+ this.element.className = className;
2478
4163
  },
2479
4164
 
2480
- relativize: function(element) {
2481
- element = $(element);
2482
- if (element.style.position == 'relative') return;
2483
- Position.prepare();
4165
+ add: function(classNameToAdd) {
4166
+ if (this.include(classNameToAdd)) return;
4167
+ this.set($A(this).concat(classNameToAdd).join(' '));
4168
+ },
2484
4169
 
2485
- element.style.position = 'relative';
2486
- var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
2487
- var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
4170
+ remove: function(classNameToRemove) {
4171
+ if (!this.include(classNameToRemove)) return;
4172
+ this.set($A(this).without(classNameToRemove).join(' '));
4173
+ },
2488
4174
 
2489
- element.style.top = top + 'px';
2490
- element.style.left = left + 'px';
2491
- element.style.height = element._originalHeight;
2492
- element.style.width = element._originalWidth;
4175
+ toString: function() {
4176
+ return $A(this).join(' ');
2493
4177
  }
2494
- }
2495
-
2496
- // Safari returns margins on body which is incorrect if the child is absolutely
2497
- // positioned. For performance reasons, redefine Position.cumulativeOffset for
2498
- // KHTML/WebKit only.
2499
- if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
2500
- Position.cumulativeOffset = function(element) {
2501
- var valueT = 0, valueL = 0;
2502
- do {
2503
- valueT += element.offsetTop || 0;
2504
- valueL += element.offsetLeft || 0;
2505
- if (element.offsetParent == document.body)
2506
- if (Element.getStyle(element, 'position') == 'absolute') break;
4178
+ };
2507
4179
 
2508
- element = element.offsetParent;
2509
- } while (element);
4180
+ Object.extend(Element.ClassNames.prototype, Enumerable);
2510
4181
 
2511
- return [valueL, valueT];
2512
- }
2513
- }
4182
+ /*--------------------------------------------------------------------------*/
2514
4183
 
2515
4184
  Element.addMethods();