backlog 0.35.5 → 0.36.2

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.
Files changed (150) hide show
  1. data/Gemfile +19 -0
  2. data/Gemfile~ +4 -0
  3. data/History.txt +25 -0
  4. data/Rakefile +3 -3
  5. data/app/controllers/{application.rb → application_controller.rb} +1 -2
  6. data/app/controllers/backlogs_controller.rb +0 -16
  7. data/app/controllers/search_controller.rb +0 -2
  8. data/app/controllers/user_controller.rb +7 -7
  9. data/app/controllers/work_locks_controller.rb +2 -2
  10. data/app/controllers/works_controller.rb +23 -23
  11. data/app/helpers/application_helper.rb +9 -6
  12. data/app/helpers/backlogs_helper.rb +1 -1
  13. data/app/helpers/periods_helper.rb +1 -1
  14. data/app/models/backlog.rb +13 -10
  15. data/app/models/period.rb +0 -5
  16. data/app/models/sidebar.rb +1 -0
  17. data/app/models/task.rb +4 -10
  18. data/app/models/user.rb +5 -6
  19. data/app/models/user_notify.rb +0 -1
  20. data/app/models/work.rb +20 -25
  21. data/app/models/works_report_filter.rb +4 -4
  22. data/app/views/backlogs/_buttons.rhtml +1 -1
  23. data/app/views/backlogs/_form.rhtml +5 -9
  24. data/app/views/layouts/_left_top.rhtml +0 -1
  25. data/app/views/periods/_form.rhtml +1 -1
  26. data/app/views/search/results.rhtml +1 -12
  27. data/app/views/task_notify/{invite_en.rhtml → invite.en.html.erb} +0 -0
  28. data/app/views/task_notify/{invite_no.rhtml → invite.no.html.erb} +0 -0
  29. data/app/views/tasks/_task.rhtml +49 -50
  30. data/app/views/tasks/edit.rhtml +4 -4
  31. data/app/views/tasks/start_work.rjs +1 -1
  32. data/app/views/user/_edit.rhtml +1 -1
  33. data/app/views/user/change_password.rhtml +1 -1
  34. data/app/views/user/edit.rhtml +4 -4
  35. data/app/views/user/signup.rhtml +2 -2
  36. data/app/views/user_notify/{change_password_en.rhtml → change_password.en.html.erb} +0 -0
  37. data/app/views/user_notify/{change_password_no.rhtml → change_password.no.html.erb} +0 -0
  38. data/app/views/user_notify/{forgot_password_en.rhtml → forgot_password.en.html.erb} +0 -0
  39. data/app/views/user_notify/{forgot_password_no.rhtml → forgot_password.no.html.erb} +0 -0
  40. data/app/views/user_notify/{monitoring_en.rhtml → monitoring.en.html.erb} +0 -0
  41. data/app/views/user_notify/{monitoring_no.rhtml → monitoring.no.html.erb} +0 -0
  42. data/app/views/user_notify/{monitoring_invitation_en.rhtml → monitoring_invitation.en.html.erb} +0 -0
  43. data/app/views/user_notify/{monitoring_invitation_no.rhtml → monitoring_invitation.no.html.erb} +0 -0
  44. data/app/views/user_notify/{signup_en.rhtml → signup.en.html.erb} +0 -0
  45. data/app/views/user_notify/{signup_no.rhtml → signup.no.html.erb} +0 -0
  46. data/app/views/work_lock_notify/{lock_en.rhtml → lock.en.html.erb} +0 -0
  47. data/app/views/work_lock_notify/{lock_no.rhtml → lock.no.html.erb} +0 -0
  48. data/app/views/work_lock_notify/{nag_en.rhtml → nag.en.html.erb} +0 -0
  49. data/app/views/work_lock_notify/{nag_no.rhtml → nag.no.html.erb} +0 -0
  50. data/app/views/works/_form.rhtml +6 -6
  51. data/app/views/works/_new_row.rhtml +6 -6
  52. data/app/views/works/_row.rhtml +2 -2
  53. data/app/views/works/daily_work_sheet.rhtml +1 -1
  54. data/app/views/works/list.rhtml +6 -6
  55. data/app/views/works/list_excel.rhtml +8 -4
  56. data/app/views/works/timeliste.rhtml +14 -14
  57. data/app/views/works/update_row.rjs +1 -1
  58. data/app/views/works/weekly_work_sheet.rhtml +5 -5
  59. data/app/views/works/weekly_work_sheet_details.rhtml +5 -5
  60. data/config/boot.rb +108 -27
  61. data/config/database.yml +3 -26
  62. data/config/environment.rb +4 -12
  63. data/config/environments/development.rb +0 -1
  64. data/config/initializers/jdbc.rb +7 -0
  65. data/config/initializers/mongrel.rb +83 -0
  66. data/config/locales/en.yml +189 -0
  67. data/config/locales/no.yml +192 -0
  68. data/config/preinitializer.rb +20 -0
  69. data/cruise_build.sh +10 -0
  70. data/cruise_config.rb +1 -1
  71. data/db/migrate/20100720124707_merge_work_account_into_backlog.rb +74 -0
  72. data/db/schema.rb +93 -127
  73. data/lib/class_table_inheritance.rb +53 -11
  74. data/lib/tasks/jdbc.rake +8 -0
  75. data/lib/user_system.rb +5 -1
  76. data/public/javascripts/controls.js +76 -79
  77. data/public/javascripts/dragdrop.js +166 -167
  78. data/public/javascripts/effects.js +174 -168
  79. data/public/javascripts/prototype.js +470 -334
  80. data/public/stylesheets/mwrt002.css +6 -6
  81. data/script/dbconsole +3 -0
  82. data/test/fixtures/backlogs.yml +2 -2
  83. data/test/fixtures/work_lock_subscriptions.yml +2 -2
  84. data/test/fixtures/works.yml +6 -6
  85. data/test/functional/absences_controller_test.rb +1 -1
  86. data/test/functional/backlogs_controller_test.rb +4 -4
  87. data/test/functional/customers_controller_test.rb +1 -1
  88. data/test/functional/dashboard_controller_test.rb +1 -1
  89. data/test/functional/estimates_controller_test.rb +1 -1
  90. data/test/functional/groups_controller_test.rb +1 -1
  91. data/test/functional/parties_controller_test.rb +1 -1
  92. data/test/functional/periods_controller_test.rb +1 -1
  93. data/test/functional/public_holidays_controller_test.rb +1 -1
  94. data/test/functional/search_controller_test.rb +1 -1
  95. data/test/functional/task_files_controller_test.rb +1 -1
  96. data/test/functional/tasks_controller_test.rb +6 -6
  97. data/test/functional/user_controller_test.rb +3 -2
  98. data/test/functional/welcome_controller_test.rb +1 -1
  99. data/test/functional/work_locks_controller_test.rb +1 -1
  100. data/test/functional/works_controller_test.rb +11 -11
  101. data/test/test_helper.rb +2 -2
  102. data/test/unit/absence_test.rb +1 -1
  103. data/test/unit/configuration_test.rb +1 -1
  104. data/test/unit/customer_test.rb +1 -1
  105. data/test/unit/estimate_test.rb +1 -1
  106. data/test/unit/group_test.rb +1 -1
  107. data/test/unit/party_test.rb +1 -1
  108. data/test/unit/period_test.rb +1 -1
  109. data/test/unit/public_holiday_test.rb +1 -1
  110. data/test/unit/task_file_test.rb +1 -1
  111. data/test/unit/task_test.rb +1 -1
  112. data/test/unit/user_test.rb +1 -1
  113. data/test/unit/work_lock_subscription_test.rb +1 -1
  114. data/test/unit/work_lock_test.rb +1 -1
  115. data/test/unit/work_test.rb +8 -8
  116. data/vendor/plugins/acts_as_list/lib/active_record/acts/list.rb +3 -3
  117. data/vendor/plugins/assert_cookie/lib/assert_cookie.rb +2 -2
  118. data/vendor/plugins/auto_complete/README +23 -0
  119. data/vendor/plugins/auto_complete/Rakefile +22 -0
  120. data/vendor/plugins/auto_complete/init.rb +2 -0
  121. data/vendor/plugins/auto_complete/lib/auto_complete.rb +47 -0
  122. data/vendor/plugins/auto_complete/lib/auto_complete_macros_helper.rb +143 -0
  123. data/vendor/plugins/auto_complete/test/auto_complete_test.rb +67 -0
  124. data/vendor/plugins/backlog_jira/init.rb +4 -0
  125. data/vendor/plugins/backlog_jira/{tasks → lib/tasks}/backlog_jira_tasks.rake +0 -0
  126. data/vendor/plugins/has_history/{tasks → lib/tasks}/has_history_tasks.rake +0 -0
  127. metadata +745 -817
  128. data/#SearchRequest.xml# +0 -3443
  129. data/app/controllers/application.rb~ +0 -207
  130. data/app/controllers/work_accounts_controller.rb +0 -58
  131. data/app/helpers/work_accounts_helper.rb +0 -2
  132. data/app/models/work_account.rb +0 -18
  133. data/app/models/work_lock_subscription.rb +0 -3
  134. data/app/views/work_accounts/_form.rhtml +0 -16
  135. data/app/views/work_accounts/_name_list.rhtml +0 -5
  136. data/app/views/work_accounts/_title.rhtml +0 -5
  137. data/app/views/work_accounts/edit.rhtml +0 -12
  138. data/app/views/work_accounts/list.rhtml +0 -31
  139. data/app/views/work_accounts/new.rhtml +0 -10
  140. data/app/views/work_accounts/show.rhtml +0 -50
  141. data/config/environments/localization_environment.rb +0 -10
  142. data/jira.log +0 -98246
  143. data/lang/en.yaml +0 -147
  144. data/lang/localizations.yaml +0 -2
  145. data/lang/no.yaml +0 -146
  146. data/lib/localization.rb +0 -88
  147. data/test/fixtures/work_accounts.yml +0 -7
  148. data/test/functional/work_accounts_controller_test.rb +0 -94
  149. data/test/unit/localization_test.rb +0 -47
  150. data/test/unit/work_account_test.rb +0 -10
@@ -1,5 +1,5 @@
1
- /* Prototype JavaScript framework, version 1.6.0
2
- * (c) 2005-2007 Sam Stephenson
1
+ /* Prototype JavaScript framework, version 1.6.0.3
2
+ * (c) 2005-2008 Sam Stephenson
3
3
  *
4
4
  * Prototype is freely distributable under the terms of an MIT-style license.
5
5
  * For details, see the Prototype web site: http://www.prototypejs.org/
@@ -7,23 +7,26 @@
7
7
  *--------------------------------------------------------------------------*/
8
8
 
9
9
  var Prototype = {
10
- Version: '1.6.0',
10
+ Version: '1.6.0.3',
11
11
 
12
12
  Browser: {
13
- IE: !!(window.attachEvent && !window.opera),
14
- Opera: !!window.opera,
13
+ IE: !!(window.attachEvent &&
14
+ navigator.userAgent.indexOf('Opera') === -1),
15
+ Opera: navigator.userAgent.indexOf('Opera') > -1,
15
16
  WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
16
- Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
17
+ Gecko: navigator.userAgent.indexOf('Gecko') > -1 &&
18
+ navigator.userAgent.indexOf('KHTML') === -1,
17
19
  MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
18
20
  },
19
21
 
20
22
  BrowserFeatures: {
21
23
  XPath: !!document.evaluate,
24
+ SelectorsAPI: !!document.querySelector,
22
25
  ElementExtensions: !!window.HTMLElement,
23
26
  SpecificElementExtensions:
24
- document.createElement('div').__proto__ &&
25
- document.createElement('div').__proto__ !==
26
- document.createElement('form').__proto__
27
+ document.createElement('div')['__proto__'] &&
28
+ document.createElement('div')['__proto__'] !==
29
+ document.createElement('form')['__proto__']
27
30
  },
28
31
 
29
32
  ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
@@ -36,8 +39,6 @@ var Prototype = {
36
39
  if (Prototype.Browser.MobileSafari)
37
40
  Prototype.BrowserFeatures.SpecificElementExtensions = false;
38
41
 
39
- if (Prototype.Browser.WebKit)
40
- Prototype.BrowserFeatures.XPath = false;
41
42
 
42
43
  /* Based on Alex Arnell's inheritance implementation. */
43
44
  var Class = {
@@ -85,12 +86,13 @@ Class.Methods = {
85
86
  var property = properties[i], value = source[property];
86
87
  if (ancestor && Object.isFunction(value) &&
87
88
  value.argumentNames().first() == "$super") {
88
- var method = value, value = Object.extend((function(m) {
89
+ var method = value;
90
+ value = (function(m) {
89
91
  return function() { return ancestor[m].apply(this, arguments) };
90
- })(property).wrap(method), {
91
- valueOf: function() { return method },
92
- toString: function() { return method.toString() }
93
- });
92
+ })(property).wrap(method);
93
+
94
+ value.valueOf = method.valueOf.bind(method);
95
+ value.toString = method.toString.bind(method);
94
96
  }
95
97
  this.prototype[property] = value;
96
98
  }
@@ -110,9 +112,9 @@ Object.extend = function(destination, source) {
110
112
  Object.extend(Object, {
111
113
  inspect: function(object) {
112
114
  try {
113
- if (object === undefined) return 'undefined';
115
+ if (Object.isUndefined(object)) return 'undefined';
114
116
  if (object === null) return 'null';
115
- return object.inspect ? object.inspect() : object.toString();
117
+ return object.inspect ? object.inspect() : String(object);
116
118
  } catch (e) {
117
119
  if (e instanceof RangeError) return '...';
118
120
  throw e;
@@ -135,7 +137,7 @@ Object.extend(Object, {
135
137
  var results = [];
136
138
  for (var property in object) {
137
139
  var value = Object.toJSON(object[property]);
138
- if (value !== undefined)
140
+ if (!Object.isUndefined(value))
139
141
  results.push(property.toJSON() + ': ' + value);
140
142
  }
141
143
 
@@ -169,11 +171,12 @@ Object.extend(Object, {
169
171
  },
170
172
 
171
173
  isElement: function(object) {
172
- return object && object.nodeType == 1;
174
+ return !!(object && object.nodeType == 1);
173
175
  },
174
176
 
175
177
  isArray: function(object) {
176
- return object && object.constructor === Array;
178
+ return object != null && typeof object == "object" &&
179
+ 'splice' in object && 'join' in object;
177
180
  },
178
181
 
179
182
  isHash: function(object) {
@@ -199,12 +202,13 @@ Object.extend(Object, {
199
202
 
200
203
  Object.extend(Function.prototype, {
201
204
  argumentNames: function() {
202
- var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip");
205
+ var names = this.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1]
206
+ .replace(/\s+/g, '').split(',');
203
207
  return names.length == 1 && !names[0] ? [] : names;
204
208
  },
205
209
 
206
210
  bind: function() {
207
- if (arguments.length < 2 && arguments[0] === undefined) return this;
211
+ if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
208
212
  var __method = this, args = $A(arguments), object = args.shift();
209
213
  return function() {
210
214
  return __method.apply(object, args.concat($A(arguments)));
@@ -233,6 +237,11 @@ Object.extend(Function.prototype, {
233
237
  }, timeout);
234
238
  },
235
239
 
240
+ defer: function() {
241
+ var args = [0.01].concat($A(arguments));
242
+ return this.delay.apply(this, args);
243
+ },
244
+
236
245
  wrap: function(wrapper) {
237
246
  var __method = this;
238
247
  return function() {
@@ -249,8 +258,6 @@ Object.extend(Function.prototype, {
249
258
  }
250
259
  });
251
260
 
252
- Function.prototype.defer = Function.prototype.delay.curry(0.01);
253
-
254
261
  Date.prototype.toJSON = function() {
255
262
  return '"' + this.getUTCFullYear() + '-' +
256
263
  (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
@@ -351,7 +358,7 @@ Object.extend(String.prototype, {
351
358
 
352
359
  sub: function(pattern, replacement, count) {
353
360
  replacement = this.gsub.prepareReplacement(replacement);
354
- count = count === undefined ? 1 : count;
361
+ count = Object.isUndefined(count) ? 1 : count;
355
362
 
356
363
  return this.gsub(pattern, function(match) {
357
364
  if (--count < 0) return match[0];
@@ -366,7 +373,7 @@ Object.extend(String.prototype, {
366
373
 
367
374
  truncate: function(length, truncation) {
368
375
  length = length || 30;
369
- truncation = truncation === undefined ? '...' : truncation;
376
+ truncation = Object.isUndefined(truncation) ? '...' : truncation;
370
377
  return this.length > length ?
371
378
  this.slice(0, length - truncation.length) + truncation : String(this);
372
379
  },
@@ -486,7 +493,9 @@ Object.extend(String.prototype, {
486
493
  },
487
494
 
488
495
  isJSON: function() {
489
- var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
496
+ var str = this;
497
+ if (str.blank()) return false;
498
+ str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
490
499
  return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
491
500
  },
492
501
 
@@ -529,7 +538,7 @@ if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.proto
529
538
  return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
530
539
  },
531
540
  unescapeHTML: function() {
532
- return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
541
+ return this.stripTags().replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
533
542
  }
534
543
  });
535
544
 
@@ -546,7 +555,7 @@ Object.extend(String.prototype.escapeHTML, {
546
555
  text: document.createTextNode('')
547
556
  });
548
557
 
549
- with (String.prototype.escapeHTML) div.appendChild(text);
558
+ String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text);
550
559
 
551
560
  var Template = Class.create({
552
561
  initialize: function(template, pattern) {
@@ -565,7 +574,8 @@ var Template = Class.create({
565
574
  if (before == '\\') return match[2];
566
575
 
567
576
  var ctx = object, expr = match[3];
568
- var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/, match = pattern.exec(expr);
577
+ var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
578
+ match = pattern.exec(expr);
569
579
  if (match == null) return before;
570
580
 
571
581
  while (match != null) {
@@ -577,7 +587,7 @@ var Template = Class.create({
577
587
  }
578
588
 
579
589
  return before + String.interpret(ctx);
580
- }.bind(this));
590
+ });
581
591
  }
582
592
  });
583
593
  Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
@@ -587,10 +597,9 @@ var $break = { };
587
597
  var Enumerable = {
588
598
  each: function(iterator, context) {
589
599
  var index = 0;
590
- iterator = iterator.bind(context);
591
600
  try {
592
601
  this._each(function(value) {
593
- iterator(value, index++);
602
+ iterator.call(context, value, index++);
594
603
  });
595
604
  } catch (e) {
596
605
  if (e != $break) throw e;
@@ -599,47 +608,46 @@ var Enumerable = {
599
608
  },
600
609
 
601
610
  eachSlice: function(number, iterator, context) {
602
- iterator = iterator ? iterator.bind(context) : Prototype.K;
603
611
  var index = -number, slices = [], array = this.toArray();
612
+ if (number < 1) return array;
604
613
  while ((index += number) < array.length)
605
614
  slices.push(array.slice(index, index+number));
606
615
  return slices.collect(iterator, context);
607
616
  },
608
617
 
609
618
  all: function(iterator, context) {
610
- iterator = iterator ? iterator.bind(context) : Prototype.K;
619
+ iterator = iterator || Prototype.K;
611
620
  var result = true;
612
621
  this.each(function(value, index) {
613
- result = result && !!iterator(value, index);
622
+ result = result && !!iterator.call(context, value, index);
614
623
  if (!result) throw $break;
615
624
  });
616
625
  return result;
617
626
  },
618
627
 
619
628
  any: function(iterator, context) {
620
- iterator = iterator ? iterator.bind(context) : Prototype.K;
629
+ iterator = iterator || Prototype.K;
621
630
  var result = false;
622
631
  this.each(function(value, index) {
623
- if (result = !!iterator(value, index))
632
+ if (result = !!iterator.call(context, value, index))
624
633
  throw $break;
625
634
  });
626
635
  return result;
627
636
  },
628
637
 
629
638
  collect: function(iterator, context) {
630
- iterator = iterator ? iterator.bind(context) : Prototype.K;
639
+ iterator = iterator || Prototype.K;
631
640
  var results = [];
632
641
  this.each(function(value, index) {
633
- results.push(iterator(value, index));
642
+ results.push(iterator.call(context, value, index));
634
643
  });
635
644
  return results;
636
645
  },
637
646
 
638
647
  detect: function(iterator, context) {
639
- iterator = iterator.bind(context);
640
648
  var result;
641
649
  this.each(function(value, index) {
642
- if (iterator(value, index)) {
650
+ if (iterator.call(context, value, index)) {
643
651
  result = value;
644
652
  throw $break;
645
653
  }
@@ -648,17 +656,16 @@ var Enumerable = {
648
656
  },
649
657
 
650
658
  findAll: function(iterator, context) {
651
- iterator = iterator.bind(context);
652
659
  var results = [];
653
660
  this.each(function(value, index) {
654
- if (iterator(value, index))
661
+ if (iterator.call(context, value, index))
655
662
  results.push(value);
656
663
  });
657
664
  return results;
658
665
  },
659
666
 
660
667
  grep: function(filter, iterator, context) {
661
- iterator = iterator ? iterator.bind(context) : Prototype.K;
668
+ iterator = iterator || Prototype.K;
662
669
  var results = [];
663
670
 
664
671
  if (Object.isString(filter))
@@ -666,7 +673,7 @@ var Enumerable = {
666
673
 
667
674
  this.each(function(value, index) {
668
675
  if (filter.match(value))
669
- results.push(iterator(value, index));
676
+ results.push(iterator.call(context, value, index));
670
677
  });
671
678
  return results;
672
679
  },
@@ -686,7 +693,7 @@ var Enumerable = {
686
693
  },
687
694
 
688
695
  inGroupsOf: function(number, fillWith) {
689
- fillWith = fillWith === undefined ? null : fillWith;
696
+ fillWith = Object.isUndefined(fillWith) ? null : fillWith;
690
697
  return this.eachSlice(number, function(slice) {
691
698
  while(slice.length < number) slice.push(fillWith);
692
699
  return slice;
@@ -694,9 +701,8 @@ var Enumerable = {
694
701
  },
695
702
 
696
703
  inject: function(memo, iterator, context) {
697
- iterator = iterator.bind(context);
698
704
  this.each(function(value, index) {
699
- memo = iterator(memo, value, index);
705
+ memo = iterator.call(context, memo, value, index);
700
706
  });
701
707
  return memo;
702
708
  },
@@ -709,32 +715,32 @@ var Enumerable = {
709
715
  },
710
716
 
711
717
  max: function(iterator, context) {
712
- iterator = iterator ? iterator.bind(context) : Prototype.K;
718
+ iterator = iterator || Prototype.K;
713
719
  var result;
714
720
  this.each(function(value, index) {
715
- value = iterator(value, index);
716
- if (result == undefined || value >= result)
721
+ value = iterator.call(context, value, index);
722
+ if (result == null || value >= result)
717
723
  result = value;
718
724
  });
719
725
  return result;
720
726
  },
721
727
 
722
728
  min: function(iterator, context) {
723
- iterator = iterator ? iterator.bind(context) : Prototype.K;
729
+ iterator = iterator || Prototype.K;
724
730
  var result;
725
731
  this.each(function(value, index) {
726
- value = iterator(value, index);
727
- if (result == undefined || value < result)
732
+ value = iterator.call(context, value, index);
733
+ if (result == null || value < result)
728
734
  result = value;
729
735
  });
730
736
  return result;
731
737
  },
732
738
 
733
739
  partition: function(iterator, context) {
734
- iterator = iterator ? iterator.bind(context) : Prototype.K;
740
+ iterator = iterator || Prototype.K;
735
741
  var trues = [], falses = [];
736
742
  this.each(function(value, index) {
737
- (iterator(value, index) ?
743
+ (iterator.call(context, value, index) ?
738
744
  trues : falses).push(value);
739
745
  });
740
746
  return [trues, falses];
@@ -749,19 +755,20 @@ var Enumerable = {
749
755
  },
750
756
 
751
757
  reject: function(iterator, context) {
752
- iterator = iterator.bind(context);
753
758
  var results = [];
754
759
  this.each(function(value, index) {
755
- if (!iterator(value, index))
760
+ if (!iterator.call(context, value, index))
756
761
  results.push(value);
757
762
  });
758
763
  return results;
759
764
  },
760
765
 
761
766
  sortBy: function(iterator, context) {
762
- iterator = iterator.bind(context);
763
767
  return this.map(function(value, index) {
764
- return {value: value, criteria: iterator(value, index)};
768
+ return {
769
+ value: value,
770
+ criteria: iterator.call(context, value, index)
771
+ };
765
772
  }).sort(function(left, right) {
766
773
  var a = left.criteria, b = right.criteria;
767
774
  return a < b ? -1 : a > b ? 1 : 0;
@@ -805,20 +812,24 @@ Object.extend(Enumerable, {
805
812
  function $A(iterable) {
806
813
  if (!iterable) return [];
807
814
  if (iterable.toArray) return iterable.toArray();
808
- var length = iterable.length, results = new Array(length);
815
+ var length = iterable.length || 0, results = new Array(length);
809
816
  while (length--) results[length] = iterable[length];
810
817
  return results;
811
818
  }
812
819
 
813
820
  if (Prototype.Browser.WebKit) {
814
- function $A(iterable) {
821
+ $A = function(iterable) {
815
822
  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);
823
+ // In Safari, only use the `toArray` method if it's not a NodeList.
824
+ // A NodeList is a function, has an function `item` property, and a numeric
825
+ // `length` property. Adapted from Google Doctype.
826
+ if (!(typeof iterable === 'function' && typeof iterable.length ===
827
+ 'number' && typeof iterable.item === 'function') && iterable.toArray)
828
+ return iterable.toArray();
829
+ var length = iterable.length || 0, results = new Array(length);
819
830
  while (length--) results[length] = iterable[length];
820
831
  return results;
821
- }
832
+ };
822
833
  }
823
834
 
824
835
  Array.from = $A;
@@ -904,7 +915,7 @@ Object.extend(Array.prototype, {
904
915
  var results = [];
905
916
  this.each(function(object) {
906
917
  var value = Object.toJSON(object);
907
- if (value !== undefined) results.push(value);
918
+ if (!Object.isUndefined(value)) results.push(value);
908
919
  });
909
920
  return '[' + results.join(', ') + ']';
910
921
  }
@@ -961,8 +972,8 @@ Object.extend(Number.prototype, {
961
972
  return this + 1;
962
973
  },
963
974
 
964
- times: function(iterator) {
965
- $R(0, this, true).each(iterator);
975
+ times: function(iterator, context) {
976
+ $R(0, this, true).each(iterator, context);
966
977
  return this;
967
978
  },
968
979
 
@@ -984,34 +995,6 @@ function $H(object) {
984
995
  };
985
996
 
986
997
  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
- }
1004
- }
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
- }
1015
998
 
1016
999
  function toQueryPair(key, value) {
1017
1000
  if (Object.isUndefined(value)) return key;
@@ -1023,14 +1006,23 @@ var Hash = Class.create(Enumerable, (function() {
1023
1006
  this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
1024
1007
  },
1025
1008
 
1026
- _each: each,
1009
+ _each: function(iterator) {
1010
+ for (var key in this._object) {
1011
+ var value = this._object[key], pair = [key, value];
1012
+ pair.key = key;
1013
+ pair.value = value;
1014
+ iterator(pair);
1015
+ }
1016
+ },
1027
1017
 
1028
1018
  set: function(key, value) {
1029
1019
  return this._object[key] = value;
1030
1020
  },
1031
1021
 
1032
1022
  get: function(key) {
1033
- return this._object[key];
1023
+ // simulating poorly supported hasOwnProperty
1024
+ if (this._object[key] !== Object.prototype[key])
1025
+ return this._object[key];
1034
1026
  },
1035
1027
 
1036
1028
  unset: function(key) {
@@ -1070,14 +1062,14 @@ var Hash = Class.create(Enumerable, (function() {
1070
1062
  },
1071
1063
 
1072
1064
  toQueryString: function() {
1073
- return this.map(function(pair) {
1065
+ return this.inject([], function(results, pair) {
1074
1066
  var key = encodeURIComponent(pair.key), values = pair.value;
1075
1067
 
1076
1068
  if (values && typeof values == 'object') {
1077
1069
  if (Object.isArray(values))
1078
- return values.map(toQueryPair.curry(key)).join('&');
1079
- }
1080
- return toQueryPair(key, values);
1070
+ return results.concat(values.map(toQueryPair.curry(key)));
1071
+ } else results.push(toQueryPair(key, values));
1072
+ return results;
1081
1073
  }).join('&');
1082
1074
  },
1083
1075
 
@@ -1187,8 +1179,11 @@ Ajax.Base = Class.create({
1187
1179
  Object.extend(this.options, options || { });
1188
1180
 
1189
1181
  this.options.method = this.options.method.toLowerCase();
1182
+
1190
1183
  if (Object.isString(this.options.parameters))
1191
1184
  this.options.parameters = this.options.parameters.toQueryParams();
1185
+ else if (Object.isHash(this.options.parameters))
1186
+ this.options.parameters = this.options.parameters.toObject();
1192
1187
  }
1193
1188
  });
1194
1189
 
@@ -1315,7 +1310,7 @@ Ajax.Request = Class.create(Ajax.Base, {
1315
1310
 
1316
1311
  var contentType = response.getHeader('Content-type');
1317
1312
  if (this.options.evalJS == 'force'
1318
- || (this.options.evalJS && contentType
1313
+ || (this.options.evalJS && this.isSameOrigin() && contentType
1319
1314
  && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
1320
1315
  this.evalResponse();
1321
1316
  }
@@ -1333,9 +1328,18 @@ Ajax.Request = Class.create(Ajax.Base, {
1333
1328
  }
1334
1329
  },
1335
1330
 
1331
+ isSameOrigin: function() {
1332
+ var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
1333
+ return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
1334
+ protocol: location.protocol,
1335
+ domain: document.domain,
1336
+ port: location.port ? ':' + location.port : ''
1337
+ }));
1338
+ },
1339
+
1336
1340
  getHeader: function(name) {
1337
1341
  try {
1338
- return this.transport.getResponseHeader(name);
1342
+ return this.transport.getResponseHeader(name) || null;
1339
1343
  } catch (e) { return null }
1340
1344
  },
1341
1345
 
@@ -1371,7 +1375,7 @@ Ajax.Response = Class.create({
1371
1375
 
1372
1376
  if(readyState == 4) {
1373
1377
  var xml = transport.responseXML;
1374
- this.responseXML = xml === undefined ? null : xml;
1378
+ this.responseXML = Object.isUndefined(xml) ? null : xml;
1375
1379
  this.responseJSON = this._getResponseJSON();
1376
1380
  }
1377
1381
  },
@@ -1408,7 +1412,8 @@ Ajax.Response = Class.create({
1408
1412
  if (!json) return null;
1409
1413
  json = decodeURIComponent(escape(json));
1410
1414
  try {
1411
- return json.evalJSON(this.request.options.sanitizeJSON);
1415
+ return json.evalJSON(this.request.options.sanitizeJSON ||
1416
+ !this.request.isSameOrigin());
1412
1417
  } catch (e) {
1413
1418
  this.request.dispatchException(e);
1414
1419
  }
@@ -1417,10 +1422,12 @@ Ajax.Response = Class.create({
1417
1422
  _getResponseJSON: function() {
1418
1423
  var options = this.request.options;
1419
1424
  if (!options.evalJSON || (options.evalJSON != 'force' &&
1420
- !(this.getHeader('Content-type') || '').include('application/json')))
1421
- return null;
1425
+ !(this.getHeader('Content-type') || '').include('application/json')) ||
1426
+ this.responseText.blank())
1427
+ return null;
1422
1428
  try {
1423
- return this.transport.responseText.evalJSON(options.sanitizeJSON);
1429
+ return this.responseText.evalJSON(options.sanitizeJSON ||
1430
+ !this.request.isSameOrigin());
1424
1431
  } catch (e) {
1425
1432
  this.request.dispatchException(e);
1426
1433
  }
@@ -1434,11 +1441,11 @@ Ajax.Updater = Class.create(Ajax.Request, {
1434
1441
  failure: (container.failure || (container.success ? null : container))
1435
1442
  };
1436
1443
 
1437
- options = options || { };
1444
+ options = Object.clone(options);
1438
1445
  var onComplete = options.onComplete;
1439
- options.onComplete = (function(response, param) {
1446
+ options.onComplete = (function(response, json) {
1440
1447
  this.updateContent(response.responseText);
1441
- if (Object.isFunction(onComplete)) onComplete(response, param);
1448
+ if (Object.isFunction(onComplete)) onComplete(response, json);
1442
1449
  }).bind(this);
1443
1450
 
1444
1451
  $super(url, options);
@@ -1460,10 +1467,6 @@ Ajax.Updater = Class.create(Ajax.Request, {
1460
1467
  }
1461
1468
  else receiver.update(responseText);
1462
1469
  }
1463
-
1464
- if (this.success()) {
1465
- if (this.onComplete) this.onComplete.bind(this).defer();
1466
- }
1467
1470
  }
1468
1471
  });
1469
1472
 
@@ -1566,6 +1569,7 @@ if (!Node.ELEMENT_NODE) {
1566
1569
  return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
1567
1570
  };
1568
1571
  Object.extend(this.Element, element || { });
1572
+ if (element) this.Element.prototype = element.prototype;
1569
1573
  }).call(window);
1570
1574
 
1571
1575
  Element.cache = { };
@@ -1582,12 +1586,14 @@ Element.Methods = {
1582
1586
  },
1583
1587
 
1584
1588
  hide: function(element) {
1585
- $(element).style.display = 'none';
1589
+ element = $(element);
1590
+ element.style.display = 'none';
1586
1591
  return element;
1587
1592
  },
1588
1593
 
1589
1594
  show: function(element) {
1590
- $(element).style.display = '';
1595
+ element = $(element);
1596
+ element.style.display = '';
1591
1597
  return element;
1592
1598
  },
1593
1599
 
@@ -1628,24 +1634,28 @@ Element.Methods = {
1628
1634
  Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
1629
1635
  insertions = {bottom:insertions};
1630
1636
 
1631
- var content, t, range;
1637
+ var content, insert, tagName, childNodes;
1632
1638
 
1633
- for (position in insertions) {
1639
+ for (var position in insertions) {
1634
1640
  content = insertions[position];
1635
1641
  position = position.toLowerCase();
1636
- t = Element._insertionTranslations[position];
1642
+ insert = Element._insertionTranslations[position];
1637
1643
 
1638
1644
  if (content && content.toElement) content = content.toElement();
1639
1645
  if (Object.isElement(content)) {
1640
- t.insert(element, content);
1646
+ insert(element, content);
1641
1647
  continue;
1642
1648
  }
1643
1649
 
1644
1650
  content = Object.toHTML(content);
1645
1651
 
1646
- range = element.ownerDocument.createRange();
1647
- t.initializeRange(element, range);
1648
- t.insert(element, range.createContextualFragment(content.stripScripts()));
1652
+ tagName = ((position == 'before' || position == 'after')
1653
+ ? element.parentNode : element).tagName.toUpperCase();
1654
+
1655
+ childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
1656
+
1657
+ if (position == 'top' || position == 'after') childNodes.reverse();
1658
+ childNodes.each(insert.curry(element));
1649
1659
 
1650
1660
  content.evalScripts.bind(content).defer();
1651
1661
  }
@@ -1690,7 +1700,7 @@ Element.Methods = {
1690
1700
  },
1691
1701
 
1692
1702
  descendants: function(element) {
1693
- return $A($(element).getElementsByTagName('*')).each(Element.extend);
1703
+ return $(element).select("*");
1694
1704
  },
1695
1705
 
1696
1706
  firstDescendant: function(element) {
@@ -1729,32 +1739,31 @@ Element.Methods = {
1729
1739
  element = $(element);
1730
1740
  if (arguments.length == 1) return $(element.parentNode);
1731
1741
  var ancestors = element.ancestors();
1732
- return expression ? Selector.findElement(ancestors, expression, index) :
1733
- ancestors[index || 0];
1742
+ return Object.isNumber(expression) ? ancestors[expression] :
1743
+ Selector.findElement(ancestors, expression, index);
1734
1744
  },
1735
1745
 
1736
1746
  down: function(element, expression, index) {
1737
1747
  element = $(element);
1738
1748
  if (arguments.length == 1) return element.firstDescendant();
1739
- var descendants = element.descendants();
1740
- return expression ? Selector.findElement(descendants, expression, index) :
1741
- descendants[index || 0];
1749
+ return Object.isNumber(expression) ? element.descendants()[expression] :
1750
+ Element.select(element, expression)[index || 0];
1742
1751
  },
1743
1752
 
1744
1753
  previous: function(element, expression, index) {
1745
1754
  element = $(element);
1746
1755
  if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
1747
1756
  var previousSiblings = element.previousSiblings();
1748
- return expression ? Selector.findElement(previousSiblings, expression, index) :
1749
- previousSiblings[index || 0];
1757
+ return Object.isNumber(expression) ? previousSiblings[expression] :
1758
+ Selector.findElement(previousSiblings, expression, index);
1750
1759
  },
1751
1760
 
1752
1761
  next: function(element, expression, index) {
1753
1762
  element = $(element);
1754
1763
  if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
1755
1764
  var nextSiblings = element.nextSiblings();
1756
- return expression ? Selector.findElement(nextSiblings, expression, index) :
1757
- nextSiblings[index || 0];
1765
+ return Object.isNumber(expression) ? nextSiblings[expression] :
1766
+ Selector.findElement(nextSiblings, expression, index);
1758
1767
  },
1759
1768
 
1760
1769
  select: function() {
@@ -1795,10 +1804,11 @@ Element.Methods = {
1795
1804
  var attributes = { }, t = Element._attributeTranslations.write;
1796
1805
 
1797
1806
  if (typeof name == 'object') attributes = name;
1798
- else attributes[name] = value === undefined ? true : value;
1807
+ else attributes[name] = Object.isUndefined(value) ? true : value;
1799
1808
 
1800
1809
  for (var attr in attributes) {
1801
- var name = t.names[attr] || attr, value = attributes[attr];
1810
+ name = t.names[attr] || attr;
1811
+ value = attributes[attr];
1802
1812
  if (t.values[attr]) name = t.values[attr](element, value);
1803
1813
  if (value === false || value === null)
1804
1814
  element.removeAttribute(name);
@@ -1871,18 +1881,12 @@ Element.Methods = {
1871
1881
  if (element.compareDocumentPosition)
1872
1882
  return (element.compareDocumentPosition(ancestor) & 8) === 8;
1873
1883
 
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
- }
1884
+ if (ancestor.contains)
1885
+ return ancestor.contains(element) && ancestor !== element;
1883
1886
 
1884
1887
  while (element = element.parentNode)
1885
1888
  if (element == ancestor) return true;
1889
+
1886
1890
  return false;
1887
1891
  },
1888
1892
 
@@ -1897,7 +1901,7 @@ Element.Methods = {
1897
1901
  element = $(element);
1898
1902
  style = style == 'float' ? 'cssFloat' : style.camelize();
1899
1903
  var value = element.style[style];
1900
- if (!value) {
1904
+ if (!value || value == 'auto') {
1901
1905
  var css = document.defaultView.getComputedStyle(element, null);
1902
1906
  value = css ? css[style] : null;
1903
1907
  }
@@ -1921,7 +1925,7 @@ Element.Methods = {
1921
1925
  if (property == 'opacity') element.setOpacity(styles[property]);
1922
1926
  else
1923
1927
  elementStyle[(property == 'float' || property == 'cssFloat') ?
1924
- (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
1928
+ (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
1925
1929
  property] = styles[property];
1926
1930
 
1927
1931
  return element;
@@ -1936,7 +1940,7 @@ Element.Methods = {
1936
1940
 
1937
1941
  getDimensions: function(element) {
1938
1942
  element = $(element);
1939
- var display = $(element).getStyle('display');
1943
+ var display = element.getStyle('display');
1940
1944
  if (display != 'none' && display != null) // Safari bug
1941
1945
  return {width: element.offsetWidth, height: element.offsetHeight};
1942
1946
 
@@ -1965,7 +1969,7 @@ Element.Methods = {
1965
1969
  element.style.position = 'relative';
1966
1970
  // Opera returns the offset relative to the positioning context, when an
1967
1971
  // element is position relative but top and left have not been defined
1968
- if (window.opera) {
1972
+ if (Prototype.Browser.Opera) {
1969
1973
  element.style.top = 0;
1970
1974
  element.style.left = 0;
1971
1975
  }
@@ -2020,9 +2024,9 @@ Element.Methods = {
2020
2024
  valueL += element.offsetLeft || 0;
2021
2025
  element = element.offsetParent;
2022
2026
  if (element) {
2023
- if (element.tagName == 'BODY') break;
2027
+ if (element.tagName.toUpperCase() == 'BODY') break;
2024
2028
  var p = Element.getStyle(element, 'position');
2025
- if (p == 'relative' || p == 'absolute') break;
2029
+ if (p !== 'static') break;
2026
2030
  }
2027
2031
  } while (element);
2028
2032
  return Element._returnOffset(valueL, valueT);
@@ -2030,7 +2034,7 @@ Element.Methods = {
2030
2034
 
2031
2035
  absolutize: function(element) {
2032
2036
  element = $(element);
2033
- if (element.getStyle('position') == 'absolute') return;
2037
+ if (element.getStyle('position') == 'absolute') return element;
2034
2038
  // Position.prepare(); // To be done manually by Scripty when it needs it.
2035
2039
 
2036
2040
  var offsets = element.positionedOffset();
@@ -2054,7 +2058,7 @@ Element.Methods = {
2054
2058
 
2055
2059
  relativize: function(element) {
2056
2060
  element = $(element);
2057
- if (element.getStyle('position') == 'relative') return;
2061
+ if (element.getStyle('position') == 'relative') return element;
2058
2062
  // Position.prepare(); // To be done manually by Scripty when it needs it.
2059
2063
 
2060
2064
  element.style.position = 'relative';
@@ -2105,7 +2109,7 @@ Element.Methods = {
2105
2109
 
2106
2110
  element = forElement;
2107
2111
  do {
2108
- if (!Prototype.Browser.Opera || element.tagName == 'BODY') {
2112
+ if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) {
2109
2113
  valueT -= element.scrollTop || 0;
2110
2114
  valueL -= element.scrollLeft || 0;
2111
2115
  }
@@ -2171,72 +2175,80 @@ Element._attributeTranslations = {
2171
2175
  }
2172
2176
  };
2173
2177
 
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));
2178
+ if (Prototype.Browser.Opera) {
2179
+ Element.Methods.getStyle = Element.Methods.getStyle.wrap(
2180
+ function(proceed, element, style) {
2181
+ switch (style) {
2182
+ case 'left': case 'top': case 'right': case 'bottom':
2183
+ if (proceed(element, 'position') === 'static') return null;
2184
+ case 'height': case 'width':
2185
+ // returns '0px' for hidden elements; we want it to return null
2186
+ if (!Element.visible(element)) return null;
2187
+
2188
+ // returns the border-box dimensions rather than the content-box
2189
+ // dimensions, so we subtract padding and borders from the value
2190
+ var dim = parseInt(proceed(element, style), 10);
2191
+
2192
+ if (dim !== element['offset' + style.capitalize()])
2193
+ return dim + 'px';
2194
+
2195
+ var properties;
2196
+ if (style === 'height') {
2197
+ properties = ['border-top-width', 'padding-top',
2198
+ 'padding-bottom', 'border-bottom-width'];
2199
+ }
2200
+ else {
2201
+ properties = ['border-left-width', 'padding-left',
2202
+ 'padding-right', 'border-right-width'];
2203
+ }
2204
+ return properties.inject(dim, function(memo, property) {
2205
+ var val = proceed(element, property);
2206
+ return val === null ? memo : memo - parseInt(val, 10);
2207
+ }) + 'px';
2208
+ default: return proceed(element, style);
2204
2209
  }
2205
- else element.insertAdjacentHTML(pos.adjacency, content.stripScripts());
2206
-
2207
- content.evalScripts.bind(content).defer();
2208
2210
  }
2211
+ );
2209
2212
 
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);
2213
+ Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
2214
+ function(proceed, element, attribute) {
2215
+ if (attribute === 'title') return element.title;
2216
+ return proceed(element, attribute);
2224
2217
  }
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
- };
2218
+ );
2231
2219
  }
2232
2220
 
2233
2221
  else if (Prototype.Browser.IE) {
2234
- $w('positionedOffset getOffsetParent viewportOffset').each(function(method) {
2222
+ // IE doesn't report offsets correctly for static elements, so we change them
2223
+ // to "relative" to get the values, then change them back.
2224
+ Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
2225
+ function(proceed, element) {
2226
+ element = $(element);
2227
+ // IE throws an error if element is not in document
2228
+ try { element.offsetParent }
2229
+ catch(e) { return $(document.body) }
2230
+ var position = element.getStyle('position');
2231
+ if (position !== 'static') return proceed(element);
2232
+ element.setStyle({ position: 'relative' });
2233
+ var value = proceed(element);
2234
+ element.setStyle({ position: position });
2235
+ return value;
2236
+ }
2237
+ );
2238
+
2239
+ $w('positionedOffset viewportOffset').each(function(method) {
2235
2240
  Element.Methods[method] = Element.Methods[method].wrap(
2236
2241
  function(proceed, element) {
2237
2242
  element = $(element);
2243
+ try { element.offsetParent }
2244
+ catch(e) { return Element._returnOffset(0,0) }
2238
2245
  var position = element.getStyle('position');
2239
- if (position != 'static') return proceed(element);
2246
+ if (position !== 'static') return proceed(element);
2247
+ // Trigger hasLayout on the offset parent so that IE6 reports
2248
+ // accurate offsetTop and offsetLeft values for position: fixed.
2249
+ var offsetParent = element.getOffsetParent();
2250
+ if (offsetParent && offsetParent.getStyle('position') === 'fixed')
2251
+ offsetParent.setStyle({ zoom: 1 });
2240
2252
  element.setStyle({ position: 'relative' });
2241
2253
  var value = proceed(element);
2242
2254
  element.setStyle({ position: position });
@@ -2245,6 +2257,14 @@ else if (Prototype.Browser.IE) {
2245
2257
  );
2246
2258
  });
2247
2259
 
2260
+ Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap(
2261
+ function(proceed, element) {
2262
+ try { element.offsetParent }
2263
+ catch(e) { return Element._returnOffset(0,0) }
2264
+ return proceed(element);
2265
+ }
2266
+ );
2267
+
2248
2268
  Element.Methods.getStyle = function(element, style) {
2249
2269
  element = $(element);
2250
2270
  style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
@@ -2301,7 +2321,7 @@ else if (Prototype.Browser.IE) {
2301
2321
  return node ? node.value : "";
2302
2322
  },
2303
2323
  _getEv: function(element, attribute) {
2304
- var attribute = element.getAttribute(attribute);
2324
+ attribute = element.getAttribute(attribute);
2305
2325
  return attribute ? attribute.toString().slice(23, -2) : null;
2306
2326
  },
2307
2327
  _flag: function(element, attribute) {
@@ -2318,7 +2338,10 @@ else if (Prototype.Browser.IE) {
2318
2338
  };
2319
2339
 
2320
2340
  Element._attributeTranslations.write = {
2321
- names: Object.clone(Element._attributeTranslations.read.names),
2341
+ names: Object.extend({
2342
+ cellpadding: 'cellPadding',
2343
+ cellspacing: 'cellSpacing'
2344
+ }, Element._attributeTranslations.read.names),
2322
2345
  values: {
2323
2346
  checked: function(element, value) {
2324
2347
  element.checked = !!value;
@@ -2333,7 +2356,7 @@ else if (Prototype.Browser.IE) {
2333
2356
  Element._attributeTranslations.has = {};
2334
2357
 
2335
2358
  $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
2336
- 'encType maxLength readOnly longDesc').each(function(attr) {
2359
+ 'encType maxLength readOnly longDesc frameBorder').each(function(attr) {
2337
2360
  Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
2338
2361
  Element._attributeTranslations.has[attr.toLowerCase()] = attr;
2339
2362
  });
@@ -2386,7 +2409,7 @@ else if (Prototype.Browser.WebKit) {
2386
2409
  (value < 0.00001) ? 0 : value;
2387
2410
 
2388
2411
  if (value == 1)
2389
- if(element.tagName == 'IMG' && element.width) {
2412
+ if(element.tagName.toUpperCase() == 'IMG' && element.width) {
2390
2413
  element.width++; element.width--;
2391
2414
  } else try {
2392
2415
  var n = document.createTextNode(' ');
@@ -2398,7 +2421,7 @@ else if (Prototype.Browser.WebKit) {
2398
2421
  };
2399
2422
 
2400
2423
  // Safari returns margins on body which is incorrect if the child is absolutely
2401
- // positioned. For performance reasons, redefine Position.cumulativeOffset for
2424
+ // positioned. For performance reasons, redefine Element#cumulativeOffset for
2402
2425
  // KHTML/WebKit only.
2403
2426
  Element.Methods.cumulativeOffset = function(element) {
2404
2427
  var valueT = 0, valueL = 0;
@@ -2438,7 +2461,7 @@ if (Prototype.Browser.IE || Prototype.Browser.Opera) {
2438
2461
  };
2439
2462
  }
2440
2463
 
2441
- if (document.createElement('div').outerHTML) {
2464
+ if ('outerHTML' in document.createElement('div')) {
2442
2465
  Element.Methods.replace = function(element, content) {
2443
2466
  element = $(element);
2444
2467
 
@@ -2476,45 +2499,25 @@ Element._returnOffset = function(l, t) {
2476
2499
 
2477
2500
  Element._getContentFromAnonymousElement = function(tagName, html) {
2478
2501
  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 });
2502
+ if (t) {
2503
+ div.innerHTML = t[0] + html + t[1];
2504
+ t[2].times(function() { div = div.firstChild });
2505
+ } else div.innerHTML = html;
2481
2506
  return $A(div.childNodes);
2482
2507
  };
2483
2508
 
2484
2509
  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
- }
2510
+ before: function(element, node) {
2511
+ element.parentNode.insertBefore(node, element);
2493
2512
  },
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
- }
2513
+ top: function(element, node) {
2514
+ element.insertBefore(node, element.firstChild);
2503
2515
  },
2504
- bottom: {
2505
- adjacency: 'beforeEnd',
2506
- insert: function(element, node) {
2507
- element.appendChild(node);
2508
- }
2516
+ bottom: function(element, node) {
2517
+ element.appendChild(node);
2509
2518
  },
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
- }
2519
+ after: function(element, node) {
2520
+ element.parentNode.insertBefore(node, element.nextSibling);
2518
2521
  },
2519
2522
  tags: {
2520
2523
  TABLE: ['<table>', '</table>', 1],
@@ -2526,7 +2529,6 @@ Element._insertionTranslations = {
2526
2529
  };
2527
2530
 
2528
2531
  (function() {
2529
- this.bottom.initializeRange = this.top.initializeRange;
2530
2532
  Object.extend(this.tags, {
2531
2533
  THEAD: this.tags.TBODY,
2532
2534
  TFOOT: this.tags.TBODY,
@@ -2538,7 +2540,7 @@ Element.Methods.Simulated = {
2538
2540
  hasAttribute: function(element, attribute) {
2539
2541
  attribute = Element._attributeTranslations.has[attribute] || attribute;
2540
2542
  var node = $(element).getAttributeNode(attribute);
2541
- return node && node.specified;
2543
+ return !!(node && node.specified);
2542
2544
  }
2543
2545
  };
2544
2546
 
@@ -2547,9 +2549,9 @@ Element.Methods.ByTag = { };
2547
2549
  Object.extend(Element, Element.Methods);
2548
2550
 
2549
2551
  if (!Prototype.BrowserFeatures.ElementExtensions &&
2550
- document.createElement('div').__proto__) {
2552
+ document.createElement('div')['__proto__']) {
2551
2553
  window.HTMLElement = { };
2552
- window.HTMLElement.prototype = document.createElement('div').__proto__;
2554
+ window.HTMLElement.prototype = document.createElement('div')['__proto__'];
2553
2555
  Prototype.BrowserFeatures.ElementExtensions = true;
2554
2556
  }
2555
2557
 
@@ -2564,7 +2566,7 @@ Element.extend = (function() {
2564
2566
  element.nodeType != 1 || element == window) return element;
2565
2567
 
2566
2568
  var methods = Object.clone(Methods),
2567
- tagName = element.tagName, property, value;
2569
+ tagName = element.tagName.toUpperCase(), property, value;
2568
2570
 
2569
2571
  // extend methods for specific tags
2570
2572
  if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
@@ -2660,7 +2662,7 @@ Element.addMethods = function(methods) {
2660
2662
  if (window[klass]) return window[klass];
2661
2663
 
2662
2664
  window[klass] = { };
2663
- window[klass].prototype = document.createElement(tagName).__proto__;
2665
+ window[klass].prototype = document.createElement(tagName)['__proto__'];
2664
2666
  return window[klass];
2665
2667
  }
2666
2668
 
@@ -2686,11 +2688,18 @@ Element.addMethods = function(methods) {
2686
2688
 
2687
2689
  document.viewport = {
2688
2690
  getDimensions: function() {
2689
- var dimensions = { };
2691
+ var dimensions = { }, B = Prototype.Browser;
2690
2692
  $w('width height').each(function(d) {
2691
2693
  var D = d.capitalize();
2692
- dimensions[d] = self['inner' + D] ||
2693
- (document.documentElement['client' + D] || document.body['client' + D]);
2694
+ if (B.WebKit && !document.evaluate) {
2695
+ // Safari <3.0 needs self.innerWidth/Height
2696
+ dimensions[d] = self['inner' + D];
2697
+ } else if (B.Opera && parseFloat(window.opera.version()) < 9.5) {
2698
+ // Opera <9.5 needs document.body.clientWidth/Height
2699
+ dimensions[d] = document.body['client' + D]
2700
+ } else {
2701
+ dimensions[d] = document.documentElement['client' + D];
2702
+ }
2694
2703
  });
2695
2704
  return dimensions;
2696
2705
  },
@@ -2709,21 +2718,61 @@ document.viewport = {
2709
2718
  window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
2710
2719
  }
2711
2720
  };
2712
- /* Portions of the Selector class are derived from Jack Slocums DomQuery,
2721
+ /* Portions of the Selector class are derived from Jack Slocum's DomQuery,
2713
2722
  * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
2714
2723
  * license. Please see http://www.yui-ext.com/ for more information. */
2715
2724
 
2716
2725
  var Selector = Class.create({
2717
2726
  initialize: function(expression) {
2718
2727
  this.expression = expression.strip();
2719
- this.compileMatcher();
2728
+
2729
+ if (this.shouldUseSelectorsAPI()) {
2730
+ this.mode = 'selectorsAPI';
2731
+ } else if (this.shouldUseXPath()) {
2732
+ this.mode = 'xpath';
2733
+ this.compileXPathMatcher();
2734
+ } else {
2735
+ this.mode = "normal";
2736
+ this.compileMatcher();
2737
+ }
2738
+
2720
2739
  },
2721
2740
 
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();
2741
+ shouldUseXPath: function() {
2742
+ if (!Prototype.BrowserFeatures.XPath) return false;
2743
+
2744
+ var e = this.expression;
2745
+
2746
+ // Safari 3 chokes on :*-of-type and :empty
2747
+ if (Prototype.Browser.WebKit &&
2748
+ (e.include("-of-type") || e.include(":empty")))
2749
+ return false;
2726
2750
 
2751
+ // XPath can't do namespaced attributes, nor can it read
2752
+ // the "checked" property from DOM nodes
2753
+ if ((/(\[[\w-]*?:|:checked)/).test(e))
2754
+ return false;
2755
+
2756
+ return true;
2757
+ },
2758
+
2759
+ shouldUseSelectorsAPI: function() {
2760
+ if (!Prototype.BrowserFeatures.SelectorsAPI) return false;
2761
+
2762
+ if (!Selector._div) Selector._div = new Element('div');
2763
+
2764
+ // Make sure the browser treats the selector as valid. Test on an
2765
+ // isolated element to minimize cost of this check.
2766
+ try {
2767
+ Selector._div.querySelector(this.expression);
2768
+ } catch(e) {
2769
+ return false;
2770
+ }
2771
+
2772
+ return true;
2773
+ },
2774
+
2775
+ compileMatcher: function() {
2727
2776
  var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
2728
2777
  c = Selector.criteria, le, p, m;
2729
2778
 
@@ -2741,7 +2790,7 @@ var Selector = Class.create({
2741
2790
  p = ps[i];
2742
2791
  if (m = e.match(p)) {
2743
2792
  this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
2744
- new Template(c[i]).evaluate(m));
2793
+ new Template(c[i]).evaluate(m));
2745
2794
  e = e.replace(m[0], '');
2746
2795
  break;
2747
2796
  }
@@ -2780,8 +2829,27 @@ var Selector = Class.create({
2780
2829
 
2781
2830
  findElements: function(root) {
2782
2831
  root = root || document;
2783
- if (this.xpath) return document._getElementsByXPath(this.xpath, root);
2784
- return this.matcher(root);
2832
+ var e = this.expression, results;
2833
+
2834
+ switch (this.mode) {
2835
+ case 'selectorsAPI':
2836
+ // querySelectorAll queries document-wide, then filters to descendants
2837
+ // of the context element. That's not what we want.
2838
+ // Add an explicit context to the selector if necessary.
2839
+ if (root !== document) {
2840
+ var oldId = root.id, id = $(root).identify();
2841
+ e = "#" + id + " " + e;
2842
+ }
2843
+
2844
+ results = $A(root.querySelectorAll(e)).map(Element.extend);
2845
+ root.id = oldId;
2846
+
2847
+ return results;
2848
+ case 'xpath':
2849
+ return document._getElementsByXPath(this.xpath, root);
2850
+ default:
2851
+ return this.matcher(root);
2852
+ }
2785
2853
  },
2786
2854
 
2787
2855
  match: function(element) {
@@ -2844,8 +2912,12 @@ Object.extend(Selector, {
2844
2912
  },
2845
2913
  className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
2846
2914
  id: "[@id='#{1}']",
2847
- attrPresence: "[@#{1}]",
2915
+ attrPresence: function(m) {
2916
+ m[1] = m[1].toLowerCase();
2917
+ return new Template("[@#{1}]").evaluate(m);
2918
+ },
2848
2919
  attr: function(m) {
2920
+ m[1] = m[1].toLowerCase();
2849
2921
  m[3] = m[5] || m[6];
2850
2922
  return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
2851
2923
  },
@@ -2868,13 +2940,13 @@ Object.extend(Selector, {
2868
2940
  'first-child': '[not(preceding-sibling::*)]',
2869
2941
  'last-child': '[not(following-sibling::*)]',
2870
2942
  'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
2871
- 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
2943
+ 'empty': "[count(*) = 0 and (count(text()) = 0)]",
2872
2944
  'checked': "[@checked]",
2873
- 'disabled': "[@disabled]",
2874
- 'enabled': "[not(@disabled)]",
2945
+ 'disabled': "[(@disabled) and (@type!='hidden')]",
2946
+ 'enabled': "[not(@disabled) and (@type!='hidden')]",
2875
2947
  'not': function(m) {
2876
2948
  var e = m[6], p = Selector.patterns,
2877
- x = Selector.xpath, le, m, v;
2949
+ x = Selector.xpath, le, v;
2878
2950
 
2879
2951
  var exclusion = [];
2880
2952
  while (e && le != e && (/\S/).test(e)) {
@@ -2931,13 +3003,13 @@ Object.extend(Selector, {
2931
3003
  },
2932
3004
 
2933
3005
  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;',
3006
+ tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
3007
+ className: 'n = h.className(n, r, "#{1}", c); c = false;',
3008
+ id: 'n = h.id(n, r, "#{1}", c); c = false;',
3009
+ attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;',
2938
3010
  attr: function(m) {
2939
3011
  m[3] = (m[5] || m[6]);
2940
- return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
3012
+ return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);
2941
3013
  },
2942
3014
  pseudo: function(m) {
2943
3015
  if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
@@ -2961,8 +3033,9 @@ Object.extend(Selector, {
2961
3033
  tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
2962
3034
  id: /^#([\w\-\*]+)(\b|$)/,
2963
3035
  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]+)\]/,
3036
+ pseudo:
3037
+ /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,
3038
+ attrPresence: /^\[((?:[\w]+:)?[\w]+)\]/,
2966
3039
  attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
2967
3040
  },
2968
3041
 
@@ -2986,7 +3059,7 @@ Object.extend(Selector, {
2986
3059
 
2987
3060
  attr: function(element, matches) {
2988
3061
  var nodeValue = Element.readAttribute(element, matches[1]);
2989
- return Selector.operators[matches[2]](nodeValue, matches[3]);
3062
+ return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);
2990
3063
  }
2991
3064
  },
2992
3065
 
@@ -3001,14 +3074,15 @@ Object.extend(Selector, {
3001
3074
 
3002
3075
  // marks an array of nodes for counting
3003
3076
  mark: function(nodes) {
3077
+ var _true = Prototype.emptyFunction;
3004
3078
  for (var i = 0, node; node = nodes[i]; i++)
3005
- node._counted = true;
3079
+ node._countedByPrototype = _true;
3006
3080
  return nodes;
3007
3081
  },
3008
3082
 
3009
3083
  unmark: function(nodes) {
3010
3084
  for (var i = 0, node; node = nodes[i]; i++)
3011
- node._counted = undefined;
3085
+ node._countedByPrototype = undefined;
3012
3086
  return nodes;
3013
3087
  },
3014
3088
 
@@ -3016,15 +3090,15 @@ Object.extend(Selector, {
3016
3090
  // "ofType" flag indicates whether we're indexing for nth-of-type
3017
3091
  // rather than nth-child
3018
3092
  index: function(parentNode, reverse, ofType) {
3019
- parentNode._counted = true;
3093
+ parentNode._countedByPrototype = Prototype.emptyFunction;
3020
3094
  if (reverse) {
3021
3095
  for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
3022
3096
  var node = nodes[i];
3023
- if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
3097
+ if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
3024
3098
  }
3025
3099
  } else {
3026
3100
  for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
3027
- if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
3101
+ if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
3028
3102
  }
3029
3103
  },
3030
3104
 
@@ -3033,8 +3107,8 @@ Object.extend(Selector, {
3033
3107
  if (nodes.length == 0) return nodes;
3034
3108
  var results = [], n;
3035
3109
  for (var i = 0, l = nodes.length; i < l; i++)
3036
- if (!(n = nodes[i])._counted) {
3037
- n._counted = true;
3110
+ if (!(n = nodes[i])._countedByPrototype) {
3111
+ n._countedByPrototype = Prototype.emptyFunction;
3038
3112
  results.push(Element.extend(n));
3039
3113
  }
3040
3114
  return Selector.handlers.unmark(results);
@@ -3051,7 +3125,7 @@ Object.extend(Selector, {
3051
3125
  child: function(nodes) {
3052
3126
  var h = Selector.handlers;
3053
3127
  for (var i = 0, results = [], node; node = nodes[i]; i++) {
3054
- for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
3128
+ for (var j = 0, child; child = node.childNodes[j]; j++)
3055
3129
  if (child.nodeType == 1 && child.tagName != '!') results.push(child);
3056
3130
  }
3057
3131
  return results;
@@ -3074,7 +3148,7 @@ Object.extend(Selector, {
3074
3148
 
3075
3149
  nextElementSibling: function(node) {
3076
3150
  while (node = node.nextSibling)
3077
- if (node.nodeType == 1) return node;
3151
+ if (node.nodeType == 1) return node;
3078
3152
  return null;
3079
3153
  },
3080
3154
 
@@ -3086,7 +3160,7 @@ Object.extend(Selector, {
3086
3160
 
3087
3161
  // TOKEN FUNCTIONS
3088
3162
  tagName: function(nodes, root, tagName, combinator) {
3089
- tagName = tagName.toUpperCase();
3163
+ var uTagName = tagName.toUpperCase();
3090
3164
  var results = [], h = Selector.handlers;
3091
3165
  if (nodes) {
3092
3166
  if (combinator) {
@@ -3099,7 +3173,7 @@ Object.extend(Selector, {
3099
3173
  if (tagName == "*") return nodes;
3100
3174
  }
3101
3175
  for (var i = 0, node; node = nodes[i]; i++)
3102
- if (node.tagName.toUpperCase() == tagName) results.push(node);
3176
+ if (node.tagName.toUpperCase() === uTagName) results.push(node);
3103
3177
  return results;
3104
3178
  } else return root.getElementsByTagName(tagName);
3105
3179
  },
@@ -3146,16 +3220,18 @@ Object.extend(Selector, {
3146
3220
  return results;
3147
3221
  },
3148
3222
 
3149
- attrPresence: function(nodes, root, attr) {
3223
+ attrPresence: function(nodes, root, attr, combinator) {
3150
3224
  if (!nodes) nodes = root.getElementsByTagName("*");
3225
+ if (nodes && combinator) nodes = this[combinator](nodes);
3151
3226
  var results = [];
3152
3227
  for (var i = 0, node; node = nodes[i]; i++)
3153
3228
  if (Element.hasAttribute(node, attr)) results.push(node);
3154
3229
  return results;
3155
3230
  },
3156
3231
 
3157
- attr: function(nodes, root, attr, value, operator) {
3232
+ attr: function(nodes, root, attr, value, operator, combinator) {
3158
3233
  if (!nodes) nodes = root.getElementsByTagName("*");
3234
+ if (nodes && combinator) nodes = this[combinator](nodes);
3159
3235
  var handler = Selector.operators[operator], results = [];
3160
3236
  for (var i = 0, node; node = nodes[i]; i++) {
3161
3237
  var nodeValue = Element.readAttribute(node, attr);
@@ -3234,7 +3310,7 @@ Object.extend(Selector, {
3234
3310
  var h = Selector.handlers, results = [], indexed = [], m;
3235
3311
  h.mark(nodes);
3236
3312
  for (var i = 0, node; node = nodes[i]; i++) {
3237
- if (!node.parentNode._counted) {
3313
+ if (!node.parentNode._countedByPrototype) {
3238
3314
  h.index(node.parentNode, reverse, ofType);
3239
3315
  indexed.push(node.parentNode);
3240
3316
  }
@@ -3261,7 +3337,7 @@ Object.extend(Selector, {
3261
3337
  'empty': function(nodes, value, root) {
3262
3338
  for (var i = 0, results = [], node; node = nodes[i]; i++) {
3263
3339
  // IE treats comments as element nodes
3264
- if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
3340
+ if (node.tagName == '!' || node.firstChild) continue;
3265
3341
  results.push(node);
3266
3342
  }
3267
3343
  return results;
@@ -3272,14 +3348,15 @@ Object.extend(Selector, {
3272
3348
  var exclusions = new Selector(selector).findElements(root);
3273
3349
  h.mark(exclusions);
3274
3350
  for (var i = 0, results = [], node; node = nodes[i]; i++)
3275
- if (!node._counted) results.push(node);
3351
+ if (!node._countedByPrototype) results.push(node);
3276
3352
  h.unmark(exclusions);
3277
3353
  return results;
3278
3354
  },
3279
3355
 
3280
3356
  'enabled': function(nodes, value, root) {
3281
3357
  for (var i = 0, results = [], node; node = nodes[i]; i++)
3282
- if (!node.disabled) results.push(node);
3358
+ if (!node.disabled && (!node.type || node.type !== 'hidden'))
3359
+ results.push(node);
3283
3360
  return results;
3284
3361
  },
3285
3362
 
@@ -3299,18 +3376,29 @@ Object.extend(Selector, {
3299
3376
  operators: {
3300
3377
  '=': function(nv, v) { return nv == v; },
3301
3378
  '!=': function(nv, v) { return nv != v; },
3302
- '^=': function(nv, v) { return nv.startsWith(v); },
3379
+ '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); },
3380
+ '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); },
3381
+ '*=': function(nv, v) { return nv == v || nv && nv.include(v); },
3303
3382
  '$=': function(nv, v) { return nv.endsWith(v); },
3304
3383
  '*=': function(nv, v) { return nv.include(v); },
3305
3384
  '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
3306
- '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
3385
+ '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() +
3386
+ '-').include('-' + (v || "").toUpperCase() + '-'); }
3387
+ },
3388
+
3389
+ split: function(expression) {
3390
+ var expressions = [];
3391
+ expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
3392
+ expressions.push(m[1].strip());
3393
+ });
3394
+ return expressions;
3307
3395
  },
3308
3396
 
3309
3397
  matchElements: function(elements, expression) {
3310
- var matches = new Selector(expression).findElements(), h = Selector.handlers;
3398
+ var matches = $$(expression), h = Selector.handlers;
3311
3399
  h.mark(matches);
3312
3400
  for (var i = 0, results = [], element; element = elements[i]; i++)
3313
- if (element._counted) results.push(element);
3401
+ if (element._countedByPrototype) results.push(element);
3314
3402
  h.unmark(matches);
3315
3403
  return results;
3316
3404
  },
@@ -3323,10 +3411,7 @@ Object.extend(Selector, {
3323
3411
  },
3324
3412
 
3325
3413
  findChildElements: function(element, expressions) {
3326
- var exprs = expressions.join(','), expressions = [];
3327
- exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
3328
- expressions.push(m[1].strip());
3329
- });
3414
+ expressions = Selector.split(expressions.join(','));
3330
3415
  var results = [], h = Selector.handlers;
3331
3416
  for (var i = 0, l = expressions.length, selector; i < l; i++) {
3332
3417
  selector = new Selector(expressions[i].strip());
@@ -3336,6 +3421,25 @@ Object.extend(Selector, {
3336
3421
  }
3337
3422
  });
3338
3423
 
3424
+ if (Prototype.Browser.IE) {
3425
+ Object.extend(Selector.handlers, {
3426
+ // IE returns comment nodes on getElementsByTagName("*").
3427
+ // Filter them out.
3428
+ concat: function(a, b) {
3429
+ for (var i = 0, node; node = b[i]; i++)
3430
+ if (node.tagName !== "!") a.push(node);
3431
+ return a;
3432
+ },
3433
+
3434
+ // IE improperly serializes _countedByPrototype in (inner|outer)HTML.
3435
+ unmark: function(nodes) {
3436
+ for (var i = 0, node; node = nodes[i]; i++)
3437
+ node.removeAttribute('_countedByPrototype');
3438
+ return nodes;
3439
+ }
3440
+ });
3441
+ }
3442
+
3339
3443
  function $$() {
3340
3444
  return Selector.findChildElements(document, $A(arguments));
3341
3445
  }
@@ -3347,13 +3451,13 @@ var Form = {
3347
3451
 
3348
3452
  serializeElements: function(elements, options) {
3349
3453
  if (typeof options != 'object') options = { hash: !!options };
3350
- else if (options.hash === undefined) options.hash = true;
3454
+ else if (Object.isUndefined(options.hash)) options.hash = true;
3351
3455
  var key, value, submitted = false, submit = options.submit;
3352
3456
 
3353
3457
  var data = elements.inject({ }, function(result, element) {
3354
3458
  if (!element.disabled && element.name) {
3355
3459
  key = element.name; value = $(element).getValue();
3356
- if (value != null && (element.type != 'submit' || (!submitted &&
3460
+ if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
3357
3461
  submit !== false && (!submit || key == submit) && (submitted = true)))) {
3358
3462
  if (key in result) {
3359
3463
  // a key is already present; construct an array of values
@@ -3514,7 +3618,6 @@ Form.Element.Methods = {
3514
3618
 
3515
3619
  disable: function(element) {
3516
3620
  element = $(element);
3517
- element.blur();
3518
3621
  element.disabled = true;
3519
3622
  return element;
3520
3623
  },
@@ -3545,31 +3648,31 @@ Form.Element.Serializers = {
3545
3648
  },
3546
3649
 
3547
3650
  inputSelector: function(element, value) {
3548
- if (value === undefined) return element.checked ? element.value : null;
3651
+ if (Object.isUndefined(value)) return element.checked ? element.value : null;
3549
3652
  else element.checked = !!value;
3550
3653
  },
3551
3654
 
3552
3655
  textarea: function(element, value) {
3553
- if (value === undefined) return element.value;
3656
+ if (Object.isUndefined(value)) return element.value;
3554
3657
  else element.value = value;
3555
3658
  },
3556
3659
 
3557
- select: function(element, index) {
3558
- if (index === undefined)
3660
+ select: function(element, value) {
3661
+ if (Object.isUndefined(value))
3559
3662
  return this[element.type == 'select-one' ?
3560
3663
  'selectOne' : 'selectMany'](element);
3561
3664
  else {
3562
- var opt, value, single = !Object.isArray(index);
3665
+ var opt, currentValue, single = !Object.isArray(value);
3563
3666
  for (var i = 0, length = element.length; i < length; i++) {
3564
3667
  opt = element.options[i];
3565
- value = this.optionValue(opt);
3668
+ currentValue = this.optionValue(opt);
3566
3669
  if (single) {
3567
- if (value == index) {
3670
+ if (currentValue == value) {
3568
3671
  opt.selected = true;
3569
3672
  return;
3570
3673
  }
3571
3674
  }
3572
- else opt.selected = index.include(value);
3675
+ else opt.selected = value.include(currentValue);
3573
3676
  }
3574
3677
  }
3575
3678
  },
@@ -3740,21 +3843,42 @@ Event.Methods = (function() {
3740
3843
  isRightClick: function(event) { return isButton(event, 2) },
3741
3844
 
3742
3845
  element: function(event) {
3743
- var node = Event.extend(event).target;
3744
- return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node);
3846
+ event = Event.extend(event);
3847
+
3848
+ var node = event.target,
3849
+ type = event.type,
3850
+ currentTarget = event.currentTarget;
3851
+
3852
+ if (currentTarget && currentTarget.tagName) {
3853
+ // Firefox screws up the "click" event when moving between radio buttons
3854
+ // via arrow keys. It also screws up the "load" and "error" events on images,
3855
+ // reporting the document as the target instead of the original image.
3856
+ if (type === 'load' || type === 'error' ||
3857
+ (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
3858
+ && currentTarget.type === 'radio'))
3859
+ node = currentTarget;
3860
+ }
3861
+ if (node.nodeType == Node.TEXT_NODE) node = node.parentNode;
3862
+ return Element.extend(node);
3745
3863
  },
3746
3864
 
3747
3865
  findElement: function(event, expression) {
3748
3866
  var element = Event.element(event);
3749
- return element.match(expression) ? element : element.up(expression);
3867
+ if (!expression) return element;
3868
+ var elements = [element].concat(element.ancestors());
3869
+ return Selector.findElement(elements, expression, 0);
3750
3870
  },
3751
3871
 
3752
3872
  pointer: function(event) {
3873
+ var docElement = document.documentElement,
3874
+ body = document.body || { scrollLeft: 0, scrollTop: 0 };
3753
3875
  return {
3754
3876
  x: event.pageX || (event.clientX +
3755
- (document.documentElement.scrollLeft || document.body.scrollLeft)),
3877
+ (docElement.scrollLeft || body.scrollLeft) -
3878
+ (docElement.clientLeft || 0)),
3756
3879
  y: event.pageY || (event.clientY +
3757
- (document.documentElement.scrollTop || document.body.scrollTop))
3880
+ (docElement.scrollTop || body.scrollTop) -
3881
+ (docElement.clientTop || 0))
3758
3882
  };
3759
3883
  },
3760
3884
 
@@ -3799,7 +3923,7 @@ Event.extend = (function() {
3799
3923
  };
3800
3924
 
3801
3925
  } else {
3802
- Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__;
3926
+ Event.prototype = Event.prototype || document.createEvent("HTMLEvents")['__proto__'];
3803
3927
  Object.extend(Event.prototype, methods);
3804
3928
  return Prototype.K;
3805
3929
  }
@@ -3809,9 +3933,9 @@ Object.extend(Event, (function() {
3809
3933
  var cache = Event.cache;
3810
3934
 
3811
3935
  function getEventID(element) {
3812
- if (element._eventID) return element._eventID;
3936
+ if (element._prototypeEventID) return element._prototypeEventID[0];
3813
3937
  arguments.callee.id = arguments.callee.id || 1;
3814
- return element._eventID = ++arguments.callee.id;
3938
+ return element._prototypeEventID = [++arguments.callee.id];
3815
3939
  }
3816
3940
 
3817
3941
  function getDOMEventName(eventName) {
@@ -3839,7 +3963,7 @@ Object.extend(Event, (function() {
3839
3963
  return false;
3840
3964
 
3841
3965
  Event.extend(event);
3842
- handler.call(element, event)
3966
+ handler.call(element, event);
3843
3967
  };
3844
3968
 
3845
3969
  wrapper.handler = handler;
@@ -3864,10 +3988,20 @@ Object.extend(Event, (function() {
3864
3988
  cache[id][eventName] = null;
3865
3989
  }
3866
3990
 
3991
+
3992
+ // Internet Explorer needs to remove event handlers on page unload
3993
+ // in order to avoid memory leaks.
3867
3994
  if (window.attachEvent) {
3868
3995
  window.attachEvent("onunload", destroyCache);
3869
3996
  }
3870
3997
 
3998
+ // Safari has a dummy event handler on page unload so that it won't
3999
+ // use its bfcache. Safari <= 3.1 has an issue with restoring the "document"
4000
+ // object when page is returned to via the back button using its bfcache.
4001
+ if (Prototype.Browser.WebKit) {
4002
+ window.addEventListener('unload', Prototype.emptyFunction, false);
4003
+ }
4004
+
3871
4005
  return {
3872
4006
  observe: function(element, eventName, handler) {
3873
4007
  element = $(element);
@@ -3921,11 +4055,12 @@ Object.extend(Event, (function() {
3921
4055
  if (element == document && document.createEvent && !element.dispatchEvent)
3922
4056
  element = document.documentElement;
3923
4057
 
4058
+ var event;
3924
4059
  if (document.createEvent) {
3925
- var event = document.createEvent("HTMLEvents");
4060
+ event = document.createEvent("HTMLEvents");
3926
4061
  event.initEvent("dataavailable", true, true);
3927
4062
  } else {
3928
- var event = document.createEventObject();
4063
+ event = document.createEventObject();
3929
4064
  event.eventType = "ondataavailable";
3930
4065
  }
3931
4066
 
@@ -3938,7 +4073,7 @@ Object.extend(Event, (function() {
3938
4073
  element.fireEvent(event.eventType, event);
3939
4074
  }
3940
4075
 
3941
- return event;
4076
+ return Event.extend(event);
3942
4077
  }
3943
4078
  };
3944
4079
  })());
@@ -3954,20 +4089,21 @@ Element.addMethods({
3954
4089
  Object.extend(document, {
3955
4090
  fire: Element.Methods.fire.methodize(),
3956
4091
  observe: Element.Methods.observe.methodize(),
3957
- stopObserving: Element.Methods.stopObserving.methodize()
4092
+ stopObserving: Element.Methods.stopObserving.methodize(),
4093
+ loaded: false
3958
4094
  });
3959
4095
 
3960
4096
  (function() {
3961
4097
  /* Support for the DOMContentLoaded event is based on work by Dan Webb,
3962
4098
  Matthias Miller, Dean Edwards and John Resig. */
3963
4099
 
3964
- var timer, fired = false;
4100
+ var timer;
3965
4101
 
3966
4102
  function fireContentLoadedEvent() {
3967
- if (fired) return;
4103
+ if (document.loaded) return;
3968
4104
  if (timer) window.clearInterval(timer);
3969
4105
  document.fire("dom:loaded");
3970
- fired = true;
4106
+ document.loaded = true;
3971
4107
  }
3972
4108
 
3973
4109
  if (document.addEventListener) {