backlog 0.35.5 → 0.36.2

Sign up to get free protection for your applications and to get access to all the features.
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) {