Description:
fixed incompatibilities with rail 2.1 git-svn-id: http://theory.cpe.ku.ac.th/grader/web/trunk@276 6386c4cd-e34a-4fa8-8920-d93eb39b512e
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r137:d08ca3e34dfe - - 7 files changed: 4226 inserted, 2259 deleted

@@ -13,7 +13,8
13 verify :method => :post, :only => [:submit],
13 verify :method => :post, :only => [:submit],
14 :redirect_to => { :action => :index }
14 :redirect_to => { :action => :index }
15
15
16 - caches_action :index, :login
16 + # COMMENT OUT, only need when having high load
17 + # caches_action :index, :login
17
18
18 def index
19 def index
19 redirect_to :action => 'login'
20 redirect_to :action => 'login'
@@ -1,18 +1,18
1 <tr class="info-<%= (problem_counter%2==0) ? "even" : "odd" %>">
1 <tr class="info-<%= (problem_counter%2==0) ? "even" : "odd" %>">
2 <td>
2 <td>
3 - <%= "#{problem_counter + 1}" %>
3 + <%= "#{problem_counter}" %>
4 </td>
4 </td>
5 <td>
5 <td>
6 <%= "#{problem.full_name} (#{problem.name})" %>
6 <%= "#{problem.full_name} (#{problem.name})" %>
7 <%= link_to '[desc]', problem.url, :popup => true if (problem.url!=nil) and (problem.url!='') %>
7 <%= link_to '[desc]', problem.url, :popup => true if (problem.url!=nil) and (problem.url!='') %>
8 </td>
8 </td>
9 <td align="center">
9 <td align="center">
10 - <%= @prob_submissions[problem_counter][:count] %>
10 + <%= @prob_submissions[problem_counter-1][:count] %>
11 </td>
11 </td>
12 <td>
12 <td>
13 <%= render :partial => 'submission_short',
13 <%= render :partial => 'submission_short',
14 :locals => {
14 :locals => {
15 - :submission => @prob_submissions[problem_counter][:submission],
15 + :submission => @prob_submissions[problem_counter-1][:submission],
16 :problem_name => problem.name }%>
16 :problem_name => problem.name }%>
17 </td>
17 </td>
18 </tr>
18 </tr>
@@ -1,45 +1,109
1 - # Don't change this file. Configuration is done in config/environment.rb and config/environments/*.rb
1 + # Don't change this file!
2 + # Configure your app in config/environment.rb and config/environments/*.rb
3 +
4 + RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
5 +
6 + module Rails
7 + class << self
8 + def boot!
9 + unless booted?
10 + preinitialize
11 + pick_boot.run
12 + end
13 + end
2
14
3 - unless defined?(RAILS_ROOT)
15 + def booted?
4 - root_path = File.join(File.dirname(__FILE__), '..')
16 + defined? Rails::Initializer
17 + end
18 +
19 + def pick_boot
20 + (vendor_rails? ? VendorBoot : GemBoot).new
21 + end
5
22
6 - unless RUBY_PLATFORM =~ /(:?mswin|mingw)/
23 + def vendor_rails?
7 - require 'pathname'
24 + File.exist?("#{RAILS_ROOT}/vendor/rails")
8 - root_path = Pathname.new(root_path).cleanpath(true).to_s
25 + end
26 +
27 + def preinitialize
28 + load(preinitializer_path) if File.exist?(preinitializer_path)
29 + end
30 +
31 + def preinitializer_path
32 + "#{RAILS_ROOT}/config/preinitializer.rb"
33 + end
9 end
34 end
10
35
11 - RAILS_ROOT = root_path
36 + class Boot
12 - end
37 + def run
13 -
38 + load_initializer
14 - unless defined?(Rails::Initializer)
39 + Rails::Initializer.run(:set_load_path)
15 - if File.directory?("#{RAILS_ROOT}/vendor/rails")
40 + end
16 - require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
41 + end
17 - else
18 - require 'rubygems'
19 -
20 - environment_without_comments = IO.readlines(File.dirname(__FILE__) + '/environment.rb').reject { |l| l =~ /^#/ }.join
21 - environment_without_comments =~ /[^#]RAILS_GEM_VERSION = '([\d.]+)'/
22 - rails_gem_version = $1
23
42
24 - if version = defined?(RAILS_GEM_VERSION) ? RAILS_GEM_VERSION : rails_gem_version
43 + class VendorBoot < Boot
25 - # Asking for 1.1.6 will give you 1.1.6.5206, if available -- makes it easier to use beta gems
44 + def load_initializer
26 - rails_gem = Gem.cache.search('rails', "~>#{version}.0").sort_by { |g| g.version.version }.last
45 + require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
27 -
46 + Rails::Initializer.run(:install_gem_spec_stubs)
28 - if rails_gem
29 - gem "rails", "=#{rails_gem.version.version}"
30 - require rails_gem.full_gem_path + '/lib/initializer'
31 - else
32 - STDERR.puts %(Cannot find gem for Rails ~>#{version}.0:
33 - Install the missing gem with 'gem install -v=#{version} rails', or
34 - change environment.rb to define RAILS_GEM_VERSION with your desired version.
35 - )
36 - exit 1
37 - end
38 - else
39 - gem "rails"
40 - require 'initializer'
41 end
47 end
42 end
48 end
43
49
44 - Rails::Initializer.run(:set_load_path)
50 + class GemBoot < Boot
51 + def load_initializer
52 + self.class.load_rubygems
53 + load_rails_gem
54 + require 'initializer'
55 + end
56 +
57 + def load_rails_gem
58 + if version = self.class.gem_version
59 + gem 'rails', version
60 + else
61 + gem 'rails'
62 + end
63 + rescue Gem::LoadError => load_error
64 + $stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.)
65 + exit 1
66 + end
67 +
68 + class << self
69 + def rubygems_version
70 + Gem::RubyGemsVersion if defined? Gem::RubyGemsVersion
71 + end
72 +
73 + def gem_version
74 + if defined? RAILS_GEM_VERSION
75 + RAILS_GEM_VERSION
76 + elsif ENV.include?('RAILS_GEM_VERSION')
77 + ENV['RAILS_GEM_VERSION']
78 + else
79 + parse_gem_version(read_environment_rb)
80 + end
81 + end
82 +
83 + def load_rubygems
84 + require 'rubygems'
85 +
86 + unless rubygems_version >= '0.9.4'
87 + $stderr.puts %(Rails requires RubyGems >= 0.9.4 (you have #{rubygems_version}). Please `gem update --system` and try again.)
88 + exit 1
89 + end
90 +
91 + rescue LoadError
92 + $stderr.puts %(Rails requires RubyGems >= 0.9.4. Please install RubyGems and try again: http://rubygems.rubyforge.org)
93 + exit 1
94 + end
95 +
96 + def parse_gem_version(text)
97 + $1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/
98 + end
99 +
100 + private
101 + def read_environment_rb
102 + File.read("#{RAILS_ROOT}/config/environment.rb")
103 + end
104 + end
105 + end
45 end
106 end
107 +
108 + # All that for this:
109 + Rails.boot!
This diff has been collapsed as it changes many lines, (840 lines changed) Show them Hide them
@@ -1,6 +1,6
1 - // Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
1 + // Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
2 - // (c) 2005, 2006 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
2 + // (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
3 - // (c) 2005, 2006 Jon Tirsen (http://www.tirsen.com)
3 + // (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
4 // Contributors:
4 // Contributors:
5 // Richard Livsey
5 // Richard Livsey
6 // Rahul Bhargava
6 // Rahul Bhargava
@@ -37,22 +37,23
37 if(typeof Effect == 'undefined')
37 if(typeof Effect == 'undefined')
38 throw("controls.js requires including script.aculo.us' effects.js library");
38 throw("controls.js requires including script.aculo.us' effects.js library");
39
39
40 - var Autocompleter = {}
40 + var Autocompleter = { }
41 - Autocompleter.Base = function() {};
41 + Autocompleter.Base = Class.create({
42 - Autocompleter.Base.prototype = {
43 baseInitialize: function(element, update, options) {
42 baseInitialize: function(element, update, options) {
44 - this.element = $(element);
43 + element = $(element)
44 + this.element = element;
45 this.update = $(update);
45 this.update = $(update);
46 this.hasFocus = false;
46 this.hasFocus = false;
47 this.changed = false;
47 this.changed = false;
48 this.active = false;
48 this.active = false;
49 this.index = 0;
49 this.index = 0;
50 this.entryCount = 0;
50 this.entryCount = 0;
51 + this.oldElementValue = this.element.value;
51
52
52 if(this.setOptions)
53 if(this.setOptions)
53 this.setOptions(options);
54 this.setOptions(options);
54 else
55 else
55 - this.options = options || {};
56 + this.options = options || { };
56
57
57 this.options.paramName = this.options.paramName || this.element.name;
58 this.options.paramName = this.options.paramName || this.element.name;
58 this.options.tokens = this.options.tokens || [];
59 this.options.tokens = this.options.tokens || [];
@@ -74,6 +75,9
74
75
75 if(typeof(this.options.tokens) == 'string')
76 if(typeof(this.options.tokens) == 'string')
76 this.options.tokens = new Array(this.options.tokens);
77 this.options.tokens = new Array(this.options.tokens);
78 + // Force carriage returns as token delimiters anyway
79 + if (!this.options.tokens.include('\n'))
80 + this.options.tokens.push('\n');
77
81
78 this.observer = null;
82 this.observer = null;
79
83
@@ -81,15 +85,14
81
85
82 Element.hide(this.update);
86 Element.hide(this.update);
83
87
84 - Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
88 + Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
85 - Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
89 + Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));
86 },
90 },
87
91
88 show: function() {
92 show: function() {
89 if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
93 if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
90 if(!this.iefix &&
94 if(!this.iefix &&
91 - (navigator.appVersion.indexOf('MSIE')>0) &&
95 + (Prototype.Browser.IE) &&
92 - (navigator.userAgent.indexOf('Opera')<0) &&
93 (Element.getStyle(this.update, 'position')=='absolute')) {
96 (Element.getStyle(this.update, 'position')=='absolute')) {
94 new Insertion.After(this.update,
97 new Insertion.After(this.update,
95 '<iframe id="' + this.update.id + '_iefix" '+
98 '<iframe id="' + this.update.id + '_iefix" '+
@@ -139,17 +142,17
139 case Event.KEY_UP:
142 case Event.KEY_UP:
140 this.markPrevious();
143 this.markPrevious();
141 this.render();
144 this.render();
142 - if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
145 + Event.stop(event);
143 return;
146 return;
144 case Event.KEY_DOWN:
147 case Event.KEY_DOWN:
145 this.markNext();
148 this.markNext();
146 this.render();
149 this.render();
147 - if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
150 + Event.stop(event);
148 return;
151 return;
149 }
152 }
150 else
153 else
151 if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
154 if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
152 - (navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0)) return;
155 + (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;
153
156
154 this.changed = true;
157 this.changed = true;
155 this.hasFocus = true;
158 this.hasFocus = true;
@@ -195,7 +198,6
195 this.index==i ?
198 this.index==i ?
196 Element.addClassName(this.getEntry(i),"selected") :
199 Element.addClassName(this.getEntry(i),"selected") :
197 Element.removeClassName(this.getEntry(i),"selected");
200 Element.removeClassName(this.getEntry(i),"selected");
198 -
199 if(this.hasFocus) {
201 if(this.hasFocus) {
200 this.show();
202 this.show();
201 this.active = true;
203 this.active = true;
@@ -238,21 +240,22
238 }
240 }
239 var value = '';
241 var value = '';
240 if (this.options.select) {
242 if (this.options.select) {
241 - var nodes = document.getElementsByClassName(this.options.select, selectedElement) || [];
243 + var nodes = $(selectedElement).select('.' + this.options.select) || [];
242 if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
244 if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
243 } else
245 } else
244 value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
246 value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
245
247
246 - var lastTokenPos = this.findLastToken();
248 + var bounds = this.getTokenBounds();
247 - if (lastTokenPos != -1) {
249 + if (bounds[0] != -1) {
248 - var newValue = this.element.value.substr(0, lastTokenPos + 1);
250 + var newValue = this.element.value.substr(0, bounds[0]);
249 - var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
251 + var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/);
250 if (whitespace)
252 if (whitespace)
251 newValue += whitespace[0];
253 newValue += whitespace[0];
252 - this.element.value = newValue + value;
254 + this.element.value = newValue + value + this.element.value.substr(bounds[1]);
253 } else {
255 } else {
254 this.element.value = value;
256 this.element.value = value;
255 }
257 }
258 + this.oldElementValue = this.element.value;
256 this.element.focus();
259 this.element.focus();
257
260
258 if (this.options.afterUpdateElement)
261 if (this.options.afterUpdateElement)
@@ -296,39 +299,48
296
299
297 onObserverEvent: function() {
300 onObserverEvent: function() {
298 this.changed = false;
301 this.changed = false;
302 + this.tokenBounds = null;
299 if(this.getToken().length>=this.options.minChars) {
303 if(this.getToken().length>=this.options.minChars) {
300 - this.startIndicator();
301 this.getUpdatedChoices();
304 this.getUpdatedChoices();
302 } else {
305 } else {
303 this.active = false;
306 this.active = false;
304 this.hide();
307 this.hide();
305 }
308 }
309 + this.oldElementValue = this.element.value;
306 },
310 },
307
311
308 getToken: function() {
312 getToken: function() {
309 - var tokenPos = this.findLastToken();
313 + var bounds = this.getTokenBounds();
310 - if (tokenPos != -1)
314 + return this.element.value.substring(bounds[0], bounds[1]).strip();
311 - var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,'');
312 - else
313 - var ret = this.element.value;
314 -
315 - return /\n/.test(ret) ? '' : ret;
316 },
315 },
317
316
318 - findLastToken: function() {
317 + getTokenBounds: function() {
319 - var lastTokenPos = -1;
318 + if (null != this.tokenBounds) return this.tokenBounds;
319 + var value = this.element.value;
320 + if (value.strip().empty()) return [-1, 0];
321 + var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue);
322 + var offset = (diff == this.oldElementValue.length ? 1 : 0);
323 + var prevTokenPos = -1, nextTokenPos = value.length;
324 + var tp;
325 + for (var index = 0, l = this.options.tokens.length; index < l; ++index) {
326 + tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
327 + if (tp > prevTokenPos) prevTokenPos = tp;
328 + tp = value.indexOf(this.options.tokens[index], diff + offset);
329 + if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
330 + }
331 + return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
332 + }
333 + });
320
334
321 - for (var i=0; i<this.options.tokens.length; i++) {
335 + Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) {
322 - var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]);
336 + var boundary = Math.min(newS.length, oldS.length);
323 - if (thisTokenPos > lastTokenPos)
337 + for (var index = 0; index < boundary; ++index)
324 - lastTokenPos = thisTokenPos;
338 + if (newS[index] != oldS[index])
325 - }
339 + return index;
326 - return lastTokenPos;
340 + return boundary;
327 - }
341 + };
328 - }
329
342
330 - Ajax.Autocompleter = Class.create();
343 + Ajax.Autocompleter = Class.create(Autocompleter.Base, {
331 - Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
332 initialize: function(element, update, url, options) {
344 initialize: function(element, update, url, options) {
333 this.baseInitialize(element, update, options);
345 this.baseInitialize(element, update, options);
334 this.options.asynchronous = true;
346 this.options.asynchronous = true;
@@ -338,7 +350,9
338 },
350 },
339
351
340 getUpdatedChoices: function() {
352 getUpdatedChoices: function() {
341 - entry = encodeURIComponent(this.options.paramName) + '=' +
353 + this.startIndicator();
354 +
355 + var entry = encodeURIComponent(this.options.paramName) + '=' +
342 encodeURIComponent(this.getToken());
356 encodeURIComponent(this.getToken());
343
357
344 this.options.parameters = this.options.callback ?
358 this.options.parameters = this.options.callback ?
@@ -346,14 +360,13
346
360
347 if(this.options.defaultParams)
361 if(this.options.defaultParams)
348 this.options.parameters += '&' + this.options.defaultParams;
362 this.options.parameters += '&' + this.options.defaultParams;
349 -
363 +
350 new Ajax.Request(this.url, this.options);
364 new Ajax.Request(this.url, this.options);
351 },
365 },
352
366
353 onComplete: function(request) {
367 onComplete: function(request) {
354 this.updateChoices(request.responseText);
368 this.updateChoices(request.responseText);
355 }
369 }
356 -
357 });
370 });
358
371
359 // The local array autocompleter. Used when you'd prefer to
372 // The local array autocompleter. Used when you'd prefer to
@@ -391,8 +404,7
391 // In that case, the other options above will not apply unless
404 // In that case, the other options above will not apply unless
392 // you support them.
405 // you support them.
393
406
394 - Autocompleter.Local = Class.create();
407 + Autocompleter.Local = Class.create(Autocompleter.Base, {
395 - Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
396 initialize: function(element, update, array, options) {
408 initialize: function(element, update, array, options) {
397 this.baseInitialize(element, update, options);
409 this.baseInitialize(element, update, options);
398 this.options.array = array;
410 this.options.array = array;
@@ -448,13 +460,12
448 ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
460 ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
449 return "<ul>" + ret.join('') + "</ul>";
461 return "<ul>" + ret.join('') + "</ul>";
450 }
462 }
451 - }, options || {});
463 + }, options || { });
452 }
464 }
453 });
465 });
454
466
455 - // AJAX in-place editor
467 + // AJAX in-place editor and collection editor
456 - //
468 + // Full rewrite by Christophe Porteneuve <tdd@tddsworld.com> (April 2007).
457 - // see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor
458
469
459 // Use this if you notice weird scrolling problems on some browsers,
470 // Use this if you notice weird scrolling problems on some browsers,
460 // the DOM might be a bit confused when this gets called so do this
471 // the DOM might be a bit confused when this gets called so do this
@@ -465,353 +476,472
465 }, 1);
476 }, 1);
466 }
477 }
467
478
468 - Ajax.InPlaceEditor = Class.create();
479 + Ajax.InPlaceEditor = Class.create({
469 - Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99";
470 - Ajax.InPlaceEditor.prototype = {
471 initialize: function(element, url, options) {
480 initialize: function(element, url, options) {
472 this.url = url;
481 this.url = url;
473 - this.element = $(element);
482 + this.element = element = $(element);
474 -
483 + this.prepareOptions();
475 - this.options = Object.extend({
484 + this._controls = { };
476 - paramName: "value",
485 + arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!!
477 - okButton: true,
486 + Object.extend(this.options, options || { });
478 - okText: "ok",
487 + if (!this.options.formId && this.element.id) {
479 - cancelLink: true,
488 + this.options.formId = this.element.id + '-inplaceeditor';
480 - cancelText: "cancel",
489 + if ($(this.options.formId))
481 - savingText: "Saving...",
490 + this.options.formId = '';
482 - clickToEditText: "Click to edit",
483 - okText: "ok",
484 - rows: 1,
485 - onComplete: function(transport, element) {
486 - new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
487 - },
488 - onFailure: function(transport) {
489 - alert("Error communicating with the server: " + transport.responseText.stripTags());
490 - },
491 - callback: function(form) {
492 - return Form.serialize(form);
493 - },
494 - handleLineBreaks: true,
495 - loadingText: 'Loading...',
496 - savingClassName: 'inplaceeditor-saving',
497 - loadingClassName: 'inplaceeditor-loading',
498 - formClassName: 'inplaceeditor-form',
499 - highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
500 - highlightendcolor: "#FFFFFF",
501 - externalControl: null,
502 - submitOnBlur: false,
503 - ajaxOptions: {},
504 - evalScripts: false
505 - }, options || {});
506 -
507 - if(!this.options.formId && this.element.id) {
508 - this.options.formId = this.element.id + "-inplaceeditor";
509 - if ($(this.options.formId)) {
510 - // there's already a form with that name, don't specify an id
511 - this.options.formId = null;
512 - }
513 }
491 }
514 -
492 + if (this.options.externalControl)
515 - if (this.options.externalControl) {
516 this.options.externalControl = $(this.options.externalControl);
493 this.options.externalControl = $(this.options.externalControl);
517 - }
494 + if (!this.options.externalControl)
518 -
495 + this.options.externalControlOnly = false;
519 - this.originalBackground = Element.getStyle(this.element, 'background-color');
496 + this._originalBackground = this.element.getStyle('background-color') || 'transparent';
520 - if (!this.originalBackground) {
521 - this.originalBackground = "transparent";
522 - }
523 -
524 this.element.title = this.options.clickToEditText;
497 this.element.title = this.options.clickToEditText;
525 -
498 + this._boundCancelHandler = this.handleFormCancellation.bind(this);
526 - this.onclickListener = this.enterEditMode.bindAsEventListener(this);
499 + this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this);
527 - this.mouseoverListener = this.enterHover.bindAsEventListener(this);
500 + this._boundFailureHandler = this.handleAJAXFailure.bind(this);
528 - this.mouseoutListener = this.leaveHover.bindAsEventListener(this);
501 + this._boundSubmitHandler = this.handleFormSubmission.bind(this);
529 - Event.observe(this.element, 'click', this.onclickListener);
502 + this._boundWrapperHandler = this.wrapUp.bind(this);
530 - Event.observe(this.element, 'mouseover', this.mouseoverListener);
503 + this.registerListeners();
531 - Event.observe(this.element, 'mouseout', this.mouseoutListener);
504 + },
532 - if (this.options.externalControl) {
505 + checkForEscapeOrReturn: function(e) {
533 - Event.observe(this.options.externalControl, 'click', this.onclickListener);
506 + if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return;
534 - Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener);
507 + if (Event.KEY_ESC == e.keyCode)
535 - Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);
508 + this.handleFormCancellation(e);
509 + else if (Event.KEY_RETURN == e.keyCode)
510 + this.handleFormSubmission(e);
511 + },
512 + createControl: function(mode, handler, extraClasses) {
513 + var control = this.options[mode + 'Control'];
514 + var text = this.options[mode + 'Text'];
515 + if ('button' == control) {
516 + var btn = document.createElement('input');
517 + btn.type = 'submit';
518 + btn.value = text;
519 + btn.className = 'editor_' + mode + '_button';
520 + if ('cancel' == mode)
521 + btn.onclick = this._boundCancelHandler;
522 + this._form.appendChild(btn);
523 + this._controls[mode] = btn;
524 + } else if ('link' == control) {
525 + var link = document.createElement('a');
526 + link.href = '#';
527 + link.appendChild(document.createTextNode(text));
528 + link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler;
529 + link.className = 'editor_' + mode + '_link';
530 + if (extraClasses)
531 + link.className += ' ' + extraClasses;
532 + this._form.appendChild(link);
533 + this._controls[mode] = link;
536 }
534 }
537 },
535 },
538 - enterEditMode: function(evt) {
536 + createEditField: function() {
539 - if (this.saving) return;
537 + var text = (this.options.loadTextURL ? this.options.loadingText : this.getText());
540 - if (this.editing) return;
538 + var fld;
541 - this.editing = true;
539 + if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) {
542 - this.onEnterEditMode();
540 + fld = document.createElement('input');
543 - if (this.options.externalControl) {
541 + fld.type = 'text';
544 - Element.hide(this.options.externalControl);
542 + var size = this.options.size || this.options.cols || 0;
543 + if (0 < size) fld.size = size;
544 + } else {
545 + fld = document.createElement('textarea');
546 + fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows);
547 + fld.cols = this.options.cols || 40;
545 }
548 }
546 - Element.hide(this.element);
549 + fld.name = this.options.paramName;
547 - this.createForm();
550 + fld.value = text; // No HTML breaks conversion anymore
548 - this.element.parentNode.insertBefore(this.form, this.element);
551 + fld.className = 'editor_field';
549 - if (!this.options.loadTextURL) Field.scrollFreeActivate(this.editField);
552 + if (this.options.submitOnBlur)
550 - // stop the event to avoid a page refresh in Safari
553 + fld.onblur = this._boundSubmitHandler;
551 - if (evt) {
554 + this._controls.editor = fld;
552 - Event.stop(evt);
555 + if (this.options.loadTextURL)
553 - }
556 + this.loadExternalText();
554 - return false;
557 + this._form.appendChild(this._controls.editor);
555 },
558 },
556 createForm: function() {
559 createForm: function() {
557 - this.form = document.createElement("form");
560 + var ipe = this;
558 - this.form.id = this.options.formId;
561 + function addText(mode, condition) {
559 - Element.addClassName(this.form, this.options.formClassName)
562 + var text = ipe.options['text' + mode + 'Controls'];
560 - this.form.onsubmit = this.onSubmit.bind(this);
563 + if (!text || condition === false) return;
561 -
564 + ipe._form.appendChild(document.createTextNode(text));
565 + };
566 + this._form = $(document.createElement('form'));
567 + this._form.id = this.options.formId;
568 + this._form.addClassName(this.options.formClassName);
569 + this._form.onsubmit = this._boundSubmitHandler;
562 this.createEditField();
570 this.createEditField();
563 -
571 + if ('textarea' == this._controls.editor.tagName.toLowerCase())
564 - if (this.options.textarea) {
572 + this._form.appendChild(document.createElement('br'));
565 - var br = document.createElement("br");
573 + if (this.options.onFormCustomization)
566 - this.form.appendChild(br);
574 + this.options.onFormCustomization(this, this._form);
567 - }
575 + addText('Before', this.options.okControl || this.options.cancelControl);
568 -
576 + this.createControl('ok', this._boundSubmitHandler);
569 - if (this.options.okButton) {
577 + addText('Between', this.options.okControl && this.options.cancelControl);
570 - okButton = document.createElement("input");
578 + this.createControl('cancel', this._boundCancelHandler, 'editor_cancel');
571 - okButton.type = "submit";
579 + addText('After', this.options.okControl || this.options.cancelControl);
572 - okButton.value = this.options.okText;
573 - okButton.className = 'editor_ok_button';
574 - this.form.appendChild(okButton);
575 - }
576 -
577 - if (this.options.cancelLink) {
578 - cancelLink = document.createElement("a");
579 - cancelLink.href = "#";
580 - cancelLink.appendChild(document.createTextNode(this.options.cancelText));
581 - cancelLink.onclick = this.onclickCancel.bind(this);
582 - cancelLink.className = 'editor_cancel';
583 - this.form.appendChild(cancelLink);
584 - }
585 - },
586 - hasHTMLLineBreaks: function(string) {
587 - if (!this.options.handleLineBreaks) return false;
588 - return string.match(/<br/i) || string.match(/<p>/i);
589 - },
590 - convertHTMLLineBreaks: function(string) {
591 - return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, "");
592 },
580 },
593 - createEditField: function() {
581 + destroy: function() {
594 - var text;
582 + if (this._oldInnerHTML)
595 - if(this.options.loadTextURL) {
583 + this.element.innerHTML = this._oldInnerHTML;
596 - text = this.options.loadingText;
584 + this.leaveEditMode();
597 - } else {
585 + this.unregisterListeners();
598 - text = this.getText();
586 + },
599 - }
587 + enterEditMode: function(e) {
600 -
588 + if (this._saving || this._editing) return;
601 - var obj = this;
589 + this._editing = true;
602 -
590 + this.triggerCallback('onEnterEditMode');
603 - if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
591 + if (this.options.externalControl)
604 - this.options.textarea = false;
592 + this.options.externalControl.hide();
605 - var textField = document.createElement("input");
593 + this.element.hide();
606 - textField.obj = this;
594 + this.createForm();
607 - textField.type = "text";
595 + this.element.parentNode.insertBefore(this._form, this.element);
608 - textField.name = this.options.paramName;
596 + if (!this.options.loadTextURL)
609 - textField.value = text;
597 + this.postProcessEditField();
610 - textField.style.backgroundColor = this.options.highlightcolor;
598 + if (e) Event.stop(e);
611 - textField.className = 'editor_field';
599 + },
612 - var size = this.options.size || this.options.cols || 0;
600 + enterHover: function(e) {
613 - if (size != 0) textField.size = size;
601 + if (this.options.hoverClassName)
614 - if (this.options.submitOnBlur)
602 + this.element.addClassName(this.options.hoverClassName);
615 - textField.onblur = this.onSubmit.bind(this);
603 + if (this._saving) return;
616 - this.editField = textField;
604 + this.triggerCallback('onEnterHover');
617 - } else {
618 - this.options.textarea = true;
619 - var textArea = document.createElement("textarea");
620 - textArea.obj = this;
621 - textArea.name = this.options.paramName;
622 - textArea.value = this.convertHTMLLineBreaks(text);
623 - textArea.rows = this.options.rows;
624 - textArea.cols = this.options.cols || 40;
625 - textArea.className = 'editor_field';
626 - if (this.options.submitOnBlur)
627 - textArea.onblur = this.onSubmit.bind(this);
628 - this.editField = textArea;
629 - }
630 -
631 - if(this.options.loadTextURL) {
632 - this.loadExternalText();
633 - }
634 - this.form.appendChild(this.editField);
635 },
605 },
636 getText: function() {
606 getText: function() {
637 return this.element.innerHTML;
607 return this.element.innerHTML;
638 },
608 },
639 - loadExternalText: function() {
609 + handleAJAXFailure: function(transport) {
640 - Element.addClassName(this.form, this.options.loadingClassName);
610 + this.triggerCallback('onFailure', transport);
641 - this.editField.disabled = true;
611 + if (this._oldInnerHTML) {
642 - new Ajax.Request(
612 + this.element.innerHTML = this._oldInnerHTML;
643 - this.options.loadTextURL,
613 + this._oldInnerHTML = null;
644 - Object.extend({
614 + }
645 - asynchronous: true,
615 + },
646 - onComplete: this.onLoadedExternalText.bind(this)
616 + handleFormCancellation: function(e) {
647 - }, this.options.ajaxOptions)
617 + this.wrapUp();
648 - );
618 + if (e) Event.stop(e);
649 },
619 },
650 - onLoadedExternalText: function(transport) {
620 + handleFormSubmission: function(e) {
651 - Element.removeClassName(this.form, this.options.loadingClassName);
621 + var form = this._form;
652 - this.editField.disabled = false;
622 + var value = $F(this._controls.editor);
653 - this.editField.value = transport.responseText.stripTags();
623 + this.prepareSubmission();
654 - Field.scrollFreeActivate(this.editField);
624 + var params = this.options.callback(form, value) || '';
655 - },
625 + if (Object.isString(params))
656 - onclickCancel: function() {
626 + params = params.toQueryParams();
657 - this.onComplete();
627 + params.editorId = this.element.id;
658 - this.leaveEditMode();
628 + if (this.options.htmlResponse) {
659 - return false;
629 + var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions);
660 - },
630 + Object.extend(options, {
661 - onFailure: function(transport) {
631 + parameters: params,
662 - this.options.onFailure(transport);
632 + onComplete: this._boundWrapperHandler,
663 - if (this.oldInnerHTML) {
633 + onFailure: this._boundFailureHandler
664 - this.element.innerHTML = this.oldInnerHTML;
634 + });
665 - this.oldInnerHTML = null;
635 + new Ajax.Updater({ success: this.element }, this.url, options);
636 + } else {
637 + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
638 + Object.extend(options, {
639 + parameters: params,
640 + onComplete: this._boundWrapperHandler,
641 + onFailure: this._boundFailureHandler
642 + });
643 + new Ajax.Request(this.url, options);
666 }
644 }
667 - return false;
645 + if (e) Event.stop(e);
668 },
646 },
669 - onSubmit: function() {
647 + leaveEditMode: function() {
670 - // onLoading resets these so we need to save them away for the Ajax call
648 + this.element.removeClassName(this.options.savingClassName);
671 - var form = this.form;
649 + this.removeForm();
672 - var value = this.editField.value;
650 + this.leaveHover();
673 -
651 + this.element.style.backgroundColor = this._originalBackground;
674 - // do this first, sometimes the ajax call returns before we get a chance to switch on Saving...
652 + this.element.show();
675 - // which means this will actually switch on Saving... *after* we've left edit mode causing Saving...
653 + if (this.options.externalControl)
676 - // to be displayed indefinitely
654 + this.options.externalControl.show();
677 - this.onLoading();
655 + this._saving = false;
678 -
656 + this._editing = false;
679 - if (this.options.evalScripts) {
657 + this._oldInnerHTML = null;
680 - new Ajax.Request(
658 + this.triggerCallback('onLeaveEditMode');
681 - this.url, Object.extend({
659 + },
682 - parameters: this.options.callback(form, value),
660 + leaveHover: function(e) {
683 - onComplete: this.onComplete.bind(this),
661 + if (this.options.hoverClassName)
684 - onFailure: this.onFailure.bind(this),
662 + this.element.removeClassName(this.options.hoverClassName);
685 - asynchronous:true,
663 + if (this._saving) return;
686 - evalScripts:true
664 + this.triggerCallback('onLeaveHover');
687 - }, this.options.ajaxOptions));
688 - } else {
689 - new Ajax.Updater(
690 - { success: this.element,
691 - // don't update on failure (this could be an option)
692 - failure: null },
693 - this.url, Object.extend({
694 - parameters: this.options.callback(form, value),
695 - onComplete: this.onComplete.bind(this),
696 - onFailure: this.onFailure.bind(this)
697 - }, this.options.ajaxOptions));
698 - }
699 - // stop the event to avoid a page refresh in Safari
700 - if (arguments.length > 1) {
701 - Event.stop(arguments[0]);
702 - }
703 - return false;
704 },
665 },
705 - onLoading: function() {
666 + loadExternalText: function() {
706 - this.saving = true;
667 + this._form.addClassName(this.options.loadingClassName);
668 + this._controls.editor.disabled = true;
669 + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
670 + Object.extend(options, {
671 + parameters: 'editorId=' + encodeURIComponent(this.element.id),
672 + onComplete: Prototype.emptyFunction,
673 + onSuccess: function(transport) {
674 + this._form.removeClassName(this.options.loadingClassName);
675 + var text = transport.responseText;
676 + if (this.options.stripLoadedTextTags)
677 + text = text.stripTags();
678 + this._controls.editor.value = text;
679 + this._controls.editor.disabled = false;
680 + this.postProcessEditField();
681 + }.bind(this),
682 + onFailure: this._boundFailureHandler
683 + });
684 + new Ajax.Request(this.options.loadTextURL, options);
685 + },
686 + postProcessEditField: function() {
687 + var fpc = this.options.fieldPostCreation;
688 + if (fpc)
689 + $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']();
690 + },
691 + prepareOptions: function() {
692 + this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions);
693 + Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks);
694 + [this._extraDefaultOptions].flatten().compact().each(function(defs) {
695 + Object.extend(this.options, defs);
696 + }.bind(this));
697 + },
698 + prepareSubmission: function() {
699 + this._saving = true;
707 this.removeForm();
700 this.removeForm();
708 this.leaveHover();
701 this.leaveHover();
709 this.showSaving();
702 this.showSaving();
710 },
703 },
711 - showSaving: function() {
704 + registerListeners: function() {
712 - this.oldInnerHTML = this.element.innerHTML;
705 + this._listeners = { };
713 - this.element.innerHTML = this.options.savingText;
706 + var listener;
714 - Element.addClassName(this.element, this.options.savingClassName);
707 + $H(Ajax.InPlaceEditor.Listeners).each(function(pair) {
715 - this.element.style.backgroundColor = this.originalBackground;
708 + listener = this[pair.value].bind(this);
716 - Element.show(this.element);
709 + this._listeners[pair.key] = listener;
710 + if (!this.options.externalControlOnly)
711 + this.element.observe(pair.key, listener);
712 + if (this.options.externalControl)
713 + this.options.externalControl.observe(pair.key, listener);
714 + }.bind(this));
717 },
715 },
718 removeForm: function() {
716 removeForm: function() {
719 - if(this.form) {
717 + if (!this._form) return;
720 - if (this.form.parentNode) Element.remove(this.form);
718 + this._form.remove();
721 - this.form = null;
719 + this._form = null;
720 + this._controls = { };
721 + },
722 + showSaving: function() {
723 + this._oldInnerHTML = this.element.innerHTML;
724 + this.element.innerHTML = this.options.savingText;
725 + this.element.addClassName(this.options.savingClassName);
726 + this.element.style.backgroundColor = this._originalBackground;
727 + this.element.show();
728 + },
729 + triggerCallback: function(cbName, arg) {
730 + if ('function' == typeof this.options[cbName]) {
731 + this.options[cbName](this, arg);
722 }
732 }
723 },
733 },
724 - enterHover: function() {
734 + unregisterListeners: function() {
725 - if (this.saving) return;
735 + $H(this._listeners).each(function(pair) {
726 - this.element.style.backgroundColor = this.options.highlightcolor;
736 + if (!this.options.externalControlOnly)
727 - if (this.effect) {
737 + this.element.stopObserving(pair.key, pair.value);
728 - this.effect.cancel();
738 + if (this.options.externalControl)
729 - }
739 + this.options.externalControl.stopObserving(pair.key, pair.value);
730 - Element.addClassName(this.element, this.options.hoverClassName)
740 + }.bind(this));
741 + },
742 + wrapUp: function(transport) {
743 + this.leaveEditMode();
744 + // Can't use triggerCallback due to backward compatibility: requires
745 + // binding + direct element
746 + this._boundComplete(transport, this.element);
747 + }
748 + });
749 +
750 + Object.extend(Ajax.InPlaceEditor.prototype, {
751 + dispose: Ajax.InPlaceEditor.prototype.destroy
752 + });
753 +
754 + Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
755 + initialize: function($super, element, url, options) {
756 + this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions;
757 + $super(element, url, options);
731 },
758 },
732 - leaveHover: function() {
759 +
733 - if (this.options.backgroundColor) {
760 + createEditField: function() {
734 - this.element.style.backgroundColor = this.oldBackground;
761 + var list = document.createElement('select');
735 - }
762 + list.name = this.options.paramName;
736 - Element.removeClassName(this.element, this.options.hoverClassName)
763 + list.size = 1;
737 - if (this.saving) return;
764 + this._controls.editor = list;
738 - this.effect = new Effect.Highlight(this.element, {
765 + this._collection = this.options.collection || [];
739 - startcolor: this.options.highlightcolor,
766 + if (this.options.loadCollectionURL)
740 - endcolor: this.options.highlightendcolor,
767 + this.loadCollection();
741 - restorecolor: this.originalBackground
768 + else
769 + this.checkForExternalText();
770 + this._form.appendChild(this._controls.editor);
771 + },
772 +
773 + loadCollection: function() {
774 + this._form.addClassName(this.options.loadingClassName);
775 + this.showLoadingText(this.options.loadingCollectionText);
776 + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
777 + Object.extend(options, {
778 + parameters: 'editorId=' + encodeURIComponent(this.element.id),
779 + onComplete: Prototype.emptyFunction,
780 + onSuccess: function(transport) {
781 + var js = transport.responseText.strip();
782 + if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
783 + throw 'Server returned an invalid collection representation.';
784 + this._collection = eval(js);
785 + this.checkForExternalText();
786 + }.bind(this),
787 + onFailure: this.onFailure
742 });
788 });
789 + new Ajax.Request(this.options.loadCollectionURL, options);
743 },
790 },
744 - leaveEditMode: function() {
791 +
745 - Element.removeClassName(this.element, this.options.savingClassName);
792 + showLoadingText: function(text) {
746 - this.removeForm();
793 + this._controls.editor.disabled = true;
747 - this.leaveHover();
794 + var tempOption = this._controls.editor.firstChild;
748 - this.element.style.backgroundColor = this.originalBackground;
795 + if (!tempOption) {
749 - Element.show(this.element);
796 + tempOption = document.createElement('option');
750 - if (this.options.externalControl) {
797 + tempOption.value = '';
751 - Element.show(this.options.externalControl);
798 + this._controls.editor.appendChild(tempOption);
799 + tempOption.selected = true;
752 }
800 }
753 - this.editing = false;
801 + tempOption.update((text || '').stripScripts().stripTags());
754 - this.saving = false;
802 + },
755 - this.oldInnerHTML = null;
803 +
756 - this.onLeaveEditMode();
804 + checkForExternalText: function() {
805 + this._text = this.getText();
806 + if (this.options.loadTextURL)
807 + this.loadExternalText();
808 + else
809 + this.buildOptionList();
810 + },
811 +
812 + loadExternalText: function() {
813 + this.showLoadingText(this.options.loadingText);
814 + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
815 + Object.extend(options, {
816 + parameters: 'editorId=' + encodeURIComponent(this.element.id),
817 + onComplete: Prototype.emptyFunction,
818 + onSuccess: function(transport) {
819 + this._text = transport.responseText.strip();
820 + this.buildOptionList();
821 + }.bind(this),
822 + onFailure: this.onFailure
823 + });
824 + new Ajax.Request(this.options.loadTextURL, options);
757 },
825 },
758 - onComplete: function(transport) {
826 +
759 - this.leaveEditMode();
827 + buildOptionList: function() {
760 - this.options.onComplete.bind(this)(transport, this.element);
828 + this._form.removeClassName(this.options.loadingClassName);
761 - },
829 + this._collection = this._collection.map(function(entry) {
762 - onEnterEditMode: function() {},
830 + return 2 === entry.length ? entry : [entry, entry].flatten();
763 - onLeaveEditMode: function() {},
831 + });
764 - dispose: function() {
832 + var marker = ('value' in this.options) ? this.options.value : this._text;
765 - if (this.oldInnerHTML) {
833 + var textFound = this._collection.any(function(entry) {
766 - this.element.innerHTML = this.oldInnerHTML;
834 + return entry[0] == marker;
767 - }
835 + }.bind(this));
768 - this.leaveEditMode();
836 + this._controls.editor.update('');
769 - Event.stopObserving(this.element, 'click', this.onclickListener);
837 + var option;
770 - Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
838 + this._collection.each(function(entry, index) {
771 - Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
839 + option = document.createElement('option');
772 - if (this.options.externalControl) {
840 + option.value = entry[0];
773 - Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);
841 + option.selected = textFound ? entry[0] == marker : 0 == index;
774 - Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);
842 + option.appendChild(document.createTextNode(entry[1]));
775 - Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
843 + this._controls.editor.appendChild(option);
776 - }
844 + }.bind(this));
845 + this._controls.editor.disabled = false;
846 + Field.scrollFreeActivate(this._controls.editor);
777 }
847 }
848 + });
849 +
850 + //**** DEPRECATION LAYER FOR InPlace[Collection]Editor! ****
851 + //**** This only exists for a while, in order to let ****
852 + //**** users adapt to the new API. Read up on the new ****
853 + //**** API and convert your code to it ASAP! ****
854 +
855 + Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) {
856 + if (!options) return;
857 + function fallback(name, expr) {
858 + if (name in options || expr === undefined) return;
859 + options[name] = expr;
860 + };
861 + fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' :
862 + options.cancelLink == options.cancelButton == false ? false : undefined)));
863 + fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' :
864 + options.okLink == options.okButton == false ? false : undefined)));
865 + fallback('highlightColor', options.highlightcolor);
866 + fallback('highlightEndColor', options.highlightendcolor);
778 };
867 };
779
868
780 - Ajax.InPlaceCollectionEditor = Class.create();
869 + Object.extend(Ajax.InPlaceEditor, {
781 - Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype);
870 + DefaultOptions: {
782 - Object.extend(Ajax.InPlaceCollectionEditor.prototype, {
871 + ajaxOptions: { },
783 - createEditField: function() {
872 + autoRows: 3, // Use when multi-line w/ rows == 1
784 - if (!this.cached_selectTag) {
873 + cancelControl: 'link', // 'link'|'button'|false
785 - var selectTag = document.createElement("select");
874 + cancelText: 'cancel',
786 - var collection = this.options.collection || [];
875 + clickToEditText: 'Click to edit',
787 - var optionTag;
876 + externalControl: null, // id|elt
788 - collection.each(function(e,i) {
877 + externalControlOnly: false,
789 - optionTag = document.createElement("option");
878 + fieldPostCreation: 'activate', // 'activate'|'focus'|false
790 - optionTag.value = (e instanceof Array) ? e[0] : e;
879 + formClassName: 'inplaceeditor-form',
791 - if((typeof this.options.value == 'undefined') &&
880 + formId: null, // id|elt
792 - ((e instanceof Array) ? this.element.innerHTML == e[1] : e == optionTag.value)) optionTag.selected = true;
881 + highlightColor: '#ffff99',
793 - if(this.options.value==optionTag.value) optionTag.selected = true;
882 + highlightEndColor: '#ffffff',
794 - optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e));
883 + hoverClassName: '',
795 - selectTag.appendChild(optionTag);
884 + htmlResponse: true,
796 - }.bind(this));
885 + loadingClassName: 'inplaceeditor-loading',
797 - this.cached_selectTag = selectTag;
886 + loadingText: 'Loading...',
887 + okControl: 'button', // 'link'|'button'|false
888 + okText: 'ok',
889 + paramName: 'value',
890 + rows: 1, // If 1 and multi-line, uses autoRows
891 + savingClassName: 'inplaceeditor-saving',
892 + savingText: 'Saving...',
893 + size: 0,
894 + stripLoadedTextTags: false,
895 + submitOnBlur: false,
896 + textAfterControls: '',
897 + textBeforeControls: '',
898 + textBetweenControls: ''
899 + },
900 + DefaultCallbacks: {
901 + callback: function(form) {
902 + return Form.serialize(form);
903 + },
904 + onComplete: function(transport, element) {
905 + // For backward compatibility, this one is bound to the IPE, and passes
906 + // the element directly. It was too often customized, so we don't break it.
907 + new Effect.Highlight(element, {
908 + startcolor: this.options.highlightColor, keepBackgroundImage: true });
909 + },
910 + onEnterEditMode: null,
911 + onEnterHover: function(ipe) {
912 + ipe.element.style.backgroundColor = ipe.options.highlightColor;
913 + if (ipe._effect)
914 + ipe._effect.cancel();
915 + },
916 + onFailure: function(transport, ipe) {
917 + alert('Error communication with the server: ' + transport.responseText.stripTags());
918 + },
919 + onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls.
920 + onLeaveEditMode: null,
921 + onLeaveHover: function(ipe) {
922 + ipe._effect = new Effect.Highlight(ipe.element, {
923 + startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor,
924 + restorecolor: ipe._originalBackground, keepBackgroundImage: true
925 + });
798 }
926 }
799 -
927 + },
800 - this.editField = this.cached_selectTag;
928 + Listeners: {
801 - if(this.options.loadTextURL) this.loadExternalText();
929 + click: 'enterEditMode',
802 - this.form.appendChild(this.editField);
930 + keydown: 'checkForEscapeOrReturn',
803 - this.options.callback = function(form, value) {
931 + mouseover: 'enterHover',
804 - return "value=" + encodeURIComponent(value);
932 + mouseout: 'leaveHover'
805 - }
806 }
933 }
807 });
934 });
808
935
936 + Ajax.InPlaceCollectionEditor.DefaultOptions = {
937 + loadingCollectionText: 'Loading options...'
938 + };
939 +
809 // Delayed observer, like Form.Element.Observer,
940 // Delayed observer, like Form.Element.Observer,
810 // but waits for delay after last key input
941 // but waits for delay after last key input
811 // Ideal for live-search fields
942 // Ideal for live-search fields
812
943
813 - Form.Element.DelayedObserver = Class.create();
944 + Form.Element.DelayedObserver = Class.create({
814 - Form.Element.DelayedObserver.prototype = {
815 initialize: function(element, delay, callback) {
945 initialize: function(element, delay, callback) {
816 this.delay = delay || 0.5;
946 this.delay = delay || 0.5;
817 this.element = $(element);
947 this.element = $(element);
@@ -830,4 +960,4
830 this.timer = null;
960 this.timer = null;
831 this.callback(this.element, $F(this.element));
961 this.callback(this.element, $F(this.element));
832 }
962 }
833 - };
963 + });
@@ -1,10 +1,10
1 - // Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
1 + // Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
2 - // (c) 2005, 2006 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
2 + // (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
3 //
3 //
4 // script.aculo.us is freely distributable under the terms of an MIT-style license.
4 // script.aculo.us is freely distributable under the terms of an MIT-style license.
5 // For details, see the script.aculo.us web site: http://script.aculo.us/
5 // For details, see the script.aculo.us web site: http://script.aculo.us/
6
6
7 - if(typeof Effect == 'undefined')
7 + if(Object.isUndefined(Effect))
8 throw("dragdrop.js requires including script.aculo.us' effects.js library");
8 throw("dragdrop.js requires including script.aculo.us' effects.js library");
9
9
10 var Droppables = {
10 var Droppables = {
@@ -20,14 +20,13
20 greedy: true,
20 greedy: true,
21 hoverclass: null,
21 hoverclass: null,
22 tree: false
22 tree: false
23 - }, arguments[1] || {});
23 + }, arguments[1] || { });
24
24
25 // cache containers
25 // cache containers
26 if(options.containment) {
26 if(options.containment) {
27 options._containers = [];
27 options._containers = [];
28 var containment = options.containment;
28 var containment = options.containment;
29 - if((typeof containment == 'object') &&
29 + if(Object.isArray(containment)) {
30 - (containment.constructor == Array)) {
31 containment.each( function(c) { options._containers.push($(c)) });
30 containment.each( function(c) { options._containers.push($(c)) });
32 } else {
31 } else {
33 options._containers.push($(containment));
32 options._containers.push($(containment));
@@ -87,21 +86,23
87
86
88 show: function(point, element) {
87 show: function(point, element) {
89 if(!this.drops.length) return;
88 if(!this.drops.length) return;
90 - var affected = [];
89 + var drop, affected = [];
91
90
92 - if(this.last_active) this.deactivate(this.last_active);
93 this.drops.each( function(drop) {
91 this.drops.each( function(drop) {
94 if(Droppables.isAffected(point, element, drop))
92 if(Droppables.isAffected(point, element, drop))
95 affected.push(drop);
93 affected.push(drop);
96 });
94 });
97
95
98 - if(affected.length>0) {
96 + if(affected.length>0)
99 drop = Droppables.findDeepestChild(affected);
97 drop = Droppables.findDeepestChild(affected);
98 +
99 + if(this.last_active && this.last_active != drop) this.deactivate(this.last_active);
100 + if (drop) {
100 Position.within(drop.element, point[0], point[1]);
101 Position.within(drop.element, point[0], point[1]);
101 if(drop.onHover)
102 if(drop.onHover)
102 drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
103 drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
103
104
104 - Droppables.activate(drop);
105 + if (drop != this.last_active) Droppables.activate(drop);
105 }
106 }
106 },
107 },
107
108
@@ -110,8 +111,10
110 Position.prepare();
111 Position.prepare();
111
112
112 if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
113 if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
113 - if (this.last_active.onDrop)
114 + if (this.last_active.onDrop) {
114 - this.last_active.onDrop(element, this.last_active.element, event);
115 + this.last_active.onDrop(element, this.last_active.element, event);
116 + return true;
117 + }
115 },
118 },
116
119
117 reset: function() {
120 reset: function() {
@@ -219,10 +222,7
219
222
220 /*--------------------------------------------------------------------------*/
223 /*--------------------------------------------------------------------------*/
221
224
222 - var Draggable = Class.create();
225 + var Draggable = Class.create({
223 - Draggable._dragging = {};
224 -
225 - Draggable.prototype = {
226 initialize: function(element) {
226 initialize: function(element) {
227 var defaults = {
227 var defaults = {
228 handle: false,
228 handle: false,
@@ -233,7 +233,7
233 });
233 });
234 },
234 },
235 endeffect: function(element) {
235 endeffect: function(element) {
236 - var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0;
236 + var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0;
237 new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
237 new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
238 queue: {scope:'_draggable', position:'end'},
238 queue: {scope:'_draggable', position:'end'},
239 afterFinish: function(){
239 afterFinish: function(){
@@ -243,6 +243,7
243 },
243 },
244 zindex: 1000,
244 zindex: 1000,
245 revert: false,
245 revert: false,
246 + quiet: false,
246 scroll: false,
247 scroll: false,
247 scrollSensitivity: 20,
248 scrollSensitivity: 20,
248 scrollSpeed: 15,
249 scrollSpeed: 15,
@@ -250,7 +251,7
250 delay: 0
251 delay: 0
251 };
252 };
252
253
253 - if(!arguments[1] || typeof arguments[1].endeffect == 'undefined')
254 + if(!arguments[1] || Object.isUndefined(arguments[1].endeffect))
254 Object.extend(defaults, {
255 Object.extend(defaults, {
255 starteffect: function(element) {
256 starteffect: function(element) {
256 element._opacity = Element.getOpacity(element);
257 element._opacity = Element.getOpacity(element);
@@ -259,11 +260,11
259 }
260 }
260 });
261 });
261
262
262 - var options = Object.extend(defaults, arguments[1] || {});
263 + var options = Object.extend(defaults, arguments[1] || { });
263
264
264 this.element = $(element);
265 this.element = $(element);
265
266
266 - if(options.handle && (typeof options.handle == 'string'))
267 + if(options.handle && Object.isString(options.handle))
267 this.handle = this.element.down('.'+options.handle, 0);
268 this.handle = this.element.down('.'+options.handle, 0);
268
269
269 if(!this.handle) this.handle = $(options.handle);
270 if(!this.handle) this.handle = $(options.handle);
@@ -276,7 +277,6
276
277
277 Element.makePositioned(this.element); // fix IE
278 Element.makePositioned(this.element); // fix IE
278
279
279 - this.delta = this.currentDelta();
280 this.options = options;
280 this.options = options;
281 this.dragging = false;
281 this.dragging = false;
282
282
@@ -298,17 +298,17
298 },
298 },
299
299
300 initDrag: function(event) {
300 initDrag: function(event) {
301 - if(typeof Draggable._dragging[this.element] != 'undefined' &&
301 + if(!Object.isUndefined(Draggable._dragging[this.element]) &&
302 Draggable._dragging[this.element]) return;
302 Draggable._dragging[this.element]) return;
303 if(Event.isLeftClick(event)) {
303 if(Event.isLeftClick(event)) {
304 // abort on form elements, fixes a Firefox issue
304 // abort on form elements, fixes a Firefox issue
305 var src = Event.element(event);
305 var src = Event.element(event);
306 - if(src.tagName && (
306 + if((tag_name = src.tagName.toUpperCase()) && (
307 - src.tagName=='INPUT' ||
307 + tag_name=='INPUT' ||
308 - src.tagName=='SELECT' ||
308 + tag_name=='SELECT' ||
309 - src.tagName=='OPTION' ||
309 + tag_name=='OPTION' ||
310 - src.tagName=='BUTTON' ||
310 + tag_name=='BUTTON' ||
311 - src.tagName=='TEXTAREA')) return;
311 + tag_name=='TEXTAREA')) return;
312
312
313 var pointer = [Event.pointerX(event), Event.pointerY(event)];
313 var pointer = [Event.pointerX(event), Event.pointerY(event)];
314 var pos = Position.cumulativeOffset(this.element);
314 var pos = Position.cumulativeOffset(this.element);
@@ -321,6 +321,8
321
321
322 startDrag: function(event) {
322 startDrag: function(event) {
323 this.dragging = true;
323 this.dragging = true;
324 + if(!this.delta)
325 + this.delta = this.currentDelta();
324
326
325 if(this.options.zindex) {
327 if(this.options.zindex) {
326 this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
328 this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
@@ -329,7 +331,9
329
331
330 if(this.options.ghosting) {
332 if(this.options.ghosting) {
331 this._clone = this.element.cloneNode(true);
333 this._clone = this.element.cloneNode(true);
332 - Position.absolutize(this.element);
334 + this.element._originallyAbsolute = (this.element.getStyle('position') == 'absolute');
335 + if (!this.element._originallyAbsolute)
336 + Position.absolutize(this.element);
333 this.element.parentNode.insertBefore(this._clone, this.element);
337 this.element.parentNode.insertBefore(this._clone, this.element);
334 }
338 }
335
339
@@ -351,8 +355,12
351
355
352 updateDrag: function(event, pointer) {
356 updateDrag: function(event, pointer) {
353 if(!this.dragging) this.startDrag(event);
357 if(!this.dragging) this.startDrag(event);
354 - Position.prepare();
358 +
355 - Droppables.show(pointer, this.element);
359 + if(!this.options.quiet){
360 + Position.prepare();
361 + Droppables.show(pointer, this.element);
362 + }
363 +
356 Draggables.notify('onDrag', this, event);
364 Draggables.notify('onDrag', this, event);
357
365
358 this.draw(pointer);
366 this.draw(pointer);
@@ -380,30 +388,44
380 }
388 }
381
389
382 // fix AppleWebKit rendering
390 // fix AppleWebKit rendering
383 - if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
391 + if(Prototype.Browser.WebKit) window.scrollBy(0,0);
384
392
385 Event.stop(event);
393 Event.stop(event);
386 },
394 },
387
395
388 finishDrag: function(event, success) {
396 finishDrag: function(event, success) {
389 this.dragging = false;
397 this.dragging = false;
398 +
399 + if(this.options.quiet){
400 + Position.prepare();
401 + var pointer = [Event.pointerX(event), Event.pointerY(event)];
402 + Droppables.show(pointer, this.element);
403 + }
390
404
391 if(this.options.ghosting) {
405 if(this.options.ghosting) {
392 - Position.relativize(this.element);
406 + if (!this.element._originallyAbsolute)
407 + Position.relativize(this.element);
408 + delete this.element._originallyAbsolute;
393 Element.remove(this._clone);
409 Element.remove(this._clone);
394 this._clone = null;
410 this._clone = null;
395 }
411 }
396
412
397 - if(success) Droppables.fire(event, this.element);
413 + var dropped = false;
414 + if(success) {
415 + dropped = Droppables.fire(event, this.element);
416 + if (!dropped) dropped = false;
417 + }
418 + if(dropped && this.options.onDropped) this.options.onDropped(this.element);
398 Draggables.notify('onEnd', this, event);
419 Draggables.notify('onEnd', this, event);
399
420
400 var revert = this.options.revert;
421 var revert = this.options.revert;
401 - if(revert && typeof revert == 'function') revert = revert(this.element);
422 + if(revert && Object.isFunction(revert)) revert = revert(this.element);
402
423
403 var d = this.currentDelta();
424 var d = this.currentDelta();
404 if(revert && this.options.reverteffect) {
425 if(revert && this.options.reverteffect) {
405 - this.options.reverteffect(this.element,
426 + if (dropped == 0 || revert != 'failure')
406 - d[1]-this.delta[1], d[0]-this.delta[0]);
427 + this.options.reverteffect(this.element,
428 + d[1]-this.delta[1], d[0]-this.delta[0]);
407 } else {
429 } else {
408 this.delta = d;
430 this.delta = d;
409 }
431 }
@@ -451,15 +473,15
451 }.bind(this));
473 }.bind(this));
452
474
453 if(this.options.snap) {
475 if(this.options.snap) {
454 - if(typeof this.options.snap == 'function') {
476 + if(Object.isFunction(this.options.snap)) {
455 p = this.options.snap(p[0],p[1],this);
477 p = this.options.snap(p[0],p[1],this);
456 } else {
478 } else {
457 - if(this.options.snap instanceof Array) {
479 + if(Object.isArray(this.options.snap)) {
458 p = p.map( function(v, i) {
480 p = p.map( function(v, i) {
459 - return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
481 + return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this))
460 } else {
482 } else {
461 p = p.map( function(v) {
483 p = p.map( function(v) {
462 - return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
484 + return (v/this.options.snap).round()*this.options.snap }.bind(this))
463 }
485 }
464 }}
486 }}
465
487
@@ -543,12 +565,13
543 }
565 }
544 return { top: T, left: L, width: W, height: H };
566 return { top: T, left: L, width: W, height: H };
545 }
567 }
546 - }
568 + });
569 +
570 + Draggable._dragging = { };
547
571
548 /*--------------------------------------------------------------------------*/
572 /*--------------------------------------------------------------------------*/
549
573
550 - var SortableObserver = Class.create();
574 + var SortableObserver = Class.create({
551 - SortableObserver.prototype = {
552 initialize: function(element, observer) {
575 initialize: function(element, observer) {
553 this.element = $(element);
576 this.element = $(element);
554 this.observer = observer;
577 this.observer = observer;
@@ -564,15 +587,15
564 if(this.lastValue != Sortable.serialize(this.element))
587 if(this.lastValue != Sortable.serialize(this.element))
565 this.observer(this.element)
588 this.observer(this.element)
566 }
589 }
567 - }
590 + });
568
591
569 var Sortable = {
592 var Sortable = {
570 SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
593 SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
571
594
572 - sortables: {},
595 + sortables: { },
573
596
574 _findRootElement: function(element) {
597 _findRootElement: function(element) {
575 - while (element.tagName != "BODY") {
598 + while (element.tagName.toUpperCase() != "BODY") {
576 if(element.id && Sortable.sortables[element.id]) return element;
599 if(element.id && Sortable.sortables[element.id]) return element;
577 element = element.parentNode;
600 element = element.parentNode;
578 }
601 }
@@ -612,13 +635,20
612 delay: 0,
635 delay: 0,
613 hoverclass: null,
636 hoverclass: null,
614 ghosting: false,
637 ghosting: false,
638 + quiet: false,
615 scroll: false,
639 scroll: false,
616 scrollSensitivity: 20,
640 scrollSensitivity: 20,
617 scrollSpeed: 15,
641 scrollSpeed: 15,
618 format: this.SERIALIZE_RULE,
642 format: this.SERIALIZE_RULE,
643 +
644 + // these take arrays of elements or ids and can be
645 + // used for better initialization performance
646 + elements: false,
647 + handles: false,
648 +
619 onChange: Prototype.emptyFunction,
649 onChange: Prototype.emptyFunction,
620 onUpdate: Prototype.emptyFunction
650 onUpdate: Prototype.emptyFunction
621 - }, arguments[1] || {});
651 + }, arguments[1] || { });
622
652
623 // clear any old sortable with same element
653 // clear any old sortable with same element
624 this.destroy(element);
654 this.destroy(element);
@@ -626,6 +656,7
626 // build options for the draggables
656 // build options for the draggables
627 var options_for_draggable = {
657 var options_for_draggable = {
628 revert: true,
658 revert: true,
659 + quiet: options.quiet,
629 scroll: options.scroll,
660 scroll: options.scroll,
630 scrollSpeed: options.scrollSpeed,
661 scrollSpeed: options.scrollSpeed,
631 scrollSensitivity: options.scrollSensitivity,
662 scrollSensitivity: options.scrollSensitivity,
@@ -679,10 +710,9
679 options.droppables.push(element);
710 options.droppables.push(element);
680 }
711 }
681
712
682 - (this.findElements(element, options) || []).each( function(e) {
713 + (options.elements || this.findElements(element, options) || []).each( function(e,i) {
683 - // handles are per-draggable
714 + var handle = options.handles ? $(options.handles[i]) :
684 - var handle = options.handle ?
715 + (options.handle ? $(e).select('.' + options.handle)[0] : e);
685 - $(e).down('.'+options.handle,0) : e;
686 options.draggables.push(
716 options.draggables.push(
687 new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
717 new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
688 Droppables.add(e, options_for_droppable);
718 Droppables.add(e, options_for_droppable);
@@ -842,7 +872,7
842 only: sortableOptions.only,
872 only: sortableOptions.only,
843 name: element.id,
873 name: element.id,
844 format: sortableOptions.format
874 format: sortableOptions.format
845 - }, arguments[1] || {});
875 + }, arguments[1] || { });
846
876
847 var root = {
877 var root = {
848 id: null,
878 id: null,
@@ -866,7 +896,7
866
896
867 sequence: function(element) {
897 sequence: function(element) {
868 element = $(element);
898 element = $(element);
869 - var options = Object.extend(this.options(element), arguments[1] || {});
899 + var options = Object.extend(this.options(element), arguments[1] || { });
870
900
871 return $(this.findElements(element, options) || []).map( function(item) {
901 return $(this.findElements(element, options) || []).map( function(item) {
872 return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
902 return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
@@ -875,9 +905,9
875
905
876 setSequence: function(element, new_sequence) {
906 setSequence: function(element, new_sequence) {
877 element = $(element);
907 element = $(element);
878 - var options = Object.extend(this.options(element), arguments[2] || {});
908 + var options = Object.extend(this.options(element), arguments[2] || { });
879
909
880 - var nodeMap = {};
910 + var nodeMap = { };
881 this.findElements(element, options).each( function(n) {
911 this.findElements(element, options).each( function(n) {
882 if (n.id.match(options.format))
912 if (n.id.match(options.format))
883 nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
913 nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
@@ -895,7 +925,7
895
925
896 serialize: function(element) {
926 serialize: function(element) {
897 element = $(element);
927 element = $(element);
898 - var options = Object.extend(Sortable.options(element), arguments[1] || {});
928 + var options = Object.extend(Sortable.options(element), arguments[1] || { });
899 var name = encodeURIComponent(
929 var name = encodeURIComponent(
900 (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
930 (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
901
931
@@ -919,7 +949,7
919 return Element.isParent(child.parentNode, element);
949 return Element.isParent(child.parentNode, element);
920 }
950 }
921
951
922 - Element.findChildren = function(element, only, recursive, tagName) {
952 + Element.findChildren = function(element, only, recursive, tagName) {
923 if(!element.hasChildNodes()) return null;
953 if(!element.hasChildNodes()) return null;
924 tagName = tagName.toUpperCase();
954 tagName = tagName.toUpperCase();
925 if(only) only = [only].flatten();
955 if(only) only = [only].flatten();
This diff has been collapsed as it changes many lines, (760 lines changed) Show them Hide them
@@ -1,4 +1,4
1 - // Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
1 + // Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
2 // Contributors:
2 // Contributors:
3 // Justin Palmer (http://encytemedia.com/)
3 // Justin Palmer (http://encytemedia.com/)
4 // Mark Pilgrim (http://diveintomark.org/)
4 // Mark Pilgrim (http://diveintomark.org/)
@@ -11,17 +11,17
11 // returns self (or first argument) if not convertable
11 // returns self (or first argument) if not convertable
12 String.prototype.parseColor = function() {
12 String.prototype.parseColor = function() {
13 var color = '#';
13 var color = '#';
14 - if(this.slice(0,4) == 'rgb(') {
14 + if (this.slice(0,4) == 'rgb(') {
15 var cols = this.slice(4,this.length-1).split(',');
15 var cols = this.slice(4,this.length-1).split(',');
16 var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
16 var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
17 } else {
17 } else {
18 - if(this.slice(0,1) == '#') {
18 + if (this.slice(0,1) == '#') {
19 - if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
19 + if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
20 - if(this.length==7) color = this.toLowerCase();
20 + if (this.length==7) color = this.toLowerCase();
21 }
21 }
22 }
22 }
23 - return(color.length==7 ? color : (arguments[0] || this));
23 + return (color.length==7 ? color : (arguments[0] || this));
24 - }
24 + };
25
25
26 /*--------------------------------------------------------------------------*/
26 /*--------------------------------------------------------------------------*/
27
27
@@ -30,7 +30,7
30 return (node.nodeType==3 ? node.nodeValue :
30 return (node.nodeType==3 ? node.nodeValue :
31 (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
31 (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
32 }).flatten().join('');
32 }).flatten().join('');
33 - }
33 + };
34
34
35 Element.collectTextNodesIgnoreClass = function(element, className) {
35 Element.collectTextNodesIgnoreClass = function(element, className) {
36 return $A($(element).childNodes).collect( function(node) {
36 return $A($(element).childNodes).collect( function(node) {
@@ -38,47 +38,18
38 ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
38 ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
39 Element.collectTextNodesIgnoreClass(node, className) : ''));
39 Element.collectTextNodesIgnoreClass(node, className) : ''));
40 }).flatten().join('');
40 }).flatten().join('');
41 - }
41 + };
42
42
43 Element.setContentZoom = function(element, percent) {
43 Element.setContentZoom = function(element, percent) {
44 element = $(element);
44 element = $(element);
45 element.setStyle({fontSize: (percent/100) + 'em'});
45 element.setStyle({fontSize: (percent/100) + 'em'});
46 - if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
46 + if (Prototype.Browser.WebKit) window.scrollBy(0,0);
47 return element;
47 return element;
48 - }
48 + };
49 -
50 - Element.getOpacity = function(element){
51 - element = $(element);
52 - var opacity;
53 - if (opacity = element.getStyle('opacity'))
54 - return parseFloat(opacity);
55 - if (opacity = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
56 - if(opacity[1]) return parseFloat(opacity[1]) / 100;
57 - return 1.0;
58 - }
59
49
60 - Element.setOpacity = function(element, value){
50 + Element.getInlineOpacity = function(element){
61 - element= $(element);
62 - if (value == 1){
63 - element.setStyle({ opacity:
64 - (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ?
65 - 0.999999 : 1.0 });
66 - if(/MSIE/.test(navigator.userAgent) && !window.opera)
67 - element.setStyle({filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')});
68 - } else {
69 - if(value < 0.00001) value = 0;
70 - element.setStyle({opacity: value});
71 - if(/MSIE/.test(navigator.userAgent) && !window.opera)
72 - element.setStyle(
73 - { filter: element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') +
74 - 'alpha(opacity='+value*100+')' });
75 - }
76 - return element;
77 - }
78 -
79 - Element.getInlineOpacity = function(element){
80 return $(element).style.opacity || '';
51 return $(element).style.opacity || '';
81 - }
52 + };
82
53
83 Element.forceRerendering = function(element) {
54 Element.forceRerendering = function(element) {
84 try {
55 try {
@@ -91,31 +62,63
91
62
92 /*--------------------------------------------------------------------------*/
63 /*--------------------------------------------------------------------------*/
93
64
94 - Array.prototype.call = function() {
95 - var args = arguments;
96 - this.each(function(f){ f.apply(this, args) });
97 - }
98 -
99 - /*--------------------------------------------------------------------------*/
100 -
101 var Effect = {
65 var Effect = {
102 _elementDoesNotExistError: {
66 _elementDoesNotExistError: {
103 name: 'ElementDoesNotExistError',
67 name: 'ElementDoesNotExistError',
104 message: 'The specified DOM element does not exist, but is required for this effect to operate'
68 message: 'The specified DOM element does not exist, but is required for this effect to operate'
105 },
69 },
70 + Transitions: {
71 + linear: Prototype.K,
72 + sinoidal: function(pos) {
73 + return (-Math.cos(pos*Math.PI)/2) + 0.5;
74 + },
75 + reverse: function(pos) {
76 + return 1-pos;
77 + },
78 + flicker: function(pos) {
79 + var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
80 + return pos > 1 ? 1 : pos;
81 + },
82 + wobble: function(pos) {
83 + return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
84 + },
85 + pulse: function(pos, pulses) {
86 + pulses = pulses || 5;
87 + return (
88 + ((pos % (1/pulses)) * pulses).round() == 0 ?
89 + ((pos * pulses * 2) - (pos * pulses * 2).floor()) :
90 + 1 - ((pos * pulses * 2) - (pos * pulses * 2).floor())
91 + );
92 + },
93 + spring: function(pos) {
94 + return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
95 + },
96 + none: function(pos) {
97 + return 0;
98 + },
99 + full: function(pos) {
100 + return 1;
101 + }
102 + },
103 + DefaultOptions: {
104 + duration: 1.0, // seconds
105 + fps: 100, // 100= assume 66fps max.
106 + sync: false, // true for combining
107 + from: 0.0,
108 + to: 1.0,
109 + delay: 0.0,
110 + queue: 'parallel'
111 + },
106 tagifyText: function(element) {
112 tagifyText: function(element) {
107 - if(typeof Builder == 'undefined')
108 - throw("Effect.tagifyText requires including script.aculo.us' builder.js library");
109 -
110 var tagifyStyle = 'position:relative';
113 var tagifyStyle = 'position:relative';
111 - if(/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1';
114 + if (Prototype.Browser.IE) tagifyStyle += ';zoom:1';
112
115
113 element = $(element);
116 element = $(element);
114 $A(element.childNodes).each( function(child) {
117 $A(element.childNodes).each( function(child) {
115 - if(child.nodeType==3) {
118 + if (child.nodeType==3) {
116 child.nodeValue.toArray().each( function(character) {
119 child.nodeValue.toArray().each( function(character) {
117 element.insertBefore(
120 element.insertBefore(
118 - Builder.node('span',{style: tagifyStyle},
121 + new Element('span', {style: tagifyStyle}).update(
119 character == ' ' ? String.fromCharCode(160) : character),
122 character == ' ' ? String.fromCharCode(160) : character),
120 child);
123 child);
121 });
124 });
@@ -125,8 +128,8
125 },
128 },
126 multiple: function(element, effect) {
129 multiple: function(element, effect) {
127 var elements;
130 var elements;
128 - if(((typeof element == 'object') ||
131 + if (((typeof element == 'object') ||
129 - (typeof element == 'function')) &&
132 + Object.isFunction(element)) &&
130 (element.length))
133 (element.length))
131 elements = element;
134 elements = element;
132 else
135 else
@@ -135,7 +138,7
135 var options = Object.extend({
138 var options = Object.extend({
136 speed: 0.1,
139 speed: 0.1,
137 delay: 0.0
140 delay: 0.0
138 - }, arguments[2] || {});
141 + }, arguments[2] || { });
139 var masterDelay = options.delay;
142 var masterDelay = options.delay;
140
143
141 $A(elements).each( function(element, index) {
144 $A(elements).each( function(element, index) {
@@ -152,53 +155,20
152 effect = (effect || 'appear').toLowerCase();
155 effect = (effect || 'appear').toLowerCase();
153 var options = Object.extend({
156 var options = Object.extend({
154 queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
157 queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
155 - }, arguments[2] || {});
158 + }, arguments[2] || { });
156 Effect[element.visible() ?
159 Effect[element.visible() ?
157 Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
160 Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
158 }
161 }
159 };
162 };
160
163
161 - var Effect2 = Effect; // deprecated
164 + Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;
162 -
163 - /* ------------- transitions ------------- */
164 -
165 - Effect.Transitions = {
166 - linear: Prototype.K,
167 - sinoidal: function(pos) {
168 - return (-Math.cos(pos*Math.PI)/2) + 0.5;
169 - },
170 - reverse: function(pos) {
171 - return 1-pos;
172 - },
173 - flicker: function(pos) {
174 - return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
175 - },
176 - wobble: function(pos) {
177 - return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
178 - },
179 - pulse: function(pos, pulses) {
180 - pulses = pulses || 5;
181 - return (
182 - Math.round((pos % (1/pulses)) * pulses) == 0 ?
183 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) :
184 - 1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
185 - );
186 - },
187 - none: function(pos) {
188 - return 0;
189 - },
190 - full: function(pos) {
191 - return 1;
192 - }
193 - };
194
165
195 /* ------------- core effects ------------- */
166 /* ------------- core effects ------------- */
196
167
197 - Effect.ScopedQueue = Class.create();
168 + Effect.ScopedQueue = Class.create(Enumerable, {
198 - Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
199 initialize: function() {
169 initialize: function() {
200 this.effects = [];
170 this.effects = [];
201 - this.interval = null;
171 + this.interval = null;
202 },
172 },
203 _each: function(iterator) {
173 _each: function(iterator) {
204 this.effects._each(iterator);
174 this.effects._each(iterator);
@@ -206,7 +176,7
206 add: function(effect) {
176 add: function(effect) {
207 var timestamp = new Date().getTime();
177 var timestamp = new Date().getTime();
208
178
209 - var position = (typeof effect.options.queue == 'string') ?
179 + var position = Object.isString(effect.options.queue) ?
210 effect.options.queue : effect.options.queue.position;
180 effect.options.queue : effect.options.queue.position;
211
181
212 switch(position) {
182 switch(position) {
@@ -229,115 +199,111
229 effect.startOn += timestamp;
199 effect.startOn += timestamp;
230 effect.finishOn += timestamp;
200 effect.finishOn += timestamp;
231
201
232 - if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
202 + if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
233 this.effects.push(effect);
203 this.effects.push(effect);
234
204
235 - if(!this.interval)
205 + if (!this.interval)
236 - this.interval = setInterval(this.loop.bind(this), 40);
206 + this.interval = setInterval(this.loop.bind(this), 15);
237 },
207 },
238 remove: function(effect) {
208 remove: function(effect) {
239 this.effects = this.effects.reject(function(e) { return e==effect });
209 this.effects = this.effects.reject(function(e) { return e==effect });
240 - if(this.effects.length == 0) {
210 + if (this.effects.length == 0) {
241 clearInterval(this.interval);
211 clearInterval(this.interval);
242 this.interval = null;
212 this.interval = null;
243 }
213 }
244 },
214 },
245 loop: function() {
215 loop: function() {
246 var timePos = new Date().getTime();
216 var timePos = new Date().getTime();
247 - this.effects.invoke('loop', timePos);
217 + for(var i=0, len=this.effects.length;i<len;i++)
218 + this.effects[i] && this.effects[i].loop(timePos);
248 }
219 }
249 });
220 });
250
221
251 Effect.Queues = {
222 Effect.Queues = {
252 instances: $H(),
223 instances: $H(),
253 get: function(queueName) {
224 get: function(queueName) {
254 - if(typeof queueName != 'string') return queueName;
225 + if (!Object.isString(queueName)) return queueName;
255
226
256 - if(!this.instances[queueName])
227 + return this.instances.get(queueName) ||
257 - this.instances[queueName] = new Effect.ScopedQueue();
228 + this.instances.set(queueName, new Effect.ScopedQueue());
258 -
259 - return this.instances[queueName];
260 }
229 }
261 - }
230 + };
262 Effect.Queue = Effect.Queues.get('global');
231 Effect.Queue = Effect.Queues.get('global');
263
232
264 - Effect.DefaultOptions = {
233 + Effect.Base = Class.create({
265 - transition: Effect.Transitions.sinoidal,
266 - duration: 1.0, // seconds
267 - fps: 25.0, // max. 25fps due to Effect.Queue implementation
268 - sync: false, // true for combining
269 - from: 0.0,
270 - to: 1.0,
271 - delay: 0.0,
272 - queue: 'parallel'
273 - }
274 -
275 - Effect.Base = function() {};
276 - Effect.Base.prototype = {
277 position: null,
234 position: null,
278 start: function(options) {
235 start: function(options) {
279 - this.options = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
236 + function codeForEvent(options,eventName){
237 + return (
238 + (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
239 + (options[eventName] ? 'this.options.'+eventName+'(this);' : '')
240 + );
241 + }
242 + if (options && options.transition === false) options.transition = Effect.Transitions.linear;
243 + this.options = Object.extend(Object.extend({ },Effect.DefaultOptions), options || { });
280 this.currentFrame = 0;
244 this.currentFrame = 0;
281 this.state = 'idle';
245 this.state = 'idle';
282 this.startOn = this.options.delay*1000;
246 this.startOn = this.options.delay*1000;
283 - this.finishOn = this.startOn + (this.options.duration*1000);
247 + this.finishOn = this.startOn+(this.options.duration*1000);
248 + this.fromToDelta = this.options.to-this.options.from;
249 + this.totalTime = this.finishOn-this.startOn;
250 + this.totalFrames = this.options.fps*this.options.duration;
251 +
252 + eval('this.render = function(pos){ '+
253 + 'if (this.state=="idle"){this.state="running";'+
254 + codeForEvent(this.options,'beforeSetup')+
255 + (this.setup ? 'this.setup();':'')+
256 + codeForEvent(this.options,'afterSetup')+
257 + '};if (this.state=="running"){'+
258 + 'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';'+
259 + 'this.position=pos;'+
260 + codeForEvent(this.options,'beforeUpdate')+
261 + (this.update ? 'this.update(pos);':'')+
262 + codeForEvent(this.options,'afterUpdate')+
263 + '}}');
264 +
284 this.event('beforeStart');
265 this.event('beforeStart');
285 - if(!this.options.sync)
266 + if (!this.options.sync)
286 - Effect.Queues.get(typeof this.options.queue == 'string' ?
267 + Effect.Queues.get(Object.isString(this.options.queue) ?
287 'global' : this.options.queue.scope).add(this);
268 'global' : this.options.queue.scope).add(this);
288 },
269 },
289 loop: function(timePos) {
270 loop: function(timePos) {
290 - if(timePos >= this.startOn) {
271 + if (timePos >= this.startOn) {
291 - if(timePos >= this.finishOn) {
272 + if (timePos >= this.finishOn) {
292 this.render(1.0);
273 this.render(1.0);
293 this.cancel();
274 this.cancel();
294 this.event('beforeFinish');
275 this.event('beforeFinish');
295 - if(this.finish) this.finish();
276 + if (this.finish) this.finish();
296 this.event('afterFinish');
277 this.event('afterFinish');
297 return;
278 return;
298 }
279 }
299 - var pos = (timePos - this.startOn) / (this.finishOn - this.startOn);
280 + var pos = (timePos - this.startOn) / this.totalTime,
300 - var frame = Math.round(pos * this.options.fps * this.options.duration);
281 + frame = (pos * this.totalFrames).round();
301 - if(frame > this.currentFrame) {
282 + if (frame > this.currentFrame) {
302 this.render(pos);
283 this.render(pos);
303 this.currentFrame = frame;
284 this.currentFrame = frame;
304 }
285 }
305 }
286 }
306 },
287 },
307 - render: function(pos) {
308 - if(this.state == 'idle') {
309 - this.state = 'running';
310 - this.event('beforeSetup');
311 - if(this.setup) this.setup();
312 - this.event('afterSetup');
313 - }
314 - if(this.state == 'running') {
315 - if(this.options.transition) pos = this.options.transition(pos);
316 - pos *= (this.options.to-this.options.from);
317 - pos += this.options.from;
318 - this.position = pos;
319 - this.event('beforeUpdate');
320 - if(this.update) this.update(pos);
321 - this.event('afterUpdate');
322 - }
323 - },
324 cancel: function() {
288 cancel: function() {
325 - if(!this.options.sync)
289 + if (!this.options.sync)
326 - Effect.Queues.get(typeof this.options.queue == 'string' ?
290 + Effect.Queues.get(Object.isString(this.options.queue) ?
327 'global' : this.options.queue.scope).remove(this);
291 'global' : this.options.queue.scope).remove(this);
328 this.state = 'finished';
292 this.state = 'finished';
329 },
293 },
330 event: function(eventName) {
294 event: function(eventName) {
331 - if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
295 + if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
332 - if(this.options[eventName]) this.options[eventName](this);
296 + if (this.options[eventName]) this.options[eventName](this);
333 },
297 },
334 inspect: function() {
298 inspect: function() {
335 - return '#<Effect:' + $H(this).inspect() + ',options:' + $H(this.options).inspect() + '>';
299 + var data = $H();
300 + for(property in this)
301 + if (!Object.isFunction(this[property])) data.set(property, this[property]);
302 + return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
336 }
303 }
337 - }
304 + });
338
305
339 - Effect.Parallel = Class.create();
306 + Effect.Parallel = Class.create(Effect.Base, {
340 - Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
341 initialize: function(effects) {
307 initialize: function(effects) {
342 this.effects = effects || [];
308 this.effects = effects || [];
343 this.start(arguments[1]);
309 this.start(arguments[1]);
@@ -350,35 +316,45
350 effect.render(1.0);
316 effect.render(1.0);
351 effect.cancel();
317 effect.cancel();
352 effect.event('beforeFinish');
318 effect.event('beforeFinish');
353 - if(effect.finish) effect.finish(position);
319 + if (effect.finish) effect.finish(position);
354 effect.event('afterFinish');
320 effect.event('afterFinish');
355 });
321 });
356 }
322 }
357 });
323 });
358
324
359 - Effect.Event = Class.create();
325 + Effect.Tween = Class.create(Effect.Base, {
360 - Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), {
326 + initialize: function(object, from, to) {
327 + object = Object.isString(object) ? $(object) : object;
328 + var args = $A(arguments), method = args.last(),
329 + options = args.length == 5 ? args[3] : null;
330 + this.method = Object.isFunction(method) ? method.bind(object) :
331 + Object.isFunction(object[method]) ? object[method].bind(object) :
332 + function(value) { object[method] = value };
333 + this.start(Object.extend({ from: from, to: to }, options || { }));
334 + },
335 + update: function(position) {
336 + this.method(position);
337 + }
338 + });
339 +
340 + Effect.Event = Class.create(Effect.Base, {
361 initialize: function() {
341 initialize: function() {
362 - var options = Object.extend({
342 + this.start(Object.extend({ duration: 0 }, arguments[0] || { }));
363 - duration: 0
364 - }, arguments[0] || {});
365 - this.start(options);
366 },
343 },
367 update: Prototype.emptyFunction
344 update: Prototype.emptyFunction
368 });
345 });
369
346
370 - Effect.Opacity = Class.create();
347 + Effect.Opacity = Class.create(Effect.Base, {
371 - Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
372 initialize: function(element) {
348 initialize: function(element) {
373 this.element = $(element);
349 this.element = $(element);
374 - if(!this.element) throw(Effect._elementDoesNotExistError);
350 + if (!this.element) throw(Effect._elementDoesNotExistError);
375 // make this work on IE on elements without 'layout'
351 // make this work on IE on elements without 'layout'
376 - if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout))
352 + if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
377 this.element.setStyle({zoom: 1});
353 this.element.setStyle({zoom: 1});
378 var options = Object.extend({
354 var options = Object.extend({
379 from: this.element.getOpacity() || 0.0,
355 from: this.element.getOpacity() || 0.0,
380 to: 1.0
356 to: 1.0
381 - }, arguments[1] || {});
357 + }, arguments[1] || { });
382 this.start(options);
358 this.start(options);
383 },
359 },
384 update: function(position) {
360 update: function(position) {
@@ -386,36 +362,30
386 }
362 }
387 });
363 });
388
364
389 - Effect.Move = Class.create();
365 + Effect.Move = Class.create(Effect.Base, {
390 - Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
391 initialize: function(element) {
366 initialize: function(element) {
392 this.element = $(element);
367 this.element = $(element);
393 - if(!this.element) throw(Effect._elementDoesNotExistError);
368 + if (!this.element) throw(Effect._elementDoesNotExistError);
394 var options = Object.extend({
369 var options = Object.extend({
395 x: 0,
370 x: 0,
396 y: 0,
371 y: 0,
397 mode: 'relative'
372 mode: 'relative'
398 - }, arguments[1] || {});
373 + }, arguments[1] || { });
399 this.start(options);
374 this.start(options);
400 },
375 },
401 setup: function() {
376 setup: function() {
402 - // Bug in Opera: Opera returns the "real" position of a static element or
403 - // relative element that does not have top/left explicitly set.
404 - // ==> Always set top and left for position relative elements in your stylesheets
405 - // (to 0 if you do not need them)
406 this.element.makePositioned();
377 this.element.makePositioned();
407 this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
378 this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
408 this.originalTop = parseFloat(this.element.getStyle('top') || '0');
379 this.originalTop = parseFloat(this.element.getStyle('top') || '0');
409 - if(this.options.mode == 'absolute') {
380 + if (this.options.mode == 'absolute') {
410 - // absolute movement, so we need to calc deltaX and deltaY
411 this.options.x = this.options.x - this.originalLeft;
381 this.options.x = this.options.x - this.originalLeft;
412 this.options.y = this.options.y - this.originalTop;
382 this.options.y = this.options.y - this.originalTop;
413 }
383 }
414 },
384 },
415 update: function(position) {
385 update: function(position) {
416 this.element.setStyle({
386 this.element.setStyle({
417 - left: Math.round(this.options.x * position + this.originalLeft) + 'px',
387 + left: (this.options.x * position + this.originalLeft).round() + 'px',
418 - top: Math.round(this.options.y * position + this.originalTop) + 'px'
388 + top: (this.options.y * position + this.originalTop).round() + 'px'
419 });
389 });
420 }
390 }
421 });
391 });
@@ -423,30 +393,29
423 // for backwards compatibility
393 // for backwards compatibility
424 Effect.MoveBy = function(element, toTop, toLeft) {
394 Effect.MoveBy = function(element, toTop, toLeft) {
425 return new Effect.Move(element,
395 return new Effect.Move(element,
426 - Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
396 + Object.extend({ x: toLeft, y: toTop }, arguments[3] || { }));
427 };
397 };
428
398
429 - Effect.Scale = Class.create();
399 + Effect.Scale = Class.create(Effect.Base, {
430 - Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
431 initialize: function(element, percent) {
400 initialize: function(element, percent) {
432 this.element = $(element);
401 this.element = $(element);
433 - if(!this.element) throw(Effect._elementDoesNotExistError);
402 + if (!this.element) throw(Effect._elementDoesNotExistError);
434 var options = Object.extend({
403 var options = Object.extend({
435 scaleX: true,
404 scaleX: true,
436 scaleY: true,
405 scaleY: true,
437 scaleContent: true,
406 scaleContent: true,
438 scaleFromCenter: false,
407 scaleFromCenter: false,
439 - scaleMode: 'box', // 'box' or 'contents' or {} with provided values
408 + scaleMode: 'box', // 'box' or 'contents' or { } with provided values
440 scaleFrom: 100.0,
409 scaleFrom: 100.0,
441 scaleTo: percent
410 scaleTo: percent
442 - }, arguments[2] || {});
411 + }, arguments[2] || { });
443 this.start(options);
412 this.start(options);
444 },
413 },
445 setup: function() {
414 setup: function() {
446 this.restoreAfterFinish = this.options.restoreAfterFinish || false;
415 this.restoreAfterFinish = this.options.restoreAfterFinish || false;
447 this.elementPositioning = this.element.getStyle('position');
416 this.elementPositioning = this.element.getStyle('position');
448
417
449 - this.originalStyle = {};
418 + this.originalStyle = { };
450 ['top','left','width','height','fontSize'].each( function(k) {
419 ['top','left','width','height','fontSize'].each( function(k) {
451 this.originalStyle[k] = this.element.style[k];
420 this.originalStyle[k] = this.element.style[k];
452 }.bind(this));
421 }.bind(this));
@@ -456,7 +425,7
456
425
457 var fontSize = this.element.getStyle('font-size') || '100%';
426 var fontSize = this.element.getStyle('font-size') || '100%';
458 ['em','px','%','pt'].each( function(fontSizeType) {
427 ['em','px','%','pt'].each( function(fontSizeType) {
459 - if(fontSize.indexOf(fontSizeType)>0) {
428 + if (fontSize.indexOf(fontSizeType)>0) {
460 this.fontSize = parseFloat(fontSize);
429 this.fontSize = parseFloat(fontSize);
461 this.fontSizeType = fontSizeType;
430 this.fontSizeType = fontSizeType;
462 }
431 }
@@ -465,60 +434,61
465 this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
434 this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
466
435
467 this.dims = null;
436 this.dims = null;
468 - if(this.options.scaleMode=='box')
437 + if (this.options.scaleMode=='box')
469 this.dims = [this.element.offsetHeight, this.element.offsetWidth];
438 this.dims = [this.element.offsetHeight, this.element.offsetWidth];
470 - if(/^content/.test(this.options.scaleMode))
439 + if (/^content/.test(this.options.scaleMode))
471 this.dims = [this.element.scrollHeight, this.element.scrollWidth];
440 this.dims = [this.element.scrollHeight, this.element.scrollWidth];
472 - if(!this.dims)
441 + if (!this.dims)
473 this.dims = [this.options.scaleMode.originalHeight,
442 this.dims = [this.options.scaleMode.originalHeight,
474 this.options.scaleMode.originalWidth];
443 this.options.scaleMode.originalWidth];
475 },
444 },
476 update: function(position) {
445 update: function(position) {
477 var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
446 var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
478 - if(this.options.scaleContent && this.fontSize)
447 + if (this.options.scaleContent && this.fontSize)
479 this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
448 this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
480 this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
449 this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
481 },
450 },
482 finish: function(position) {
451 finish: function(position) {
483 - if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
452 + if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
484 },
453 },
485 setDimensions: function(height, width) {
454 setDimensions: function(height, width) {
486 - var d = {};
455 + var d = { };
487 - if(this.options.scaleX) d.width = Math.round(width) + 'px';
456 + if (this.options.scaleX) d.width = width.round() + 'px';
488 - if(this.options.scaleY) d.height = Math.round(height) + 'px';
457 + if (this.options.scaleY) d.height = height.round() + 'px';
489 - if(this.options.scaleFromCenter) {
458 + if (this.options.scaleFromCenter) {
490 var topd = (height - this.dims[0])/2;
459 var topd = (height - this.dims[0])/2;
491 var leftd = (width - this.dims[1])/2;
460 var leftd = (width - this.dims[1])/2;
492 - if(this.elementPositioning == 'absolute') {
461 + if (this.elementPositioning == 'absolute') {
493 - if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
462 + if (this.options.scaleY) d.top = this.originalTop-topd + 'px';
494 - if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
463 + if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
495 } else {
464 } else {
496 - if(this.options.scaleY) d.top = -topd + 'px';
465 + if (this.options.scaleY) d.top = -topd + 'px';
497 - if(this.options.scaleX) d.left = -leftd + 'px';
466 + if (this.options.scaleX) d.left = -leftd + 'px';
498 }
467 }
499 }
468 }
500 this.element.setStyle(d);
469 this.element.setStyle(d);
501 }
470 }
502 });
471 });
503
472
504 - Effect.Highlight = Class.create();
473 + Effect.Highlight = Class.create(Effect.Base, {
505 - Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
506 initialize: function(element) {
474 initialize: function(element) {
507 this.element = $(element);
475 this.element = $(element);
508 - if(!this.element) throw(Effect._elementDoesNotExistError);
476 + if (!this.element) throw(Effect._elementDoesNotExistError);
509 - var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
477 + var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { });
510 this.start(options);
478 this.start(options);
511 },
479 },
512 setup: function() {
480 setup: function() {
513 // Prevent executing on elements not in the layout flow
481 // Prevent executing on elements not in the layout flow
514 - if(this.element.getStyle('display')=='none') { this.cancel(); return; }
482 + if (this.element.getStyle('display')=='none') { this.cancel(); return; }
515 // Disable background image during the effect
483 // Disable background image during the effect
516 - this.oldStyle = {
484 + this.oldStyle = { };
517 - backgroundImage: this.element.getStyle('background-image') };
485 + if (!this.options.keepBackgroundImage) {
518 - this.element.setStyle({backgroundImage: 'none'});
486 + this.oldStyle.backgroundImage = this.element.getStyle('background-image');
519 - if(!this.options.endcolor)
487 + this.element.setStyle({backgroundImage: 'none'});
488 + }
489 + if (!this.options.endcolor)
520 this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
490 this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
521 - if(!this.options.restorecolor)
491 + if (!this.options.restorecolor)
522 this.options.restorecolor = this.element.getStyle('background-color');
492 this.options.restorecolor = this.element.getStyle('background-color');
523 // init color calculations
493 // init color calculations
524 this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
494 this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
@@ -526,7 +496,7
526 },
496 },
527 update: function(position) {
497 update: function(position) {
528 this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
498 this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
529 - return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
499 + return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) });
530 },
500 },
531 finish: function() {
501 finish: function() {
532 this.element.setStyle(Object.extend(this.oldStyle, {
502 this.element.setStyle(Object.extend(this.oldStyle, {
@@ -535,30 +505,21
535 }
505 }
536 });
506 });
537
507
538 - Effect.ScrollTo = Class.create();
508 + Effect.ScrollTo = function(element) {
539 - Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
509 + var options = arguments[1] || { },
540 - initialize: function(element) {
510 + scrollOffsets = document.viewport.getScrollOffsets(),
541 - this.element = $(element);
511 + elementOffsets = $(element).cumulativeOffset(),
542 - this.start(arguments[1] || {});
512 + max = (window.height || document.body.scrollHeight) - document.viewport.getHeight();
543 - },
513 +
544 - setup: function() {
514 + if (options.offset) elementOffsets[1] += options.offset;
545 - Position.prepare();
515 +
546 - var offsets = Position.cumulativeOffset(this.element);
516 + return new Effect.Tween(null,
547 - if(this.options.offset) offsets[1] += this.options.offset;
517 + scrollOffsets.top,
548 - var max = window.innerHeight ?
518 + elementOffsets[1] > max ? max : elementOffsets[1],
549 - window.height - window.innerHeight :
519 + options,
550 - document.body.scrollHeight -
520 + function(p){ scrollTo(scrollOffsets.left, p.round()) }
551 - (document.documentElement.clientHeight ?
521 + );
552 - document.documentElement.clientHeight : document.body.clientHeight);
522 + };
553 - this.scrollStart = Position.deltaY;
554 - this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
555 - },
556 - update: function(position) {
557 - Position.prepare();
558 - window.scrollTo(Position.deltaX,
559 - this.scrollStart + (position*this.delta));
560 - }
561 - });
562
523
563 /* ------------- combination effects ------------- */
524 /* ------------- combination effects ------------- */
564
525
@@ -566,14 +527,15
566 element = $(element);
527 element = $(element);
567 var oldOpacity = element.getInlineOpacity();
528 var oldOpacity = element.getInlineOpacity();
568 var options = Object.extend({
529 var options = Object.extend({
569 - from: element.getOpacity() || 1.0,
530 + from: element.getOpacity() || 1.0,
570 - to: 0.0,
531 + to: 0.0,
571 - afterFinishInternal: function(effect) {
532 + afterFinishInternal: function(effect) {
572 - if(effect.options.to!=0) return;
533 + if (effect.options.to!=0) return;
573 - effect.element.hide().setStyle({opacity: oldOpacity});
534 + effect.element.hide().setStyle({opacity: oldOpacity});
574 - }}, arguments[1] || {});
535 + }
536 + }, arguments[1] || { });
575 return new Effect.Opacity(element,options);
537 return new Effect.Opacity(element,options);
576 - }
538 + };
577
539
578 Effect.Appear = function(element) {
540 Effect.Appear = function(element) {
579 element = $(element);
541 element = $(element);
@@ -586,9 +548,9
586 },
548 },
587 beforeSetup: function(effect) {
549 beforeSetup: function(effect) {
588 effect.element.setOpacity(effect.options.from).show();
550 effect.element.setOpacity(effect.options.from).show();
589 - }}, arguments[1] || {});
551 + }}, arguments[1] || { });
590 return new Effect.Opacity(element,options);
552 return new Effect.Opacity(element,options);
591 - }
553 + };
592
554
593 Effect.Puff = function(element) {
555 Effect.Puff = function(element) {
594 element = $(element);
556 element = $(element);
@@ -610,9 +572,9
610 },
572 },
611 afterFinishInternal: function(effect) {
573 afterFinishInternal: function(effect) {
612 effect.effects[0].element.hide().setStyle(oldStyle); }
574 effect.effects[0].element.hide().setStyle(oldStyle); }
613 - }, arguments[1] || {})
575 + }, arguments[1] || { })
614 );
576 );
615 - }
577 + };
616
578
617 Effect.BlindUp = function(element) {
579 Effect.BlindUp = function(element) {
618 element = $(element);
580 element = $(element);
@@ -624,9 +586,9
624 afterFinishInternal: function(effect) {
586 afterFinishInternal: function(effect) {
625 effect.element.hide().undoClipping();
587 effect.element.hide().undoClipping();
626 }
588 }
627 - }, arguments[1] || {})
589 + }, arguments[1] || { })
628 );
590 );
629 - }
591 + };
630
592
631 Effect.BlindDown = function(element) {
593 Effect.BlindDown = function(element) {
632 element = $(element);
594 element = $(element);
@@ -643,8 +605,8
643 afterFinishInternal: function(effect) {
605 afterFinishInternal: function(effect) {
644 effect.element.undoClipping();
606 effect.element.undoClipping();
645 }
607 }
646 - }, arguments[1] || {}));
608 + }, arguments[1] || { }));
647 - }
609 + };
648
610
649 Effect.SwitchOff = function(element) {
611 Effect.SwitchOff = function(element) {
650 element = $(element);
612 element = $(element);
@@ -665,8 +627,8
665 }
627 }
666 })
628 })
667 }
629 }
668 - }, arguments[1] || {}));
630 + }, arguments[1] || { }));
669 - }
631 + };
670
632
671 Effect.DropOut = function(element) {
633 Effect.DropOut = function(element) {
672 element = $(element);
634 element = $(element);
@@ -685,29 +647,35
685 afterFinishInternal: function(effect) {
647 afterFinishInternal: function(effect) {
686 effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
648 effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
687 }
649 }
688 - }, arguments[1] || {}));
650 + }, arguments[1] || { }));
689 - }
651 + };
690
652
691 Effect.Shake = function(element) {
653 Effect.Shake = function(element) {
692 element = $(element);
654 element = $(element);
655 + var options = Object.extend({
656 + distance: 20,
657 + duration: 0.5
658 + }, arguments[1] || {});
659 + var distance = parseFloat(options.distance);
660 + var split = parseFloat(options.duration) / 10.0;
693 var oldStyle = {
661 var oldStyle = {
694 top: element.getStyle('top'),
662 top: element.getStyle('top'),
695 left: element.getStyle('left') };
663 left: element.getStyle('left') };
696 - return new Effect.Move(element,
664 + return new Effect.Move(element,
697 - { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
665 + { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) {
698 new Effect.Move(effect.element,
666 new Effect.Move(effect.element,
699 - { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
667 + { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
700 new Effect.Move(effect.element,
668 new Effect.Move(effect.element,
701 - { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
669 + { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
702 new Effect.Move(effect.element,
670 new Effect.Move(effect.element,
703 - { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
671 + { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
704 new Effect.Move(effect.element,
672 new Effect.Move(effect.element,
705 - { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
673 + { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
706 new Effect.Move(effect.element,
674 new Effect.Move(effect.element,
707 - { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
675 + { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {
708 effect.element.undoPositioned().setStyle(oldStyle);
676 effect.element.undoPositioned().setStyle(oldStyle);
709 }}) }}) }}) }}) }}) }});
677 }}) }}) }}) }}) }}) }});
710 - }
678 + };
711
679
712 Effect.SlideDown = function(element) {
680 Effect.SlideDown = function(element) {
713 element = $(element).cleanWhitespace();
681 element = $(element).cleanWhitespace();
@@ -723,7 +691,7
723 afterSetup: function(effect) {
691 afterSetup: function(effect) {
724 effect.element.makePositioned();
692 effect.element.makePositioned();
725 effect.element.down().makePositioned();
693 effect.element.down().makePositioned();
726 - if(window.opera) effect.element.setStyle({top: ''});
694 + if (window.opera) effect.element.setStyle({top: ''});
727 effect.element.makeClipping().setStyle({height: '0px'}).show();
695 effect.element.makeClipping().setStyle({height: '0px'}).show();
728 },
696 },
729 afterUpdateInternal: function(effect) {
697 afterUpdateInternal: function(effect) {
@@ -733,23 +701,25
733 afterFinishInternal: function(effect) {
701 afterFinishInternal: function(effect) {
734 effect.element.undoClipping().undoPositioned();
702 effect.element.undoClipping().undoPositioned();
735 effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
703 effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
736 - }, arguments[1] || {})
704 + }, arguments[1] || { })
737 );
705 );
738 - }
706 + };
739
707
740 Effect.SlideUp = function(element) {
708 Effect.SlideUp = function(element) {
741 element = $(element).cleanWhitespace();
709 element = $(element).cleanWhitespace();
742 var oldInnerBottom = element.down().getStyle('bottom');
710 var oldInnerBottom = element.down().getStyle('bottom');
711 + var elementDimensions = element.getDimensions();
743 return new Effect.Scale(element, window.opera ? 0 : 1,
712 return new Effect.Scale(element, window.opera ? 0 : 1,
744 Object.extend({ scaleContent: false,
713 Object.extend({ scaleContent: false,
745 scaleX: false,
714 scaleX: false,
746 scaleMode: 'box',
715 scaleMode: 'box',
747 scaleFrom: 100,
716 scaleFrom: 100,
717 + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
748 restoreAfterFinish: true,
718 restoreAfterFinish: true,
749 - beforeStartInternal: function(effect) {
719 + afterSetup: function(effect) {
750 effect.element.makePositioned();
720 effect.element.makePositioned();
751 effect.element.down().makePositioned();
721 effect.element.down().makePositioned();
752 - if(window.opera) effect.element.setStyle({top: ''});
722 + if (window.opera) effect.element.setStyle({top: ''});
753 effect.element.makeClipping().show();
723 effect.element.makeClipping().show();
754 },
724 },
755 afterUpdateInternal: function(effect) {
725 afterUpdateInternal: function(effect) {
@@ -757,12 +727,12
757 (effect.dims[0] - effect.element.clientHeight) + 'px' });
727 (effect.dims[0] - effect.element.clientHeight) + 'px' });
758 },
728 },
759 afterFinishInternal: function(effect) {
729 afterFinishInternal: function(effect) {
760 - effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom});
730 + effect.element.hide().undoClipping().undoPositioned();
761 - effect.element.down().undoPositioned();
731 + effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom});
762 }
732 }
763 - }, arguments[1] || {})
733 + }, arguments[1] || { })
764 );
734 );
765 - }
735 + };
766
736
767 // Bug in opera makes the TD containing this element expand for a instance after finish
737 // Bug in opera makes the TD containing this element expand for a instance after finish
768 Effect.Squish = function(element) {
738 Effect.Squish = function(element) {
@@ -775,7 +745,7
775 effect.element.hide().undoClipping();
745 effect.element.hide().undoClipping();
776 }
746 }
777 });
747 });
778 - }
748 + };
779
749
780 Effect.Grow = function(element) {
750 Effect.Grow = function(element) {
781 element = $(element);
751 element = $(element);
@@ -784,7 +754,7
784 moveTransition: Effect.Transitions.sinoidal,
754 moveTransition: Effect.Transitions.sinoidal,
785 scaleTransition: Effect.Transitions.sinoidal,
755 scaleTransition: Effect.Transitions.sinoidal,
786 opacityTransition: Effect.Transitions.full
756 opacityTransition: Effect.Transitions.full
787 - }, arguments[1] || {});
757 + }, arguments[1] || { });
788 var oldStyle = {
758 var oldStyle = {
789 top: element.style.top,
759 top: element.style.top,
790 left: element.style.left,
760 left: element.style.left,
@@ -849,7 +819,7
849 )
819 )
850 }
820 }
851 });
821 });
852 - }
822 + };
853
823
854 Effect.Shrink = function(element) {
824 Effect.Shrink = function(element) {
855 element = $(element);
825 element = $(element);
@@ -858,7 +828,7
858 moveTransition: Effect.Transitions.sinoidal,
828 moveTransition: Effect.Transitions.sinoidal,
859 scaleTransition: Effect.Transitions.sinoidal,
829 scaleTransition: Effect.Transitions.sinoidal,
860 opacityTransition: Effect.Transitions.none
830 opacityTransition: Effect.Transitions.none
861 - }, arguments[1] || {});
831 + }, arguments[1] || { });
862 var oldStyle = {
832 var oldStyle = {
863 top: element.style.top,
833 top: element.style.top,
864 left: element.style.left,
834 left: element.style.left,
@@ -903,11 +873,11
903 effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
873 effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
904 }, options)
874 }, options)
905 );
875 );
906 - }
876 + };
907
877
908 Effect.Pulsate = function(element) {
878 Effect.Pulsate = function(element) {
909 element = $(element);
879 element = $(element);
910 - var options = arguments[1] || {};
880 + var options = arguments[1] || { };
911 var oldOpacity = element.getInlineOpacity();
881 var oldOpacity = element.getInlineOpacity();
912 var transition = options.transition || Effect.Transitions.sinoidal;
882 var transition = options.transition || Effect.Transitions.sinoidal;
913 var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
883 var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
@@ -916,7 +886,7
916 Object.extend(Object.extend({ duration: 2.0, from: 0,
886 Object.extend(Object.extend({ duration: 2.0, from: 0,
917 afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
887 afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
918 }, options), {transition: reverser}));
888 }, options), {transition: reverser}));
919 - }
889 + };
920
890
921 Effect.Fold = function(element) {
891 Effect.Fold = function(element) {
922 element = $(element);
892 element = $(element);
@@ -936,37 +906,71
936 afterFinishInternal: function(effect) {
906 afterFinishInternal: function(effect) {
937 effect.element.hide().undoClipping().setStyle(oldStyle);
907 effect.element.hide().undoClipping().setStyle(oldStyle);
938 } });
908 } });
939 - }}, arguments[1] || {}));
909 + }}, arguments[1] || { }));
940 };
910 };
941
911
942 - Effect.Morph = Class.create();
912 + Effect.Morph = Class.create(Effect.Base, {
943 - Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), {
944 initialize: function(element) {
913 initialize: function(element) {
945 this.element = $(element);
914 this.element = $(element);
946 - if(!this.element) throw(Effect._elementDoesNotExistError);
915 + if (!this.element) throw(Effect._elementDoesNotExistError);
947 var options = Object.extend({
916 var options = Object.extend({
948 - style: ''
917 + style: { }
949 - }, arguments[1] || {});
918 + }, arguments[1] || { });
919 +
920 + if (!Object.isString(options.style)) this.style = $H(options.style);
921 + else {
922 + if (options.style.include(':'))
923 + this.style = options.style.parseStyle();
924 + else {
925 + this.element.addClassName(options.style);
926 + this.style = $H(this.element.getStyles());
927 + this.element.removeClassName(options.style);
928 + var css = this.element.getStyles();
929 + this.style = this.style.reject(function(style) {
930 + return style.value == css[style.key];
931 + });
932 + options.afterFinishInternal = function(effect) {
933 + effect.element.addClassName(effect.options.style);
934 + effect.transforms.each(function(transform) {
935 + effect.element.style[transform.style] = '';
936 + });
937 + }
938 + }
939 + }
950 this.start(options);
940 this.start(options);
951 },
941 },
942 +
952 setup: function(){
943 setup: function(){
953 function parseColor(color){
944 function parseColor(color){
954 - if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
945 + if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
955 color = color.parseColor();
946 color = color.parseColor();
956 return $R(0,2).map(function(i){
947 return $R(0,2).map(function(i){
957 return parseInt( color.slice(i*2+1,i*2+3), 16 )
948 return parseInt( color.slice(i*2+1,i*2+3), 16 )
958 });
949 });
959 }
950 }
960 - this.transforms = this.options.style.parseStyle().map(function(property){
951 + this.transforms = this.style.map(function(pair){
961 - var originalValue = this.element.getStyle(property[0]);
952 + var property = pair[0], value = pair[1], unit = null;
962 - return $H({
953 +
963 - style: property[0],
954 + if (value.parseColor('#zzzzzz') != '#zzzzzz') {
964 - originalValue: property[1].unit=='color' ?
955 + value = value.parseColor();
965 - parseColor(originalValue) : parseFloat(originalValue || 0),
956 + unit = 'color';
966 - targetValue: property[1].unit=='color' ?
957 + } else if (property == 'opacity') {
967 - parseColor(property[1].value) : property[1].value,
958 + value = parseFloat(value);
968 - unit: property[1].unit
959 + if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
969 - });
960 + this.element.setStyle({zoom: 1});
961 + } else if (Element.CSS_LENGTH.test(value)) {
962 + var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
963 + value = parseFloat(components[1]);
964 + unit = (components.length == 3) ? components[2] : null;
965 + }
966 +
967 + var originalValue = this.element.getStyle(property);
968 + return {
969 + style: property.camelize(),
970 + originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
971 + targetValue: unit=='color' ? parseColor(value) : value,
972 + unit: unit
973 + };
970 }.bind(this)).reject(function(transform){
974 }.bind(this)).reject(function(transform){
971 return (
975 return (
972 (transform.originalValue == transform.targetValue) ||
976 (transform.originalValue == transform.targetValue) ||
@@ -978,32 +982,35
978 });
982 });
979 },
983 },
980 update: function(position) {
984 update: function(position) {
981 - var style = $H(), value = null;
985 + var style = { }, transform, i = this.transforms.length;
982 - this.transforms.each(function(transform){
986 + while(i--)
983 - value = transform.unit=='color' ?
987 + style[(transform = this.transforms[i]).style] =
984 - $R(0,2).inject('#',function(m,v,i){
988 + transform.unit=='color' ? '#'+
985 - return m+(Math.round(transform.originalValue[i]+
989 + (Math.round(transform.originalValue[0]+
986 - (transform.targetValue[i] - transform.originalValue[i])*position)).toColorPart() }) :
990 + (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
987 - transform.originalValue + Math.round(
991 + (Math.round(transform.originalValue[1]+
988 - ((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit;
992 + (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
989 - style[transform.style] = value;
993 + (Math.round(transform.originalValue[2]+
990 - });
994 + (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
991 - this.element.setStyle(style);
995 + (transform.originalValue +
996 + (transform.targetValue - transform.originalValue) * position).toFixed(3) +
997 + (transform.unit === null ? '' : transform.unit);
998 + this.element.setStyle(style, true);
992 }
999 }
993 });
1000 });
994
1001
995 - Effect.Transform = Class.create();
1002 + Effect.Transform = Class.create({
996 - Object.extend(Effect.Transform.prototype, {
997 initialize: function(tracks){
1003 initialize: function(tracks){
998 this.tracks = [];
1004 this.tracks = [];
999 - this.options = arguments[1] || {};
1005 + this.options = arguments[1] || { };
1000 this.addTracks(tracks);
1006 this.addTracks(tracks);
1001 },
1007 },
1002 addTracks: function(tracks){
1008 addTracks: function(tracks){
1003 tracks.each(function(track){
1009 tracks.each(function(track){
1004 - var data = $H(track).values().first();
1010 + track = $H(track);
1011 + var data = track.values().first();
1005 this.tracks.push($H({
1012 this.tracks.push($H({
1006 - ids: $H(track).keys().first(),
1013 + ids: track.keys().first(),
1007 effect: Effect.Morph,
1014 effect: Effect.Morph,
1008 options: { style: data }
1015 options: { style: data }
1009 }));
1016 }));
@@ -1013,76 +1020,101
1013 play: function(){
1020 play: function(){
1014 return new Effect.Parallel(
1021 return new Effect.Parallel(
1015 this.tracks.map(function(track){
1022 this.tracks.map(function(track){
1016 - var elements = [$(track.ids) || $$(track.ids)].flatten();
1023 + var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options');
1017 - return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) });
1024 + var elements = [$(ids) || $$(ids)].flatten();
1025 + return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) });
1018 }).flatten(),
1026 }).flatten(),
1019 this.options
1027 this.options
1020 );
1028 );
1021 }
1029 }
1022 });
1030 });
1023
1031
1024 - Element.CSS_PROPERTIES = ['azimuth', 'backgroundAttachment', 'backgroundColor', 'backgroundImage',
1032 + Element.CSS_PROPERTIES = $w(
1025 - 'backgroundPosition', 'backgroundRepeat', 'borderBottomColor', 'borderBottomStyle',
1033 + 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +
1026 - 'borderBottomWidth', 'borderCollapse', 'borderLeftColor', 'borderLeftStyle', 'borderLeftWidth',
1034 + 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
1027 - 'borderRightColor', 'borderRightStyle', 'borderRightWidth', 'borderSpacing', 'borderTopColor',
1035 + 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
1028 - 'borderTopStyle', 'borderTopWidth', 'bottom', 'captionSide', 'clear', 'clip', 'color', 'content',
1036 + 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
1029 - 'counterIncrement', 'counterReset', 'cssFloat', 'cueAfter', 'cueBefore', 'cursor', 'direction',
1037 + 'fontSize fontWeight height left letterSpacing lineHeight ' +
1030 - 'display', 'elevation', 'emptyCells', 'fontFamily', 'fontSize', 'fontSizeAdjust', 'fontStretch',
1038 + 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
1031 - 'fontStyle', 'fontVariant', 'fontWeight', 'height', 'left', 'letterSpacing', 'lineHeight',
1039 + 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
1032 - 'listStyleImage', 'listStylePosition', 'listStyleType', 'marginBottom', 'marginLeft', 'marginRight',
1040 + 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
1033 - 'marginTop', 'markerOffset', 'marks', 'maxHeight', 'maxWidth', 'minHeight', 'minWidth', 'opacity',
1041 + 'right textIndent top width wordSpacing zIndex');
1034 - 'orphans', 'outlineColor', 'outlineOffset', 'outlineStyle', 'outlineWidth', 'overflowX', 'overflowY',
1035 - 'paddingBottom', 'paddingLeft', 'paddingRight', 'paddingTop', 'page', 'pageBreakAfter', 'pageBreakBefore',
1036 - 'pageBreakInside', 'pauseAfter', 'pauseBefore', 'pitch', 'pitchRange', 'position', 'quotes',
1037 - 'richness', 'right', 'size', 'speakHeader', 'speakNumeral', 'speakPunctuation', 'speechRate', 'stress',
1038 - 'tableLayout', 'textAlign', 'textDecoration', 'textIndent', 'textShadow', 'textTransform', 'top',
1039 - 'unicodeBidi', 'verticalAlign', 'visibility', 'voiceFamily', 'volume', 'whiteSpace', 'widows',
1040 - 'width', 'wordSpacing', 'zIndex'];
1041
1042
1042 Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
1043 Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
1043
1044
1045 + String.__parseStyleElement = document.createElement('div');
1044 String.prototype.parseStyle = function(){
1046 String.prototype.parseStyle = function(){
1045 - var element = Element.extend(document.createElement('div'));
1047 + var style, styleRules = $H();
1046 - element.innerHTML = '<div style="' + this + '"></div>';
1048 + if (Prototype.Browser.WebKit)
1047 - var style = element.down().style, styleRules = $H();
1049 + style = new Element('div',{style:this}).style;
1050 + else {
1051 + String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>';
1052 + style = String.__parseStyleElement.childNodes[0].style;
1053 + }
1048
1054
1049 Element.CSS_PROPERTIES.each(function(property){
1055 Element.CSS_PROPERTIES.each(function(property){
1050 - if(style[property]) styleRules[property] = style[property];
1056 + if (style[property]) styleRules.set(property, style[property]);
1051 });
1057 });
1052
1058
1053 - var result = $H();
1059 + if (Prototype.Browser.IE && this.include('opacity'))
1054 -
1060 + styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]);
1055 - styleRules.each(function(pair){
1061 +
1056 - var property = pair[0], value = pair[1], unit = null;
1062 + return styleRules;
1057 -
1063 + };
1058 - if(value.parseColor('#zzzzzz') != '#zzzzzz') {
1064 +
1059 - value = value.parseColor();
1065 + if (document.defaultView && document.defaultView.getComputedStyle) {
1060 - unit = 'color';
1066 + Element.getStyles = function(element) {
1061 - } else if(Element.CSS_LENGTH.test(value))
1067 + var css = document.defaultView.getComputedStyle($(element), null);
1062 - var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/),
1068 + return Element.CSS_PROPERTIES.inject({ }, function(styles, property) {
1063 - value = parseFloat(components[1]), unit = (components.length == 3) ? components[2] : null;
1069 + styles[property] = css[property];
1064 -
1070 + return styles;
1065 - result[property.underscore().dasherize()] = $H({ value:value, unit:unit });
1071 + });
1066 - }.bind(this));
1072 + };
1067 -
1073 + } else {
1068 - return result;
1074 + Element.getStyles = function(element) {
1075 + element = $(element);
1076 + var css = element.currentStyle, styles;
1077 + styles = Element.CSS_PROPERTIES.inject({ }, function(hash, property) {
1078 + hash.set(property, css[property]);
1079 + return hash;
1080 + });
1081 + if (!styles.opacity) styles.set('opacity', element.getOpacity());
1082 + return styles;
1083 + };
1069 };
1084 };
1070
1085
1071 - Element.morph = function(element, style) {
1086 + Effect.Methods = {
1072 - new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {}));
1087 + morph: function(element, style) {
1073 - return element;
1088 + element = $(element);
1089 + new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { }));
1090 + return element;
1091 + },
1092 + visualEffect: function(element, effect, options) {
1093 + element = $(element)
1094 + var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);
1095 + new Effect[klass](element, options);
1096 + return element;
1097 + },
1098 + highlight: function(element, options) {
1099 + element = $(element);
1100 + new Effect.Highlight(element, options);
1101 + return element;
1102 + }
1074 };
1103 };
1075
1104
1076 - ['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',
1105 + $w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+
1077 - 'collectTextNodes','collectTextNodesIgnoreClass','morph'].each(
1106 + 'pulsate shake puff squish switchOff dropOut').each(
1078 - function(f) { Element.Methods[f] = Element[f]; }
1107 + function(effect) {
1108 + Effect.Methods[effect] = function(element, options){
1109 + element = $(element);
1110 + Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);
1111 + return element;
1112 + }
1113 + }
1079 );
1114 );
1080
1115
1081 - Element.Methods.visualEffect = function(element, effect, options) {
1116 + $w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(
1082 - s = effect.gsub(/_/, '-').camelize();
1117 + function(f) { Effect.Methods[f] = Element[f]; }
1083 - effect_class = s.charAt(0).toUpperCase() + s.substring(1);
1118 + );
1084 - new Effect[effect_class](element, options);
1085 - return $(element);
1086 - };
1087
1119
1088 - Element.addMethods(); No newline at end of file
1120 + Element.addMethods(Effect.Methods);
This diff has been collapsed as it changes many lines, (4594 lines changed) Show them Hide them
@@ -1,43 +1,114
1 - /* Prototype JavaScript framework, version 1.5.0
1 + /* Prototype JavaScript framework, version 1.6.0.1
2 * (c) 2005-2007 Sam Stephenson
2 * (c) 2005-2007 Sam Stephenson
3 *
3 *
4 * Prototype is freely distributable under the terms of an MIT-style license.
4 * Prototype is freely distributable under the terms of an MIT-style license.
5 - * For details, see the Prototype web site: http://prototype.conio.net/
5 + * For details, see the Prototype web site: http://www.prototypejs.org/
6 *
6 *
7 - /*--------------------------------------------------------------------------*/
7 + *--------------------------------------------------------------------------*/
8
8
9 var Prototype = {
9 var Prototype = {
10 - Version: '1.5.0',
10 + Version: '1.6.0.1',
11 +
12 + Browser: {
13 + IE: !!(window.attachEvent && !window.opera),
14 + Opera: !!window.opera,
15 + WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
16 + Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
17 + MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
18 + },
19 +
11 BrowserFeatures: {
20 BrowserFeatures: {
12 - XPath: !!document.evaluate
21 + XPath: !!document.evaluate,
13 - },
22 + ElementExtensions: !!window.HTMLElement,
14 -
23 + SpecificElementExtensions:
15 - ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
24 + document.createElement('div').__proto__ &&
16 - emptyFunction: function() {},
25 + document.createElement('div').__proto__ !==
26 + document.createElement('form').__proto__
27 + },
28 +
29 + ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
30 + JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
31 +
32 + emptyFunction: function() { },
17 K: function(x) { return x }
33 K: function(x) { return x }
18 - }
34 + };
19 -
35 +
36 + if (Prototype.Browser.MobileSafari)
37 + Prototype.BrowserFeatures.SpecificElementExtensions = false;
38 +
39 +
40 + /* Based on Alex Arnell's inheritance implementation. */
20 var Class = {
41 var Class = {
21 create: function() {
42 create: function() {
22 - return function() {
43 + var parent = null, properties = $A(arguments);
44 + if (Object.isFunction(properties[0]))
45 + parent = properties.shift();
46 +
47 + function klass() {
23 this.initialize.apply(this, arguments);
48 this.initialize.apply(this, arguments);
24 }
49 }
50 +
51 + Object.extend(klass, Class.Methods);
52 + klass.superclass = parent;
53 + klass.subclasses = [];
54 +
55 + if (parent) {
56 + var subclass = function() { };
57 + subclass.prototype = parent.prototype;
58 + klass.prototype = new subclass;
59 + parent.subclasses.push(klass);
60 + }
61 +
62 + for (var i = 0; i < properties.length; i++)
63 + klass.addMethods(properties[i]);
64 +
65 + if (!klass.prototype.initialize)
66 + klass.prototype.initialize = Prototype.emptyFunction;
67 +
68 + klass.prototype.constructor = klass;
69 +
70 + return klass;
25 }
71 }
26 - }
72 + };
27 -
73 +
28 - var Abstract = new Object();
74 + Class.Methods = {
75 + addMethods: function(source) {
76 + var ancestor = this.superclass && this.superclass.prototype;
77 + var properties = Object.keys(source);
78 +
79 + if (!Object.keys({ toString: true }).length)
80 + properties.push("toString", "valueOf");
81 +
82 + for (var i = 0, length = properties.length; i < length; i++) {
83 + var property = properties[i], value = source[property];
84 + if (ancestor && Object.isFunction(value) &&
85 + value.argumentNames().first() == "$super") {
86 + var method = value, value = Object.extend((function(m) {
87 + return function() { return ancestor[m].apply(this, arguments) };
88 + })(property).wrap(method), {
89 + valueOf: function() { return method },
90 + toString: function() { return method.toString() }
91 + });
92 + }
93 + this.prototype[property] = value;
94 + }
95 +
96 + return this;
97 + }
98 + };
99 +
100 + var Abstract = { };
29
101
30 Object.extend = function(destination, source) {
102 Object.extend = function(destination, source) {
31 - for (var property in source) {
103 + for (var property in source)
32 destination[property] = source[property];
104 destination[property] = source[property];
33 - }
34 return destination;
105 return destination;
35 - }
106 + };
36
107
37 Object.extend(Object, {
108 Object.extend(Object, {
38 inspect: function(object) {
109 inspect: function(object) {
39 try {
110 try {
40 - if (object === undefined) return 'undefined';
111 + if (Object.isUndefined(object)) return 'undefined';
41 if (object === null) return 'null';
112 if (object === null) return 'null';
42 return object.inspect ? object.inspect() : object.toString();
113 return object.inspect ? object.inspect() : object.toString();
43 } catch (e) {
114 } catch (e) {
@@ -46,6 +117,37
46 }
117 }
47 },
118 },
48
119
120 + toJSON: function(object) {
121 + var type = typeof object;
122 + switch (type) {
123 + case 'undefined':
124 + case 'function':
125 + case 'unknown': return;
126 + case 'boolean': return object.toString();
127 + }
128 +
129 + if (object === null) return 'null';
130 + if (object.toJSON) return object.toJSON();
131 + if (Object.isElement(object)) return;
132 +
133 + var results = [];
134 + for (var property in object) {
135 + var value = Object.toJSON(object[property]);
136 + if (!Object.isUndefined(value))
137 + results.push(property.toJSON() + ': ' + value);
138 + }
139 +
140 + return '{' + results.join(', ') + '}';
141 + },
142 +
143 + toQueryString: function(object) {
144 + return $H(object).toQueryString();
145 + },
146 +
147 + toHTML: function(object) {
148 + return object && object.toHTML ? object.toHTML() : String.interpret(object);
149 + },
150 +
49 keys: function(object) {
151 keys: function(object) {
50 var keys = [];
152 var keys = [];
51 for (var property in object)
153 for (var property in object)
@@ -61,41 +163,101
61 },
163 },
62
164
63 clone: function(object) {
165 clone: function(object) {
64 - return Object.extend({}, object);
166 + return Object.extend({ }, object);
167 + },
168 +
169 + isElement: function(object) {
170 + return object && object.nodeType == 1;
171 + },
172 +
173 + isArray: function(object) {
174 + return object && object.constructor === Array;
175 + },
176 +
177 + isHash: function(object) {
178 + return object instanceof Hash;
179 + },
180 +
181 + isFunction: function(object) {
182 + return typeof object == "function";
183 + },
184 +
185 + isString: function(object) {
186 + return typeof object == "string";
187 + },
188 +
189 + isNumber: function(object) {
190 + return typeof object == "number";
191 + },
192 +
193 + isUndefined: function(object) {
194 + return typeof object == "undefined";
65 }
195 }
66 });
196 });
67
197
68 - Function.prototype.bind = function() {
198 + Object.extend(Function.prototype, {
69 - var __method = this, args = $A(arguments), object = args.shift();
199 + argumentNames: function() {
70 - return function() {
200 + var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip");
71 - return __method.apply(object, args.concat($A(arguments)));
201 + return names.length == 1 && !names[0] ? [] : names;
72 - }
202 + },
73 - }
203 +
74 -
204 + bind: function() {
75 - Function.prototype.bindAsEventListener = function(object) {
205 + if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
76 - var __method = this, args = $A(arguments), object = args.shift();
206 + var __method = this, args = $A(arguments), object = args.shift();
77 - return function(event) {
207 + return function() {
78 - return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));
208 + return __method.apply(object, args.concat($A(arguments)));
79 - }
209 + }
80 - }
210 + },
81 -
211 +
82 - Object.extend(Number.prototype, {
212 + bindAsEventListener: function() {
83 - toColorPart: function() {
213 + var __method = this, args = $A(arguments), object = args.shift();
84 - var digits = this.toString(16);
214 + return function(event) {
85 - if (this < 16) return '0' + digits;
215 + return __method.apply(object, [event || window.event].concat(args));
86 - return digits;
216 + }
87 - },
217 + },
88 -
218 +
89 - succ: function() {
219 + curry: function() {
90 - return this + 1;
220 + if (!arguments.length) return this;
91 - },
221 + var __method = this, args = $A(arguments);
92 -
222 + return function() {
93 - times: function(iterator) {
223 + return __method.apply(this, args.concat($A(arguments)));
94 - $R(0, this, true).each(iterator);
224 + }
95 - return this;
225 + },
226 +
227 + delay: function() {
228 + var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
229 + return window.setTimeout(function() {
230 + return __method.apply(__method, args);
231 + }, timeout);
232 + },
233 +
234 + wrap: function(wrapper) {
235 + var __method = this;
236 + return function() {
237 + return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
238 + }
239 + },
240 +
241 + methodize: function() {
242 + if (this._methodized) return this._methodized;
243 + var __method = this;
244 + return this._methodized = function() {
245 + return __method.apply(null, [this].concat($A(arguments)));
246 + };
96 }
247 }
97 });
248 });
98
249
250 + Function.prototype.defer = Function.prototype.delay.curry(0.01);
251 +
252 + Date.prototype.toJSON = function() {
253 + return '"' + this.getUTCFullYear() + '-' +
254 + (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
255 + this.getUTCDate().toPaddedString(2) + 'T' +
256 + this.getUTCHours().toPaddedString(2) + ':' +
257 + this.getUTCMinutes().toPaddedString(2) + ':' +
258 + this.getUTCSeconds().toPaddedString(2) + 'Z"';
259 + };
260 +
99 var Try = {
261 var Try = {
100 these: function() {
262 these: function() {
101 var returnValue;
263 var returnValue;
@@ -105,17 +267,22
105 try {
267 try {
106 returnValue = lambda();
268 returnValue = lambda();
107 break;
269 break;
108 - } catch (e) {}
270 + } catch (e) { }
109 }
271 }
110
272
111 return returnValue;
273 return returnValue;
112 }
274 }
113 - }
275 + };
276 +
277 + RegExp.prototype.match = RegExp.prototype.test;
278 +
279 + RegExp.escape = function(str) {
280 + return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
281 + };
114
282
115 /*--------------------------------------------------------------------------*/
283 /*--------------------------------------------------------------------------*/
116
284
117 - var PeriodicalExecuter = Class.create();
285 + var PeriodicalExecuter = Class.create({
118 - PeriodicalExecuter.prototype = {
119 initialize: function(callback, frequency) {
286 initialize: function(callback, frequency) {
120 this.callback = callback;
287 this.callback = callback;
121 this.frequency = frequency;
288 this.frequency = frequency;
@@ -128,6 +295,10
128 this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
295 this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
129 },
296 },
130
297
298 + execute: function() {
299 + this.callback(this);
300 + },
301 +
131 stop: function() {
302 stop: function() {
132 if (!this.timer) return;
303 if (!this.timer) return;
133 clearInterval(this.timer);
304 clearInterval(this.timer);
@@ -138,16 +309,26
138 if (!this.currentlyExecuting) {
309 if (!this.currentlyExecuting) {
139 try {
310 try {
140 this.currentlyExecuting = true;
311 this.currentlyExecuting = true;
141 - this.callback(this);
312 + this.execute();
142 } finally {
313 } finally {
143 this.currentlyExecuting = false;
314 this.currentlyExecuting = false;
144 }
315 }
145 }
316 }
146 }
317 }
147 - }
318 + });
148 - String.interpret = function(value){
319 + Object.extend(String, {
149 - return value == null ? '' : String(value);
320 + interpret: function(value) {
150 - }
321 + return value == null ? '' : String(value);
322 + },
323 + specialChar: {
324 + '\b': '\\b',
325 + '\t': '\\t',
326 + '\n': '\\n',
327 + '\f': '\\f',
328 + '\r': '\\r',
329 + '\\': '\\\\'
330 + }
331 + });
151
332
152 Object.extend(String.prototype, {
333 Object.extend(String.prototype, {
153 gsub: function(pattern, replacement) {
334 gsub: function(pattern, replacement) {
@@ -168,7 +349,7
168
349
169 sub: function(pattern, replacement, count) {
350 sub: function(pattern, replacement, count) {
170 replacement = this.gsub.prepareReplacement(replacement);
351 replacement = this.gsub.prepareReplacement(replacement);
171 - count = count === undefined ? 1 : count;
352 + count = Object.isUndefined(count) ? 1 : count;
172
353
173 return this.gsub(pattern, function(match) {
354 return this.gsub(pattern, function(match) {
174 if (--count < 0) return match[0];
355 if (--count < 0) return match[0];
@@ -178,14 +359,14
178
359
179 scan: function(pattern, iterator) {
360 scan: function(pattern, iterator) {
180 this.gsub(pattern, iterator);
361 this.gsub(pattern, iterator);
181 - return this;
362 + return String(this);
182 },
363 },
183
364
184 truncate: function(length, truncation) {
365 truncate: function(length, truncation) {
185 length = length || 30;
366 length = length || 30;
186 - truncation = truncation === undefined ? '...' : truncation;
367 + truncation = Object.isUndefined(truncation) ? '...' : truncation;
187 return this.length > length ?
368 return this.length > length ?
188 - this.slice(0, length - truncation.length) + truncation : this;
369 + this.slice(0, length - truncation.length) + truncation : String(this);
189 },
370 },
190
371
191 strip: function() {
372 strip: function() {
@@ -213,35 +394,34
213 },
394 },
214
395
215 escapeHTML: function() {
396 escapeHTML: function() {
216 - var div = document.createElement('div');
397 + var self = arguments.callee;
217 - var text = document.createTextNode(this);
398 + self.text.data = this;
218 - div.appendChild(text);
399 + return self.div.innerHTML;
219 - return div.innerHTML;
220 },
400 },
221
401
222 unescapeHTML: function() {
402 unescapeHTML: function() {
223 - var div = document.createElement('div');
403 + var div = new Element('div');
224 div.innerHTML = this.stripTags();
404 div.innerHTML = this.stripTags();
225 return div.childNodes[0] ? (div.childNodes.length > 1 ?
405 return div.childNodes[0] ? (div.childNodes.length > 1 ?
226 - $A(div.childNodes).inject('',function(memo,node){ return memo+node.nodeValue }) :
406 + $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
227 div.childNodes[0].nodeValue) : '';
407 div.childNodes[0].nodeValue) : '';
228 },
408 },
229
409
230 toQueryParams: function(separator) {
410 toQueryParams: function(separator) {
231 var match = this.strip().match(/([^?#]*)(#.*)?$/);
411 var match = this.strip().match(/([^?#]*)(#.*)?$/);
232 - if (!match) return {};
412 + if (!match) return { };
233 -
413 +
234 - return match[1].split(separator || '&').inject({}, function(hash, pair) {
414 + return match[1].split(separator || '&').inject({ }, function(hash, pair) {
235 if ((pair = pair.split('='))[0]) {
415 if ((pair = pair.split('='))[0]) {
236 - var name = decodeURIComponent(pair[0]);
416 + var key = decodeURIComponent(pair.shift());
237 - var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
417 + var value = pair.length > 1 ? pair.join('=') : pair[0];
238 -
418 + if (value != undefined) value = decodeURIComponent(value);
239 - if (hash[name] !== undefined) {
419 +
240 - if (hash[name].constructor != Array)
420 + if (key in hash) {
241 - hash[name] = [hash[name]];
421 + if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
242 - if (value) hash[name].push(value);
422 + hash[key].push(value);
243 }
423 }
244 - else hash[name] = value;
424 + else hash[key] = value;
245 }
425 }
246 return hash;
426 return hash;
247 });
427 });
@@ -256,6 +436,10
256 String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
436 String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
257 },
437 },
258
438
439 + times: function(count) {
440 + return count < 1 ? '' : new Array(count + 1).join(this);
441 + },
442 +
259 camelize: function() {
443 camelize: function() {
260 var parts = this.split('-'), len = parts.length;
444 var parts = this.split('-'), len = parts.length;
261 if (len == 1) return parts[0];
445 if (len == 1) return parts[0];
@@ -270,7 +454,7
270 return camelized;
454 return camelized;
271 },
455 },
272
456
273 - capitalize: function(){
457 + capitalize: function() {
274 return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
458 return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
275 },
459 },
276
460
@@ -283,52 +467,131
283 },
467 },
284
468
285 inspect: function(useDoubleQuotes) {
469 inspect: function(useDoubleQuotes) {
286 - var escapedString = this.replace(/\\/g, '\\\\');
470 + var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
287 - if (useDoubleQuotes)
471 + var character = String.specialChar[match[0]];
288 - return '"' + escapedString.replace(/"/g, '\\"') + '"';
472 + return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
289 - else
473 + });
290 - return "'" + escapedString.replace(/'/g, '\\\'') + "'";
474 + if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
475 + return "'" + escapedString.replace(/'/g, '\\\'') + "'";
476 + },
477 +
478 + toJSON: function() {
479 + return this.inspect(true);
480 + },
481 +
482 + unfilterJSON: function(filter) {
483 + return this.sub(filter || Prototype.JSONFilter, '#{1}');
484 + },
485 +
486 + isJSON: function() {
487 + var str = this;
488 + if (str.blank()) return false;
489 + str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
490 + return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
491 + },
492 +
493 + evalJSON: function(sanitize) {
494 + var json = this.unfilterJSON();
495 + try {
496 + if (!sanitize || json.isJSON()) return eval('(' + json + ')');
497 + } catch (e) { }
498 + throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
499 + },
500 +
501 + include: function(pattern) {
502 + return this.indexOf(pattern) > -1;
503 + },
504 +
505 + startsWith: function(pattern) {
506 + return this.indexOf(pattern) === 0;
507 + },
508 +
509 + endsWith: function(pattern) {
510 + var d = this.length - pattern.length;
511 + return d >= 0 && this.lastIndexOf(pattern) === d;
512 + },
513 +
514 + empty: function() {
515 + return this == '';
516 + },
517 +
518 + blank: function() {
519 + return /^\s*$/.test(this);
520 + },
521 +
522 + interpolate: function(object, pattern) {
523 + return new Template(this, pattern).evaluate(object);
524 + }
525 + });
526 +
527 + if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
528 + escapeHTML: function() {
529 + return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
530 + },
531 + unescapeHTML: function() {
532 + return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
291 }
533 }
292 });
534 });
293
535
294 String.prototype.gsub.prepareReplacement = function(replacement) {
536 String.prototype.gsub.prepareReplacement = function(replacement) {
295 - if (typeof replacement == 'function') return replacement;
537 + if (Object.isFunction(replacement)) return replacement;
296 var template = new Template(replacement);
538 var template = new Template(replacement);
297 return function(match) { return template.evaluate(match) };
539 return function(match) { return template.evaluate(match) };
298 - }
540 + };
299
541
300 String.prototype.parseQuery = String.prototype.toQueryParams;
542 String.prototype.parseQuery = String.prototype.toQueryParams;
301
543
302 - var Template = Class.create();
544 + Object.extend(String.prototype.escapeHTML, {
303 - Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
545 + div: document.createElement('div'),
304 - Template.prototype = {
546 + text: document.createTextNode('')
547 + });
548 +
549 + with (String.prototype.escapeHTML) div.appendChild(text);
550 +
551 + var Template = Class.create({
305 initialize: function(template, pattern) {
552 initialize: function(template, pattern) {
306 this.template = template.toString();
553 this.template = template.toString();
307 - this.pattern = pattern || Template.Pattern;
554 + this.pattern = pattern || Template.Pattern;
308 },
555 },
309
556
310 evaluate: function(object) {
557 evaluate: function(object) {
558 + if (Object.isFunction(object.toTemplateReplacements))
559 + object = object.toTemplateReplacements();
560 +
311 return this.template.gsub(this.pattern, function(match) {
561 return this.template.gsub(this.pattern, function(match) {
312 - var before = match[1];
562 + if (object == null) return '';
563 +
564 + var before = match[1] || '';
313 if (before == '\\') return match[2];
565 if (before == '\\') return match[2];
314 - return before + String.interpret(object[match[3]]);
566 +
315 - });
567 + var ctx = object, expr = match[3];
568 + var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
569 + match = pattern.exec(expr);
570 + if (match == null) return before;
571 +
572 + while (match != null) {
573 + var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
574 + ctx = ctx[comp];
575 + if (null == ctx || '' == match[3]) break;
576 + expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
577 + match = pattern.exec(expr);
578 + }
579 +
580 + return before + String.interpret(ctx);
581 + }.bind(this));
316 }
582 }
317 - }
583 + });
318 -
584 + Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
319 - var $break = new Object();
585 +
320 - var $continue = new Object();
586 + var $break = { };
321
587
322 var Enumerable = {
588 var Enumerable = {
323 - each: function(iterator) {
589 + each: function(iterator, context) {
324 var index = 0;
590 var index = 0;
591 + iterator = iterator.bind(context);
325 try {
592 try {
326 this._each(function(value) {
593 this._each(function(value) {
327 - try {
594 + iterator(value, index++);
328 - iterator(value, index++);
329 - } catch (e) {
330 - if (e != $continue) throw e;
331 - }
332 });
595 });
333 } catch (e) {
596 } catch (e) {
334 if (e != $break) throw e;
597 if (e != $break) throw e;
@@ -336,40 +599,45
336 return this;
599 return this;
337 },
600 },
338
601
339 - eachSlice: function(number, iterator) {
602 + eachSlice: function(number, iterator, context) {
603 + iterator = iterator ? iterator.bind(context) : Prototype.K;
340 var index = -number, slices = [], array = this.toArray();
604 var index = -number, slices = [], array = this.toArray();
341 while ((index += number) < array.length)
605 while ((index += number) < array.length)
342 slices.push(array.slice(index, index+number));
606 slices.push(array.slice(index, index+number));
343 - return slices.map(iterator);
607 + return slices.collect(iterator, context);
344 - },
608 + },
345 -
609 +
346 - all: function(iterator) {
610 + all: function(iterator, context) {
611 + iterator = iterator ? iterator.bind(context) : Prototype.K;
347 var result = true;
612 var result = true;
348 this.each(function(value, index) {
613 this.each(function(value, index) {
349 - result = result && !!(iterator || Prototype.K)(value, index);
614 + result = result && !!iterator(value, index);
350 if (!result) throw $break;
615 if (!result) throw $break;
351 });
616 });
352 return result;
617 return result;
353 },
618 },
354
619
355 - any: function(iterator) {
620 + any: function(iterator, context) {
621 + iterator = iterator ? iterator.bind(context) : Prototype.K;
356 var result = false;
622 var result = false;
357 this.each(function(value, index) {
623 this.each(function(value, index) {
358 - if (result = !!(iterator || Prototype.K)(value, index))
624 + if (result = !!iterator(value, index))
359 throw $break;
625 throw $break;
360 });
626 });
361 return result;
627 return result;
362 },
628 },
363
629
364 - collect: function(iterator) {
630 + collect: function(iterator, context) {
631 + iterator = iterator ? iterator.bind(context) : Prototype.K;
365 var results = [];
632 var results = [];
366 this.each(function(value, index) {
633 this.each(function(value, index) {
367 - results.push((iterator || Prototype.K)(value, index));
634 + results.push(iterator(value, index));
368 });
635 });
369 return results;
636 return results;
370 },
637 },
371
638
372 - detect: function(iterator) {
639 + detect: function(iterator, context) {
640 + iterator = iterator.bind(context);
373 var result;
641 var result;
374 this.each(function(value, index) {
642 this.each(function(value, index) {
375 if (iterator(value, index)) {
643 if (iterator(value, index)) {
@@ -380,7 +648,8
380 return result;
648 return result;
381 },
649 },
382
650
383 - findAll: function(iterator) {
651 + findAll: function(iterator, context) {
652 + iterator = iterator.bind(context);
384 var results = [];
653 var results = [];
385 this.each(function(value, index) {
654 this.each(function(value, index) {
386 if (iterator(value, index))
655 if (iterator(value, index))
@@ -389,17 +658,24
389 return results;
658 return results;
390 },
659 },
391
660
392 - grep: function(pattern, iterator) {
661 + grep: function(filter, iterator, context) {
662 + iterator = iterator ? iterator.bind(context) : Prototype.K;
393 var results = [];
663 var results = [];
664 +
665 + if (Object.isString(filter))
666 + filter = new RegExp(filter);
667 +
394 this.each(function(value, index) {
668 this.each(function(value, index) {
395 - var stringValue = value.toString();
669 + if (filter.match(value))
396 - if (stringValue.match(pattern))
670 + results.push(iterator(value, index));
397 - results.push((iterator || Prototype.K)(value, index));
671 + });
398 - })
399 return results;
672 return results;
400 },
673 },
401
674
402 include: function(object) {
675 include: function(object) {
676 + if (Object.isFunction(this.indexOf))
677 + if (this.indexOf(object) != -1) return true;
678 +
403 var found = false;
679 var found = false;
404 this.each(function(value) {
680 this.each(function(value) {
405 if (value == object) {
681 if (value == object) {
@@ -411,14 +687,15
411 },
687 },
412
688
413 inGroupsOf: function(number, fillWith) {
689 inGroupsOf: function(number, fillWith) {
414 - fillWith = fillWith === undefined ? null : fillWith;
690 + fillWith = Object.isUndefined(fillWith) ? null : fillWith;
415 return this.eachSlice(number, function(slice) {
691 return this.eachSlice(number, function(slice) {
416 while(slice.length < number) slice.push(fillWith);
692 while(slice.length < number) slice.push(fillWith);
417 return slice;
693 return slice;
418 });
694 });
419 },
695 },
420
696
421 - inject: function(memo, iterator) {
697 + inject: function(memo, iterator, context) {
698 + iterator = iterator.bind(context);
422 this.each(function(value, index) {
699 this.each(function(value, index) {
423 memo = iterator(memo, value, index);
700 memo = iterator(memo, value, index);
424 });
701 });
@@ -432,30 +709,33
432 });
709 });
433 },
710 },
434
711
435 - max: function(iterator) {
712 + max: function(iterator, context) {
713 + iterator = iterator ? iterator.bind(context) : Prototype.K;
436 var result;
714 var result;
437 this.each(function(value, index) {
715 this.each(function(value, index) {
438 - value = (iterator || Prototype.K)(value, index);
716 + value = iterator(value, index);
439 - if (result == undefined || value >= result)
717 + if (result == null || value >= result)
440 result = value;
718 result = value;
441 });
719 });
442 return result;
720 return result;
443 },
721 },
444
722
445 - min: function(iterator) {
723 + min: function(iterator, context) {
724 + iterator = iterator ? iterator.bind(context) : Prototype.K;
446 var result;
725 var result;
447 this.each(function(value, index) {
726 this.each(function(value, index) {
448 - value = (iterator || Prototype.K)(value, index);
727 + value = iterator(value, index);
449 - if (result == undefined || value < result)
728 + if (result == null || value < result)
450 result = value;
729 result = value;
451 });
730 });
452 return result;
731 return result;
453 },
732 },
454
733
455 - partition: function(iterator) {
734 + partition: function(iterator, context) {
735 + iterator = iterator ? iterator.bind(context) : Prototype.K;
456 var trues = [], falses = [];
736 var trues = [], falses = [];
457 this.each(function(value, index) {
737 this.each(function(value, index) {
458 - ((iterator || Prototype.K)(value, index) ?
738 + (iterator(value, index) ?
459 trues : falses).push(value);
739 trues : falses).push(value);
460 });
740 });
461 return [trues, falses];
741 return [trues, falses];
@@ -463,13 +743,14
463
743
464 pluck: function(property) {
744 pluck: function(property) {
465 var results = [];
745 var results = [];
466 - this.each(function(value, index) {
746 + this.each(function(value) {
467 results.push(value[property]);
747 results.push(value[property]);
468 });
748 });
469 return results;
749 return results;
470 },
750 },
471
751
472 - reject: function(iterator) {
752 + reject: function(iterator, context) {
753 + iterator = iterator.bind(context);
473 var results = [];
754 var results = [];
474 this.each(function(value, index) {
755 this.each(function(value, index) {
475 if (!iterator(value, index))
756 if (!iterator(value, index))
@@ -478,7 +759,8
478 return results;
759 return results;
479 },
760 },
480
761
481 - sortBy: function(iterator) {
762 + sortBy: function(iterator, context) {
763 + iterator = iterator.bind(context);
482 return this.map(function(value, index) {
764 return this.map(function(value, index) {
483 return {value: value, criteria: iterator(value, index)};
765 return {value: value, criteria: iterator(value, index)};
484 }).sort(function(left, right) {
766 }).sort(function(left, right) {
@@ -493,7 +775,7
493
775
494 zip: function() {
776 zip: function() {
495 var iterator = Prototype.K, args = $A(arguments);
777 var iterator = Prototype.K, args = $A(arguments);
496 - if (typeof args.last() == 'function')
778 + if (Object.isFunction(args.last()))
497 iterator = args.pop();
779 iterator = args.pop();
498
780
499 var collections = [this].concat(args).map($A);
781 var collections = [this].concat(args).map($A);
@@ -509,31 +791,42
509 inspect: function() {
791 inspect: function() {
510 return '#<Enumerable:' + this.toArray().inspect() + '>';
792 return '#<Enumerable:' + this.toArray().inspect() + '>';
511 }
793 }
512 - }
794 + };
513
795
514 Object.extend(Enumerable, {
796 Object.extend(Enumerable, {
515 map: Enumerable.collect,
797 map: Enumerable.collect,
516 find: Enumerable.detect,
798 find: Enumerable.detect,
517 select: Enumerable.findAll,
799 select: Enumerable.findAll,
800 + filter: Enumerable.findAll,
518 member: Enumerable.include,
801 member: Enumerable.include,
519 - entries: Enumerable.toArray
802 + entries: Enumerable.toArray,
803 + every: Enumerable.all,
804 + some: Enumerable.any
520 });
805 });
521 - var $A = Array.from = function(iterable) {
806 + function $A(iterable) {
522 if (!iterable) return [];
807 if (!iterable) return [];
523 - if (iterable.toArray) {
808 + if (iterable.toArray) return iterable.toArray();
524 - return iterable.toArray();
809 + var length = iterable.length, results = new Array(length);
525 - } else {
810 + while (length--) results[length] = iterable[length];
526 - var results = [];
811 + return results;
527 - for (var i = 0, length = iterable.length; i < length; i++)
812 + }
528 - results.push(iterable[i]);
813 +
814 + if (Prototype.Browser.WebKit) {
815 + function $A(iterable) {
816 + if (!iterable) return [];
817 + if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
818 + iterable.toArray) return iterable.toArray();
819 + var length = iterable.length, results = new Array(length);
820 + while (length--) results[length] = iterable[length];
529 return results;
821 return results;
530 }
822 }
531 }
823 }
532
824
825 + Array.from = $A;
826 +
533 Object.extend(Array.prototype, Enumerable);
827 Object.extend(Array.prototype, Enumerable);
534
828
535 - if (!Array.prototype._reverse)
829 + if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;
536 - Array.prototype._reverse = Array.prototype.reverse;
537
830
538 Object.extend(Array.prototype, {
831 Object.extend(Array.prototype, {
539 _each: function(iterator) {
832 _each: function(iterator) {
@@ -562,7 +855,7
562
855
563 flatten: function() {
856 flatten: function() {
564 return this.inject([], function(array, value) {
857 return this.inject([], function(array, value) {
565 - return array.concat(value && value.constructor == Array ?
858 + return array.concat(Object.isArray(value) ?
566 value.flatten() : [value]);
859 value.flatten() : [value]);
567 });
860 });
568 },
861 },
@@ -574,12 +867,6
574 });
867 });
575 },
868 },
576
869
577 - indexOf: function(object) {
578 - for (var i = 0, length = this.length; i < length; i++)
579 - if (this[i] == object) return i;
580 - return -1;
581 - },
582 -
583 reverse: function(inline) {
870 reverse: function(inline) {
584 return (inline !== false ? this : this.toArray())._reverse();
871 return (inline !== false ? this : this.toArray())._reverse();
585 },
872 },
@@ -588,9 +875,17
588 return this.length > 1 ? this : this[0];
875 return this.length > 1 ? this : this[0];
589 },
876 },
590
877
591 - uniq: function() {
878 + uniq: function(sorted) {
592 - return this.inject([], function(array, value) {
879 + return this.inject([], function(array, value, index) {
593 - return array.include(value) ? array : array.concat([value]);
880 + if (0 == index || (sorted ? array.last() != value : !array.include(value)))
881 + array.push(value);
882 + return array;
883 + });
884 + },
885 +
886 + intersect: function(array) {
887 + return this.uniq().findAll(function(item) {
888 + return array.detect(function(value) { return item === value });
594 });
889 });
595 },
890 },
596
891
@@ -604,125 +899,187
604
899
605 inspect: function() {
900 inspect: function() {
606 return '[' + this.map(Object.inspect).join(', ') + ']';
901 return '[' + this.map(Object.inspect).join(', ') + ']';
902 + },
903 +
904 + toJSON: function() {
905 + var results = [];
906 + this.each(function(object) {
907 + var value = Object.toJSON(object);
908 + if (!Object.isUndefined(value)) results.push(value);
909 + });
910 + return '[' + results.join(', ') + ']';
607 }
911 }
608 });
912 });
609
913
914 + // use native browser JS 1.6 implementation if available
915 + if (Object.isFunction(Array.prototype.forEach))
916 + Array.prototype._each = Array.prototype.forEach;
917 +
918 + if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {
919 + i || (i = 0);
920 + var length = this.length;
921 + if (i < 0) i = length + i;
922 + for (; i < length; i++)
923 + if (this[i] === item) return i;
924 + return -1;
925 + };
926 +
927 + if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {
928 + i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
929 + var n = this.slice(0, i).reverse().indexOf(item);
930 + return (n < 0) ? n : i - n - 1;
931 + };
932 +
610 Array.prototype.toArray = Array.prototype.clone;
933 Array.prototype.toArray = Array.prototype.clone;
611
934
612 - function $w(string){
935 + function $w(string) {
936 + if (!Object.isString(string)) return [];
613 string = string.strip();
937 string = string.strip();
614 return string ? string.split(/\s+/) : [];
938 return string ? string.split(/\s+/) : [];
615 }
939 }
616
940
617 - if(window.opera){
941 + if (Prototype.Browser.Opera){
618 - Array.prototype.concat = function(){
942 + Array.prototype.concat = function() {
619 var array = [];
943 var array = [];
620 - for(var i = 0, length = this.length; i < length; i++) array.push(this[i]);
944 + for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
621 - for(var i = 0, length = arguments.length; i < length; i++) {
945 + for (var i = 0, length = arguments.length; i < length; i++) {
622 - if(arguments[i].constructor == Array) {
946 + if (Object.isArray(arguments[i])) {
623 - for(var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
947 + for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
624 array.push(arguments[i][j]);
948 array.push(arguments[i][j]);
625 } else {
949 } else {
626 array.push(arguments[i]);
950 array.push(arguments[i]);
627 }
951 }
628 }
952 }
629 return array;
953 return array;
630 - }
954 + };
631 }
955 }
632 - var Hash = function(obj) {
956 + Object.extend(Number.prototype, {
633 - Object.extend(this, obj || {});
957 + toColorPart: function() {
634 - };
958 + return this.toPaddedString(2, 16);
635 -
959 + },
636 - Object.extend(Hash, {
960 +
637 - toQueryString: function(obj) {
961 + succ: function() {
638 - var parts = [];
962 + return this + 1;
639 -
963 + },
640 - this.prototype._each.call(obj, function(pair) {
964 +
641 - if (!pair.key) return;
965 + times: function(iterator) {
642 -
966 + $R(0, this, true).each(iterator);
643 - if (pair.value && pair.value.constructor == Array) {
967 + return this;
644 - var values = pair.value.compact();
968 + },
645 - if (values.length < 2) pair.value = values.reduce();
969 +
646 - else {
970 + toPaddedString: function(length, radix) {
647 - key = encodeURIComponent(pair.key);
971 + var string = this.toString(radix || 10);
648 - values.each(function(value) {
972 + return '0'.times(length - string.length) + string;
649 - value = value != undefined ? encodeURIComponent(value) : '';
973 + },
650 - parts.push(key + '=' + encodeURIComponent(value));
974 +
651 - });
975 + toJSON: function() {
652 - return;
976 + return isFinite(this) ? this.toString() : 'null';
653 - }
654 - }
655 - if (pair.value == undefined) pair[1] = '';
656 - parts.push(pair.map(encodeURIComponent).join('='));
657 - });
658 -
659 - return parts.join('&');
660 }
977 }
661 });
978 });
662
979
663 - Object.extend(Hash.prototype, Enumerable);
980 + $w('abs round ceil floor').each(function(method){
664 - Object.extend(Hash.prototype, {
981 + Number.prototype[method] = Math[method].methodize();
665 - _each: function(iterator) {
666 - for (var key in this) {
667 - var value = this[key];
668 - if (value && value == Hash.prototype[key]) continue;
669 -
670 - var pair = [key, value];
671 - pair.key = key;
672 - pair.value = value;
673 - iterator(pair);
674 - }
675 - },
676 -
677 - keys: function() {
678 - return this.pluck('key');
679 - },
680 -
681 - values: function() {
682 - return this.pluck('value');
683 - },
684 -
685 - merge: function(hash) {
686 - return $H(hash).inject(this, function(mergedHash, pair) {
687 - mergedHash[pair.key] = pair.value;
688 - return mergedHash;
689 - });
690 - },
691 -
692 - remove: function() {
693 - var result;
694 - for(var i = 0, length = arguments.length; i < length; i++) {
695 - var value = this[arguments[i]];
696 - if (value !== undefined){
697 - if (result === undefined) result = value;
698 - else {
699 - if (result.constructor != Array) result = [result];
700 - result.push(value)
701 - }
702 - }
703 - delete this[arguments[i]];
704 - }
705 - return result;
706 - },
707 -
708 - toQueryString: function() {
709 - return Hash.toQueryString(this);
710 - },
711 -
712 - inspect: function() {
713 - return '#<Hash:{' + this.map(function(pair) {
714 - return pair.map(Object.inspect).join(': ');
715 - }).join(', ') + '}>';
716 - }
717 });
982 });
718 -
719 function $H(object) {
983 function $H(object) {
720 - if (object && object.constructor == Hash) return object;
721 return new Hash(object);
984 return new Hash(object);
722 };
985 };
723 - ObjectRange = Class.create();
986 +
724 - Object.extend(ObjectRange.prototype, Enumerable);
987 + var Hash = Class.create(Enumerable, (function() {
725 - Object.extend(ObjectRange.prototype, {
988 +
989 + function toQueryPair(key, value) {
990 + if (Object.isUndefined(value)) return key;
991 + return key + '=' + encodeURIComponent(String.interpret(value));
992 + }
993 +
994 + return {
995 + initialize: function(object) {
996 + this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
997 + },
998 +
999 + _each: function(iterator) {
1000 + for (var key in this._object) {
1001 + var value = this._object[key], pair = [key, value];
1002 + pair.key = key;
1003 + pair.value = value;
1004 + iterator(pair);
1005 + }
1006 + },
1007 +
1008 + set: function(key, value) {
1009 + return this._object[key] = value;
1010 + },
1011 +
1012 + get: function(key) {
1013 + return this._object[key];
1014 + },
1015 +
1016 + unset: function(key) {
1017 + var value = this._object[key];
1018 + delete this._object[key];
1019 + return value;
1020 + },
1021 +
1022 + toObject: function() {
1023 + return Object.clone(this._object);
1024 + },
1025 +
1026 + keys: function() {
1027 + return this.pluck('key');
1028 + },
1029 +
1030 + values: function() {
1031 + return this.pluck('value');
1032 + },
1033 +
1034 + index: function(value) {
1035 + var match = this.detect(function(pair) {
1036 + return pair.value === value;
1037 + });
1038 + return match && match.key;
1039 + },
1040 +
1041 + merge: function(object) {
1042 + return this.clone().update(object);
1043 + },
1044 +
1045 + update: function(object) {
1046 + return new Hash(object).inject(this, function(result, pair) {
1047 + result.set(pair.key, pair.value);
1048 + return result;
1049 + });
1050 + },
1051 +
1052 + toQueryString: function() {
1053 + return this.map(function(pair) {
1054 + var key = encodeURIComponent(pair.key), values = pair.value;
1055 +
1056 + if (values && typeof values == 'object') {
1057 + if (Object.isArray(values))
1058 + return values.map(toQueryPair.curry(key)).join('&');
1059 + }
1060 + return toQueryPair(key, values);
1061 + }).join('&');
1062 + },
1063 +
1064 + inspect: function() {
1065 + return '#<Hash:{' + this.map(function(pair) {
1066 + return pair.map(Object.inspect).join(': ');
1067 + }).join(', ') + '}>';
1068 + },
1069 +
1070 + toJSON: function() {
1071 + return Object.toJSON(this.toObject());
1072 + },
1073 +
1074 + clone: function() {
1075 + return new Hash(this);
1076 + }
1077 + }
1078 + })());
1079 +
1080 + Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;
1081 + Hash.from = $H;
1082 + var ObjectRange = Class.create(Enumerable, {
726 initialize: function(start, end, exclusive) {
1083 initialize: function(start, end, exclusive) {
727 this.start = start;
1084 this.start = start;
728 this.end = end;
1085 this.end = end;
@@ -748,7 +1105,7
748
1105
749 var $R = function(start, end, exclusive) {
1106 var $R = function(start, end, exclusive) {
750 return new ObjectRange(start, end, exclusive);
1107 return new ObjectRange(start, end, exclusive);
751 - }
1108 + };
752
1109
753 var Ajax = {
1110 var Ajax = {
754 getTransport: function() {
1111 getTransport: function() {
@@ -760,7 +1117,7
760 },
1117 },
761
1118
762 activeRequestCount: 0
1119 activeRequestCount: 0
763 - }
1120 + };
764
1121
765 Ajax.Responders = {
1122 Ajax.Responders = {
766 responders: [],
1123 responders: [],
@@ -780,10 +1137,10
780
1137
781 dispatch: function(callback, request, transport, json) {
1138 dispatch: function(callback, request, transport, json) {
782 this.each(function(responder) {
1139 this.each(function(responder) {
783 - if (typeof responder[callback] == 'function') {
1140 + if (Object.isFunction(responder[callback])) {
784 try {
1141 try {
785 responder[callback].apply(responder, [request, transport, json]);
1142 responder[callback].apply(responder, [request, transport, json]);
786 - } catch (e) {}
1143 + } catch (e) { }
787 }
1144 }
788 });
1145 });
789 }
1146 }
@@ -792,49 +1149,45
792 Object.extend(Ajax.Responders, Enumerable);
1149 Object.extend(Ajax.Responders, Enumerable);
793
1150
794 Ajax.Responders.register({
1151 Ajax.Responders.register({
795 - onCreate: function() {
1152 + onCreate: function() { Ajax.activeRequestCount++ },
796 - Ajax.activeRequestCount++;
1153 + onComplete: function() { Ajax.activeRequestCount-- }
797 - },
798 - onComplete: function() {
799 - Ajax.activeRequestCount--;
800 - }
801 });
1154 });
802
1155
803 - Ajax.Base = function() {};
1156 + Ajax.Base = Class.create({
804 - Ajax.Base.prototype = {
1157 + initialize: function(options) {
805 - setOptions: function(options) {
806 this.options = {
1158 this.options = {
807 method: 'post',
1159 method: 'post',
808 asynchronous: true,
1160 asynchronous: true,
809 contentType: 'application/x-www-form-urlencoded',
1161 contentType: 'application/x-www-form-urlencoded',
810 encoding: 'UTF-8',
1162 encoding: 'UTF-8',
811 - parameters: ''
1163 + parameters: '',
812 - }
1164 + evalJSON: true,
813 - Object.extend(this.options, options || {});
1165 + evalJS: true
1166 + };
1167 + Object.extend(this.options, options || { });
814
1168
815 this.options.method = this.options.method.toLowerCase();
1169 this.options.method = this.options.method.toLowerCase();
816 - if (typeof this.options.parameters == 'string')
1170 +
1171 + if (Object.isString(this.options.parameters))
817 this.options.parameters = this.options.parameters.toQueryParams();
1172 this.options.parameters = this.options.parameters.toQueryParams();
1173 + else if (Object.isHash(this.options.parameters))
1174 + this.options.parameters = this.options.parameters.toObject();
818 }
1175 }
819 - }
1176 + });
820 -
1177 +
821 - Ajax.Request = Class.create();
1178 + Ajax.Request = Class.create(Ajax.Base, {
822 - Ajax.Request.Events =
823 - ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
824 -
825 - Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
826 _complete: false,
1179 _complete: false,
827
1180
828 - initialize: function(url, options) {
1181 + initialize: function($super, url, options) {
1182 + $super(options);
829 this.transport = Ajax.getTransport();
1183 this.transport = Ajax.getTransport();
830 - this.setOptions(options);
831 this.request(url);
1184 this.request(url);
832 },
1185 },
833
1186
834 request: function(url) {
1187 request: function(url) {
835 this.url = url;
1188 this.url = url;
836 this.method = this.options.method;
1189 this.method = this.options.method;
837 - var params = this.options.parameters;
1190 + var params = Object.clone(this.options.parameters);
838
1191
839 if (!['get', 'post'].include(this.method)) {
1192 if (!['get', 'post'].include(this.method)) {
840 // simulate other verbs over post
1193 // simulate other verbs over post
@@ -842,28 +1195,31
842 this.method = 'post';
1195 this.method = 'post';
843 }
1196 }
844
1197
845 - params = Hash.toQueryString(params);
1198 + this.parameters = params;
846 - if (params && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_='
1199 +
847 -
1200 + if (params = Object.toQueryString(params)) {
848 - // when GET, append parameters to URL
1201 + // when GET, append parameters to URL
849 - if (this.method == 'get' && params)
1202 + if (this.method == 'get')
850 - this.url += (this.url.indexOf('?') > -1 ? '&' : '?') + params;
1203 + this.url += (this.url.include('?') ? '&' : '?') + params;
1204 + else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
1205 + params += '&_=';
1206 + }
851
1207
852 try {
1208 try {
853 - Ajax.Responders.dispatch('onCreate', this, this.transport);
1209 + var response = new Ajax.Response(this);
1210 + if (this.options.onCreate) this.options.onCreate(response);
1211 + Ajax.Responders.dispatch('onCreate', this, response);
854
1212
855 this.transport.open(this.method.toUpperCase(), this.url,
1213 this.transport.open(this.method.toUpperCase(), this.url,
856 this.options.asynchronous);
1214 this.options.asynchronous);
857
1215
858 - if (this.options.asynchronous)
1216 + if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
859 - setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
860
1217
861 this.transport.onreadystatechange = this.onStateChange.bind(this);
1218 this.transport.onreadystatechange = this.onStateChange.bind(this);
862 this.setRequestHeaders();
1219 this.setRequestHeaders();
863
1220
864 - var body = this.method == 'post' ? (this.options.postBody || params) : null;
1221 + this.body = this.method == 'post' ? (this.options.postBody || params) : null;
865 -
1222 + this.transport.send(this.body);
866 - this.transport.send(body);
867
1223
868 /* Force Firefox to handle ready state 4 for synchronous requests */
1224 /* Force Firefox to handle ready state 4 for synchronous requests */
869 if (!this.options.asynchronous && this.transport.overrideMimeType)
1225 if (!this.options.asynchronous && this.transport.overrideMimeType)
@@ -905,7 +1261,7
905 if (typeof this.options.requestHeaders == 'object') {
1261 if (typeof this.options.requestHeaders == 'object') {
906 var extras = this.options.requestHeaders;
1262 var extras = this.options.requestHeaders;
907
1263
908 - if (typeof extras.push == 'function')
1264 + if (Object.isFunction(extras.push))
909 for (var i = 0, length = extras.length; i < length; i += 2)
1265 for (var i = 0, length = extras.length; i < length; i += 2)
910 headers[extras[i]] = extras[i+1];
1266 headers[extras[i]] = extras[i+1];
911 else
1267 else
@@ -917,32 +1273,39
917 },
1273 },
918
1274
919 success: function() {
1275 success: function() {
920 - return !this.transport.status
1276 + var status = this.getStatus();
921 - || (this.transport.status >= 200 && this.transport.status < 300);
1277 + return !status || (status >= 200 && status < 300);
1278 + },
1279 +
1280 + getStatus: function() {
1281 + try {
1282 + return this.transport.status || 0;
1283 + } catch (e) { return 0 }
922 },
1284 },
923
1285
924 respondToReadyState: function(readyState) {
1286 respondToReadyState: function(readyState) {
925 - var state = Ajax.Request.Events[readyState];
1287 + var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
926 - var transport = this.transport, json = this.evalJSON();
927
1288
928 if (state == 'Complete') {
1289 if (state == 'Complete') {
929 try {
1290 try {
930 this._complete = true;
1291 this._complete = true;
931 - (this.options['on' + this.transport.status]
1292 + (this.options['on' + response.status]
932 || this.options['on' + (this.success() ? 'Success' : 'Failure')]
1293 || this.options['on' + (this.success() ? 'Success' : 'Failure')]
933 - || Prototype.emptyFunction)(transport, json);
1294 + || Prototype.emptyFunction)(response, response.headerJSON);
934 } catch (e) {
1295 } catch (e) {
935 this.dispatchException(e);
1296 this.dispatchException(e);
936 }
1297 }
937
1298
938 - if ((this.getHeader('Content-type') || 'text/javascript').strip().
1299 + var contentType = response.getHeader('Content-type');
939 - match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
1300 + if (this.options.evalJS == 'force'
940 - this.evalResponse();
1301 + || (this.options.evalJS && contentType
1302 + && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
1303 + this.evalResponse();
941 }
1304 }
942
1305
943 try {
1306 try {
944 - (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
1307 + (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
945 - Ajax.Responders.dispatch('on' + state, this, transport, json);
1308 + Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
946 } catch (e) {
1309 } catch (e) {
947 this.dispatchException(e);
1310 this.dispatchException(e);
948 }
1311 }
@@ -959,16 +1322,9
959 } catch (e) { return null }
1322 } catch (e) { return null }
960 },
1323 },
961
1324
962 - evalJSON: function() {
963 - try {
964 - var json = this.getHeader('X-JSON');
965 - return json ? eval('(' + json + ')') : null;
966 - } catch (e) { return null }
967 - },
968 -
969 evalResponse: function() {
1325 evalResponse: function() {
970 try {
1326 try {
971 - return eval(this.transport.responseText);
1327 + return eval((this.transport.responseText || '').unfilterJSON());
972 } catch (e) {
1328 } catch (e) {
973 this.dispatchException(e);
1329 this.dispatchException(e);
974 }
1330 }
@@ -980,57 +1336,126
980 }
1336 }
981 });
1337 });
982
1338
983 - Ajax.Updater = Class.create();
1339 + Ajax.Request.Events =
984 -
1340 + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
985 - Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
1341 +
986 - initialize: function(container, url, options) {
1342 + Ajax.Response = Class.create({
1343 + initialize: function(request){
1344 + this.request = request;
1345 + var transport = this.transport = request.transport,
1346 + readyState = this.readyState = transport.readyState;
1347 +
1348 + if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
1349 + this.status = this.getStatus();
1350 + this.statusText = this.getStatusText();
1351 + this.responseText = String.interpret(transport.responseText);
1352 + this.headerJSON = this._getHeaderJSON();
1353 + }
1354 +
1355 + if(readyState == 4) {
1356 + var xml = transport.responseXML;
1357 + this.responseXML = Object.isUndefined(xml) ? null : xml;
1358 + this.responseJSON = this._getResponseJSON();
1359 + }
1360 + },
1361 +
1362 + status: 0,
1363 + statusText: '',
1364 +
1365 + getStatus: Ajax.Request.prototype.getStatus,
1366 +
1367 + getStatusText: function() {
1368 + try {
1369 + return this.transport.statusText || '';
1370 + } catch (e) { return '' }
1371 + },
1372 +
1373 + getHeader: Ajax.Request.prototype.getHeader,
1374 +
1375 + getAllHeaders: function() {
1376 + try {
1377 + return this.getAllResponseHeaders();
1378 + } catch (e) { return null }
1379 + },
1380 +
1381 + getResponseHeader: function(name) {
1382 + return this.transport.getResponseHeader(name);
1383 + },
1384 +
1385 + getAllResponseHeaders: function() {
1386 + return this.transport.getAllResponseHeaders();
1387 + },
1388 +
1389 + _getHeaderJSON: function() {
1390 + var json = this.getHeader('X-JSON');
1391 + if (!json) return null;
1392 + json = decodeURIComponent(escape(json));
1393 + try {
1394 + return json.evalJSON(this.request.options.sanitizeJSON);
1395 + } catch (e) {
1396 + this.request.dispatchException(e);
1397 + }
1398 + },
1399 +
1400 + _getResponseJSON: function() {
1401 + var options = this.request.options;
1402 + if (!options.evalJSON || (options.evalJSON != 'force' &&
1403 + !(this.getHeader('Content-type') || '').include('application/json')) ||
1404 + this.responseText.blank())
1405 + return null;
1406 + try {
1407 + return this.responseText.evalJSON(options.sanitizeJSON);
1408 + } catch (e) {
1409 + this.request.dispatchException(e);
1410 + }
1411 + }
1412 + });
1413 +
1414 + Ajax.Updater = Class.create(Ajax.Request, {
1415 + initialize: function($super, container, url, options) {
987 this.container = {
1416 this.container = {
988 success: (container.success || container),
1417 success: (container.success || container),
989 failure: (container.failure || (container.success ? null : container))
1418 failure: (container.failure || (container.success ? null : container))
990 - }
1419 + };
991 -
1420 +
992 - this.transport = Ajax.getTransport();
1421 + options = Object.clone(options);
993 - this.setOptions(options);
1422 + var onComplete = options.onComplete;
994 -
1423 + options.onComplete = (function(response, json) {
995 - var onComplete = this.options.onComplete || Prototype.emptyFunction;
1424 + this.updateContent(response.responseText);
996 - this.options.onComplete = (function(transport, param) {
1425 + if (Object.isFunction(onComplete)) onComplete(response, json);
997 - this.updateContent();
998 - onComplete(transport, param);
999 }).bind(this);
1426 }).bind(this);
1000
1427
1001 - this.request(url);
1428 + $super(url, options);
1002 - },
1429 + },
1003 -
1430 +
1004 - updateContent: function() {
1431 + updateContent: function(responseText) {
1005 - var receiver = this.container[this.success() ? 'success' : 'failure'];
1432 + var receiver = this.container[this.success() ? 'success' : 'failure'],
1006 - var response = this.transport.responseText;
1433 + options = this.options;
1007 -
1434 +
1008 - if (!this.options.evalScripts) response = response.stripScripts();
1435 + if (!options.evalScripts) responseText = responseText.stripScripts();
1009
1436
1010 if (receiver = $(receiver)) {
1437 if (receiver = $(receiver)) {
1011 - if (this.options.insertion)
1438 + if (options.insertion) {
1012 - new this.options.insertion(receiver, response);
1439 + if (Object.isString(options.insertion)) {
1013 - else
1440 + var insertion = { }; insertion[options.insertion] = responseText;
1014 - receiver.update(response);
1441 + receiver.insert(insertion);
1015 - }
1442 + }
1016 -
1443 + else options.insertion(receiver, responseText);
1017 - if (this.success()) {
1444 + }
1018 - if (this.onComplete)
1445 + else receiver.update(responseText);
1019 - setTimeout(this.onComplete.bind(this), 10);
1020 }
1446 }
1021 }
1447 }
1022 });
1448 });
1023
1449
1024 - Ajax.PeriodicalUpdater = Class.create();
1450 + Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
1025 - Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
1451 + initialize: function($super, container, url, options) {
1026 - initialize: function(container, url, options) {
1452 + $super(options);
1027 - this.setOptions(options);
1028 this.onComplete = this.options.onComplete;
1453 this.onComplete = this.options.onComplete;
1029
1454
1030 this.frequency = (this.options.frequency || 2);
1455 this.frequency = (this.options.frequency || 2);
1031 this.decay = (this.options.decay || 1);
1456 this.decay = (this.options.decay || 1);
1032
1457
1033 - this.updater = {};
1458 + this.updater = { };
1034 this.container = container;
1459 this.container = container;
1035 this.url = url;
1460 this.url = url;
1036
1461
@@ -1048,15 +1473,14
1048 (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
1473 (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
1049 },
1474 },
1050
1475
1051 - updateComplete: function(request) {
1476 + updateComplete: function(response) {
1052 if (this.options.decay) {
1477 if (this.options.decay) {
1053 - this.decay = (request.responseText == this.lastText ?
1478 + this.decay = (response.responseText == this.lastText ?
1054 this.decay * this.options.decay : 1);
1479 this.decay * this.options.decay : 1);
1055
1480
1056 - this.lastText = request.responseText;
1481 + this.lastText = response.responseText;
1057 }
1482 }
1058 - this.timer = setTimeout(this.onTimerEvent.bind(this),
1483 + this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
1059 - this.decay * this.frequency * 1000);
1060 },
1484 },
1061
1485
1062 onTimerEvent: function() {
1486 onTimerEvent: function() {
@@ -1069,7 +1493,7
1069 elements.push($(arguments[i]));
1493 elements.push($(arguments[i]));
1070 return elements;
1494 return elements;
1071 }
1495 }
1072 - if (typeof element == 'string')
1496 + if (Object.isString(element))
1073 element = document.getElementById(element);
1497 element = document.getElementById(element);
1074 return Element.extend(element);
1498 return Element.extend(element);
1075 }
1499 }
@@ -1080,63 +1504,51
1080 var query = document.evaluate(expression, $(parentElement) || document,
1504 var query = document.evaluate(expression, $(parentElement) || document,
1081 null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
1505 null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
1082 for (var i = 0, length = query.snapshotLength; i < length; i++)
1506 for (var i = 0, length = query.snapshotLength; i < length; i++)
1083 - results.push(query.snapshotItem(i));
1507 + results.push(Element.extend(query.snapshotItem(i)));
1084 return results;
1508 return results;
1085 };
1509 };
1086 }
1510 }
1087
1511
1088 - document.getElementsByClassName = function(className, parentElement) {
1512 + /*--------------------------------------------------------------------------*/
1089 - if (Prototype.BrowserFeatures.XPath) {
1513 +
1090 - var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
1514 + if (!window.Node) var Node = { };
1091 - return document._getElementsByXPath(q, parentElement);
1515 +
1092 - } else {
1516 + if (!Node.ELEMENT_NODE) {
1093 - var children = ($(parentElement) || document.body).getElementsByTagName('*');
1517 + // DOM level 2 ECMAScript Language Binding
1094 - var elements = [], child;
1518 + Object.extend(Node, {
1095 - for (var i = 0, length = children.length; i < length; i++) {
1519 + ELEMENT_NODE: 1,
1096 - child = children[i];
1520 + ATTRIBUTE_NODE: 2,
1097 - if (Element.hasClassName(child, className))
1521 + TEXT_NODE: 3,
1098 - elements.push(Element.extend(child));
1522 + CDATA_SECTION_NODE: 4,
1523 + ENTITY_REFERENCE_NODE: 5,
1524 + ENTITY_NODE: 6,
1525 + PROCESSING_INSTRUCTION_NODE: 7,
1526 + COMMENT_NODE: 8,
1527 + DOCUMENT_NODE: 9,
1528 + DOCUMENT_TYPE_NODE: 10,
1529 + DOCUMENT_FRAGMENT_NODE: 11,
1530 + NOTATION_NODE: 12
1531 + });
1532 + }
1533 +
1534 + (function() {
1535 + var element = this.Element;
1536 + this.Element = function(tagName, attributes) {
1537 + attributes = attributes || { };
1538 + tagName = tagName.toLowerCase();
1539 + var cache = Element.cache;
1540 + if (Prototype.Browser.IE && attributes.name) {
1541 + tagName = '<' + tagName + ' name="' + attributes.name + '">';
1542 + delete attributes.name;
1543 + return Element.writeAttribute(document.createElement(tagName), attributes);
1099 }
1544 }
1100 - return elements;
1545 + if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
1101 - }
1546 + return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
1102 - };
1547 + };
1103 -
1548 + Object.extend(this.Element, element || { });
1104 - /*--------------------------------------------------------------------------*/
1549 + }).call(window);
1105 -
1550 +
1106 - if (!window.Element)
1551 + Element.cache = { };
1107 - var Element = new Object();
1108 -
1109 - Element.extend = function(element) {
1110 - if (!element || _nativeExtensions || element.nodeType == 3) return element;
1111 -
1112 - if (!element._extended && element.tagName && element != window) {
1113 - var methods = Object.clone(Element.Methods), cache = Element.extend.cache;
1114 -
1115 - if (element.tagName == 'FORM')
1116 - Object.extend(methods, Form.Methods);
1117 - if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
1118 - Object.extend(methods, Form.Element.Methods);
1119 -
1120 - Object.extend(methods, Element.Methods.Simulated);
1121 -
1122 - for (var property in methods) {
1123 - var value = methods[property];
1124 - if (typeof value == 'function' && !(property in element))
1125 - element[property] = cache.findOrStore(value);
1126 - }
1127 - }
1128 -
1129 - element._extended = true;
1130 - return element;
1131 - };
1132 -
1133 - Element.extend.cache = {
1134 - findOrStore: function(value) {
1135 - return this[value] = this[value] || function() {
1136 - return value.apply(null, [this].concat($A(arguments)));
1137 - }
1138 - }
1139 - };
1140
1552
1141 Element.Methods = {
1553 Element.Methods = {
1142 visible: function(element) {
1554 visible: function(element) {
@@ -1165,28 +1577,74
1165 return element;
1577 return element;
1166 },
1578 },
1167
1579
1168 - update: function(element, html) {
1580 + update: function(element, content) {
1169 - html = typeof html == 'undefined' ? '' : html.toString();
1581 + element = $(element);
1170 - $(element).innerHTML = html.stripScripts();
1582 + if (content && content.toElement) content = content.toElement();
1171 - setTimeout(function() {html.evalScripts()}, 10);
1583 + if (Object.isElement(content)) return element.update().insert(content);
1584 + content = Object.toHTML(content);
1585 + element.innerHTML = content.stripScripts();
1586 + content.evalScripts.bind(content).defer();
1172 return element;
1587 return element;
1173 },
1588 },
1174
1589
1175 - replace: function(element, html) {
1590 + replace: function(element, content) {
1591 + element = $(element);
1592 + if (content && content.toElement) content = content.toElement();
1593 + else if (!Object.isElement(content)) {
1594 + content = Object.toHTML(content);
1595 + var range = element.ownerDocument.createRange();
1596 + range.selectNode(element);
1597 + content.evalScripts.bind(content).defer();
1598 + content = range.createContextualFragment(content.stripScripts());
1599 + }
1600 + element.parentNode.replaceChild(content, element);
1601 + return element;
1602 + },
1603 +
1604 + insert: function(element, insertions) {
1176 element = $(element);
1605 element = $(element);
1177 - html = typeof html == 'undefined' ? '' : html.toString();
1606 +
1178 - if (element.outerHTML) {
1607 + if (Object.isString(insertions) || Object.isNumber(insertions) ||
1179 - element.outerHTML = html.stripScripts();
1608 + Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
1180 - } else {
1609 + insertions = {bottom:insertions};
1181 - var range = element.ownerDocument.createRange();
1610 +
1182 - range.selectNodeContents(element);
1611 + var content, t, range;
1183 - element.parentNode.replaceChild(
1612 +
1184 - range.createContextualFragment(html.stripScripts()), element);
1613 + for (position in insertions) {
1614 + content = insertions[position];
1615 + position = position.toLowerCase();
1616 + t = Element._insertionTranslations[position];
1617 +
1618 + if (content && content.toElement) content = content.toElement();
1619 + if (Object.isElement(content)) {
1620 + t.insert(element, content);
1621 + continue;
1622 + }
1623 +
1624 + content = Object.toHTML(content);
1625 +
1626 + range = element.ownerDocument.createRange();
1627 + t.initializeRange(element, range);
1628 + t.insert(element, range.createContextualFragment(content.stripScripts()));
1629 +
1630 + content.evalScripts.bind(content).defer();
1185 }
1631 }
1186 - setTimeout(function() {html.evalScripts()}, 10);
1632 +
1187 return element;
1633 return element;
1188 },
1634 },
1189
1635
1636 + wrap: function(element, wrapper, attributes) {
1637 + element = $(element);
1638 + if (Object.isElement(wrapper))
1639 + $(wrapper).writeAttribute(attributes || { });
1640 + else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
1641 + else wrapper = new Element('div', wrapper);
1642 + if (element.parentNode)
1643 + element.parentNode.replaceChild(wrapper, element);
1644 + wrapper.appendChild(element);
1645 + return wrapper;
1646 + },
1647 +
1190 inspect: function(element) {
1648 inspect: function(element) {
1191 element = $(element);
1649 element = $(element);
1192 var result = '<' + element.tagName.toLowerCase();
1650 var result = '<' + element.tagName.toLowerCase();
@@ -1212,7 +1670,13
1212 },
1670 },
1213
1671
1214 descendants: function(element) {
1672 descendants: function(element) {
1215 - return $A($(element).getElementsByTagName('*'));
1673 + return $(element).getElementsBySelector("*");
1674 + },
1675 +
1676 + firstDescendant: function(element) {
1677 + element = $(element).firstChild;
1678 + while (element && element.nodeType != 1) element = element.nextSibling;
1679 + return $(element);
1216 },
1680 },
1217
1681
1218 immediateDescendants: function(element) {
1682 immediateDescendants: function(element) {
@@ -1236,48 +1700,96
1236 },
1700 },
1237
1701
1238 match: function(element, selector) {
1702 match: function(element, selector) {
1239 - if (typeof selector == 'string')
1703 + if (Object.isString(selector))
1240 selector = new Selector(selector);
1704 selector = new Selector(selector);
1241 return selector.match($(element));
1705 return selector.match($(element));
1242 },
1706 },
1243
1707
1244 up: function(element, expression, index) {
1708 up: function(element, expression, index) {
1245 - return Selector.findElement($(element).ancestors(), expression, index);
1709 + element = $(element);
1710 + if (arguments.length == 1) return $(element.parentNode);
1711 + var ancestors = element.ancestors();
1712 + return expression ? Selector.findElement(ancestors, expression, index) :
1713 + ancestors[index || 0];
1246 },
1714 },
1247
1715
1248 down: function(element, expression, index) {
1716 down: function(element, expression, index) {
1249 - return Selector.findElement($(element).descendants(), expression, index);
1717 + element = $(element);
1718 + if (arguments.length == 1) return element.firstDescendant();
1719 + var descendants = element.descendants();
1720 + return expression ? Selector.findElement(descendants, expression, index) :
1721 + descendants[index || 0];
1250 },
1722 },
1251
1723
1252 previous: function(element, expression, index) {
1724 previous: function(element, expression, index) {
1253 - return Selector.findElement($(element).previousSiblings(), expression, index);
1725 + element = $(element);
1726 + if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
1727 + var previousSiblings = element.previousSiblings();
1728 + return expression ? Selector.findElement(previousSiblings, expression, index) :
1729 + previousSiblings[index || 0];
1254 },
1730 },
1255
1731
1256 next: function(element, expression, index) {
1732 next: function(element, expression, index) {
1257 - return Selector.findElement($(element).nextSiblings(), expression, index);
1733 + element = $(element);
1258 - },
1734 + if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
1259 -
1735 + var nextSiblings = element.nextSiblings();
1260 - getElementsBySelector: function() {
1736 + return expression ? Selector.findElement(nextSiblings, expression, index) :
1737 + nextSiblings[index || 0];
1738 + },
1739 +
1740 + select: function() {
1261 var args = $A(arguments), element = $(args.shift());
1741 var args = $A(arguments), element = $(args.shift());
1262 return Selector.findChildElements(element, args);
1742 return Selector.findChildElements(element, args);
1263 },
1743 },
1264
1744
1265 - getElementsByClassName: function(element, className) {
1745 + adjacent: function() {
1266 - return document.getElementsByClassName(className, element);
1746 + var args = $A(arguments), element = $(args.shift());
1747 + return Selector.findChildElements(element.parentNode, args).without(element);
1748 + },
1749 +
1750 + identify: function(element) {
1751 + element = $(element);
1752 + var id = element.readAttribute('id'), self = arguments.callee;
1753 + if (id) return id;
1754 + do { id = 'anonymous_element_' + self.counter++ } while ($(id));
1755 + element.writeAttribute('id', id);
1756 + return id;
1267 },
1757 },
1268
1758
1269 readAttribute: function(element, name) {
1759 readAttribute: function(element, name) {
1270 element = $(element);
1760 element = $(element);
1271 - if (document.all && !window.opera) {
1761 + if (Prototype.Browser.IE) {
1272 - var t = Element._attributeTranslations;
1762 + var t = Element._attributeTranslations.read;
1273 if (t.values[name]) return t.values[name](element, name);
1763 if (t.values[name]) return t.values[name](element, name);
1274 - if (t.names[name]) name = t.names[name];
1764 + if (t.names[name]) name = t.names[name];
1275 - var attribute = element.attributes[name];
1765 + if (name.include(':')) {
1276 - if(attribute) return attribute.nodeValue;
1766 + return (!element.attributes || !element.attributes[name]) ? null :
1767 + element.attributes[name].value;
1768 + }
1277 }
1769 }
1278 return element.getAttribute(name);
1770 return element.getAttribute(name);
1279 },
1771 },
1280
1772
1773 + writeAttribute: function(element, name, value) {
1774 + element = $(element);
1775 + var attributes = { }, t = Element._attributeTranslations.write;
1776 +
1777 + if (typeof name == 'object') attributes = name;
1778 + else attributes[name] = Object.isUndefined(value) ? true : value;
1779 +
1780 + for (var attr in attributes) {
1781 + name = t.names[attr] || attr;
1782 + value = attributes[attr];
1783 + if (t.values[attr]) name = t.values[attr](element, value);
1784 + if (value === false || value === null)
1785 + element.removeAttribute(name);
1786 + else if (value === true)
1787 + element.setAttribute(name, name);
1788 + else element.setAttribute(name, value);
1789 + }
1790 + return element;
1791 + },
1792 +
1281 getHeight: function(element) {
1793 getHeight: function(element) {
1282 return $(element).getDimensions().height;
1794 return $(element).getDimensions().height;
1283 },
1795 },
@@ -1293,39 +1805,28
1293 hasClassName: function(element, className) {
1805 hasClassName: function(element, className) {
1294 if (!(element = $(element))) return;
1806 if (!(element = $(element))) return;
1295 var elementClassName = element.className;
1807 var elementClassName = element.className;
1296 - if (elementClassName.length == 0) return false;
1808 + return (elementClassName.length > 0 && (elementClassName == className ||
1297 - if (elementClassName == className ||
1809 + new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
1298 - elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
1299 - return true;
1300 - return false;
1301 },
1810 },
1302
1811
1303 addClassName: function(element, className) {
1812 addClassName: function(element, className) {
1304 if (!(element = $(element))) return;
1813 if (!(element = $(element))) return;
1305 - Element.classNames(element).add(className);
1814 + if (!element.hasClassName(className))
1815 + element.className += (element.className ? ' ' : '') + className;
1306 return element;
1816 return element;
1307 },
1817 },
1308
1818
1309 removeClassName: function(element, className) {
1819 removeClassName: function(element, className) {
1310 if (!(element = $(element))) return;
1820 if (!(element = $(element))) return;
1311 - Element.classNames(element).remove(className);
1821 + element.className = element.className.replace(
1822 + new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
1312 return element;
1823 return element;
1313 },
1824 },
1314
1825
1315 toggleClassName: function(element, className) {
1826 toggleClassName: function(element, className) {
1316 if (!(element = $(element))) return;
1827 if (!(element = $(element))) return;
1317 - Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
1828 + return element[element.hasClassName(className) ?
1318 - return element;
1829 + 'removeClassName' : 'addClassName'](className);
1319 - },
1320 -
1321 - observe: function() {
1322 - Event.observe.apply(Event, arguments);
1323 - return $A(arguments).first();
1324 - },
1325 -
1326 - stopObserving: function() {
1327 - Event.stopObserving.apply(Event, arguments);
1328 - return $A(arguments).first();
1329 },
1830 },
1330
1831
1331 // removes whitespace-only text node children
1832 // removes whitespace-only text node children
@@ -1342,74 +1843,76
1342 },
1843 },
1343
1844
1344 empty: function(element) {
1845 empty: function(element) {
1345 - return $(element).innerHTML.match(/^\s*$/);
1846 + return $(element).innerHTML.blank();
1346 },
1847 },
1347
1848
1348 descendantOf: function(element, ancestor) {
1849 descendantOf: function(element, ancestor) {
1349 element = $(element), ancestor = $(ancestor);
1850 element = $(element), ancestor = $(ancestor);
1851 + var originalAncestor = ancestor;
1852 +
1853 + if (element.compareDocumentPosition)
1854 + return (element.compareDocumentPosition(ancestor) & 8) === 8;
1855 +
1856 + if (element.sourceIndex && !Prototype.Browser.Opera) {
1857 + var e = element.sourceIndex, a = ancestor.sourceIndex,
1858 + nextAncestor = ancestor.nextSibling;
1859 + if (!nextAncestor) {
1860 + do { ancestor = ancestor.parentNode; }
1861 + while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);
1862 + }
1863 + if (nextAncestor) return (e > a && e < nextAncestor.sourceIndex);
1864 + }
1865 +
1350 while (element = element.parentNode)
1866 while (element = element.parentNode)
1351 - if (element == ancestor) return true;
1867 + if (element == originalAncestor) return true;
1352 return false;
1868 return false;
1353 },
1869 },
1354
1870
1355 scrollTo: function(element) {
1871 scrollTo: function(element) {
1356 element = $(element);
1872 element = $(element);
1357 - var pos = Position.cumulativeOffset(element);
1873 + var pos = element.cumulativeOffset();
1358 window.scrollTo(pos[0], pos[1]);
1874 window.scrollTo(pos[0], pos[1]);
1359 return element;
1875 return element;
1360 },
1876 },
1361
1877
1362 getStyle: function(element, style) {
1878 getStyle: function(element, style) {
1363 element = $(element);
1879 element = $(element);
1364 - if (['float','cssFloat'].include(style))
1880 + style = style == 'float' ? 'cssFloat' : style.camelize();
1365 - style = (typeof element.style.styleFloat != 'undefined' ? 'styleFloat' : 'cssFloat');
1366 - style = style.camelize();
1367 var value = element.style[style];
1881 var value = element.style[style];
1368 if (!value) {
1882 if (!value) {
1369 - if (document.defaultView && document.defaultView.getComputedStyle) {
1883 + var css = document.defaultView.getComputedStyle(element, null);
1370 - var css = document.defaultView.getComputedStyle(element, null);
1884 + value = css ? css[style] : null;
1371 - value = css ? css[style] : null;
1372 - } else if (element.currentStyle) {
1373 - value = element.currentStyle[style];
1374 - }
1375 }
1885 }
1376 -
1886 + if (style == 'opacity') return value ? parseFloat(value) : 1.0;
1377 - if((value == 'auto') && ['width','height'].include(style) && (element.getStyle('display') != 'none'))
1378 - value = element['offset'+style.capitalize()] + 'px';
1379 -
1380 - if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
1381 - if (Element.getStyle(element, 'position') == 'static') value = 'auto';
1382 - if(style == 'opacity') {
1383 - if(value) return parseFloat(value);
1384 - if(value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
1385 - if(value[1]) return parseFloat(value[1]) / 100;
1386 - return 1.0;
1387 - }
1388 return value == 'auto' ? null : value;
1887 return value == 'auto' ? null : value;
1389 },
1888 },
1390
1889
1391 - setStyle: function(element, style) {
1890 + getOpacity: function(element) {
1891 + return $(element).getStyle('opacity');
1892 + },
1893 +
1894 + setStyle: function(element, styles) {
1392 element = $(element);
1895 element = $(element);
1393 - for (var name in style) {
1896 + var elementStyle = element.style, match;
1394 - var value = style[name];
1897 + if (Object.isString(styles)) {
1395 - if(name == 'opacity') {
1898 + element.style.cssText += ';' + styles;
1396 - if (value == 1) {
1899 + return styles.include('opacity') ?
1397 - value = (/Gecko/.test(navigator.userAgent) &&
1900 + element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
1398 - !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : 1.0;
1399 - if(/MSIE/.test(navigator.userAgent) && !window.opera)
1400 - element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
1401 - } else if(value == '') {
1402 - if(/MSIE/.test(navigator.userAgent) && !window.opera)
1403 - element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
1404 - } else {
1405 - if(value < 0.00001) value = 0;
1406 - if(/MSIE/.test(navigator.userAgent) && !window.opera)
1407 - element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') +
1408 - 'alpha(opacity='+value*100+')';
1409 - }
1410 - } else if(['float','cssFloat'].include(name)) name = (typeof element.style.styleFloat != 'undefined') ? 'styleFloat' : 'cssFloat';
1411 - element.style[name.camelize()] = value;
1412 }
1901 }
1902 + for (var property in styles)
1903 + if (property == 'opacity') element.setOpacity(styles[property]);
1904 + else
1905 + elementStyle[(property == 'float' || property == 'cssFloat') ?
1906 + (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
1907 + property] = styles[property];
1908 +
1909 + return element;
1910 + },
1911 +
1912 + setOpacity: function(element, value) {
1913 + element = $(element);
1914 + element.style.opacity = (value == 1 || value === '') ? '' :
1915 + (value < 0.00001) ? 0 : value;
1413 return element;
1916 return element;
1414 },
1917 },
1415
1918
@@ -1468,8 +1971,8
1468 makeClipping: function(element) {
1971 makeClipping: function(element) {
1469 element = $(element);
1972 element = $(element);
1470 if (element._overflow) return element;
1973 if (element._overflow) return element;
1471 - element._overflow = element.style.overflow || 'auto';
1974 + element._overflow = Element.getStyle(element, 'overflow') || 'auto';
1472 - if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
1975 + if (element._overflow !== 'hidden')
1473 element.style.overflow = 'hidden';
1976 element.style.overflow = 'hidden';
1474 return element;
1977 return element;
1475 },
1978 },
@@ -1480,232 +1983,2207
1480 element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
1983 element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
1481 element._overflow = null;
1984 element._overflow = null;
1482 return element;
1985 return element;
1986 + },
1987 +
1988 + cumulativeOffset: function(element) {
1989 + var valueT = 0, valueL = 0;
1990 + do {
1991 + valueT += element.offsetTop || 0;
1992 + valueL += element.offsetLeft || 0;
1993 + element = element.offsetParent;
1994 + } while (element);
1995 + return Element._returnOffset(valueL, valueT);
1996 + },
1997 +
1998 + positionedOffset: function(element) {
1999 + var valueT = 0, valueL = 0;
2000 + do {
2001 + valueT += element.offsetTop || 0;
2002 + valueL += element.offsetLeft || 0;
2003 + element = element.offsetParent;
2004 + if (element) {
2005 + if (element.tagName == 'BODY') break;
2006 + var p = Element.getStyle(element, 'position');
2007 + if (p == 'relative' || p == 'absolute') break;
2008 + }
2009 + } while (element);
2010 + return Element._returnOffset(valueL, valueT);
2011 + },
2012 +
2013 + absolutize: function(element) {
2014 + element = $(element);
2015 + if (element.getStyle('position') == 'absolute') return;
2016 + // Position.prepare(); // To be done manually by Scripty when it needs it.
2017 +
2018 + var offsets = element.positionedOffset();
2019 + var top = offsets[1];
2020 + var left = offsets[0];
2021 + var width = element.clientWidth;
2022 + var height = element.clientHeight;
2023 +
2024 + element._originalLeft = left - parseFloat(element.style.left || 0);
2025 + element._originalTop = top - parseFloat(element.style.top || 0);
2026 + element._originalWidth = element.style.width;
2027 + element._originalHeight = element.style.height;
2028 +
2029 + element.style.position = 'absolute';
2030 + element.style.top = top + 'px';
2031 + element.style.left = left + 'px';
2032 + element.style.width = width + 'px';
2033 + element.style.height = height + 'px';
2034 + return element;
2035 + },
2036 +
2037 + relativize: function(element) {
2038 + element = $(element);
2039 + if (element.getStyle('position') == 'relative') return;
2040 + // Position.prepare(); // To be done manually by Scripty when it needs it.
2041 +
2042 + element.style.position = 'relative';
2043 + var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
2044 + var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
2045 +
2046 + element.style.top = top + 'px';
2047 + element.style.left = left + 'px';
2048 + element.style.height = element._originalHeight;
2049 + element.style.width = element._originalWidth;
2050 + return element;
2051 + },
2052 +
2053 + cumulativeScrollOffset: function(element) {
2054 + var valueT = 0, valueL = 0;
2055 + do {
2056 + valueT += element.scrollTop || 0;
2057 + valueL += element.scrollLeft || 0;
2058 + element = element.parentNode;
2059 + } while (element);
2060 + return Element._returnOffset(valueL, valueT);
2061 + },
2062 +
2063 + getOffsetParent: function(element) {
2064 + if (element.offsetParent) return $(element.offsetParent);
2065 + if (element == document.body) return $(element);
2066 +
2067 + while ((element = element.parentNode) && element != document.body)
2068 + if (Element.getStyle(element, 'position') != 'static')
2069 + return $(element);
2070 +
2071 + return $(document.body);
2072 + },
2073 +
2074 + viewportOffset: function(forElement) {
2075 + var valueT = 0, valueL = 0;
2076 +
2077 + var element = forElement;
2078 + do {
2079 + valueT += element.offsetTop || 0;
2080 + valueL += element.offsetLeft || 0;
2081 +
2082 + // Safari fix
2083 + if (element.offsetParent == document.body &&
2084 + Element.getStyle(element, 'position') == 'absolute') break;
2085 +
2086 + } while (element = element.offsetParent);
2087 +
2088 + element = forElement;
2089 + do {
2090 + if (!Prototype.Browser.Opera || element.tagName == 'BODY') {
2091 + valueT -= element.scrollTop || 0;
2092 + valueL -= element.scrollLeft || 0;
2093 + }
2094 + } while (element = element.parentNode);
2095 +
2096 + return Element._returnOffset(valueL, valueT);
2097 + },
2098 +
2099 + clonePosition: function(element, source) {
2100 + var options = Object.extend({
2101 + setLeft: true,
2102 + setTop: true,
2103 + setWidth: true,
2104 + setHeight: true,
2105 + offsetTop: 0,
2106 + offsetLeft: 0
2107 + }, arguments[2] || { });
2108 +
2109 + // find page position of source
2110 + source = $(source);
2111 + var p = source.viewportOffset();
2112 +
2113 + // find coordinate system to use
2114 + element = $(element);
2115 + var delta = [0, 0];
2116 + var parent = null;
2117 + // delta [0,0] will do fine with position: fixed elements,
2118 + // position:absolute needs offsetParent deltas
2119 + if (Element.getStyle(element, 'position') == 'absolute') {
2120 + parent = element.getOffsetParent();
2121 + delta = parent.viewportOffset();
2122 + }
2123 +
2124 + // correct by body offsets (fixes Safari)
2125 + if (parent == document.body) {
2126 + delta[0] -= document.body.offsetLeft;
2127 + delta[1] -= document.body.offsetTop;
2128 + }
2129 +
2130 + // set position
2131 + if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
2132 + if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
2133 + if (options.setWidth) element.style.width = source.offsetWidth + 'px';
2134 + if (options.setHeight) element.style.height = source.offsetHeight + 'px';
2135 + return element;
2136 + }
2137 + };
2138 +
2139 + Element.Methods.identify.counter = 1;
2140 +
2141 + Object.extend(Element.Methods, {
2142 + getElementsBySelector: Element.Methods.select,
2143 + childElements: Element.Methods.immediateDescendants
2144 + });
2145 +
2146 + Element._attributeTranslations = {
2147 + write: {
2148 + names: {
2149 + className: 'class',
2150 + htmlFor: 'for'
2151 + },
2152 + values: { }
1483 }
2153 }
1484 };
2154 };
1485
2155
1486 - Object.extend(Element.Methods, {childOf: Element.Methods.descendantOf});
2156 +
1487 -
2157 + if (!document.createRange || Prototype.Browser.Opera) {
1488 - Element._attributeTranslations = {};
2158 + Element.Methods.insert = function(element, insertions) {
1489 -
2159 + element = $(element);
1490 - Element._attributeTranslations.names = {
2160 +
1491 - colspan: "colSpan",
2161 + if (Object.isString(insertions) || Object.isNumber(insertions) ||
1492 - rowspan: "rowSpan",
2162 + Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
1493 - valign: "vAlign",
2163 + insertions = { bottom: insertions };
1494 - datetime: "dateTime",
2164 +
1495 - accesskey: "accessKey",
2165 + var t = Element._insertionTranslations, content, position, pos, tagName;
1496 - tabindex: "tabIndex",
2166 +
1497 - enctype: "encType",
2167 + for (position in insertions) {
1498 - maxlength: "maxLength",
2168 + content = insertions[position];
1499 - readonly: "readOnly",
2169 + position = position.toLowerCase();
1500 - longdesc: "longDesc"
2170 + pos = t[position];
2171 +
2172 + if (content && content.toElement) content = content.toElement();
2173 + if (Object.isElement(content)) {
2174 + pos.insert(element, content);
2175 + continue;
2176 + }
2177 +
2178 + content = Object.toHTML(content);
2179 + tagName = ((position == 'before' || position == 'after')
2180 + ? element.parentNode : element).tagName.toUpperCase();
2181 +
2182 + if (t.tags[tagName]) {
2183 + var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
2184 + if (position == 'top' || position == 'after') fragments.reverse();
2185 + fragments.each(pos.insert.curry(element));
2186 + }
2187 + else element.insertAdjacentHTML(pos.adjacency, content.stripScripts());
2188 +
2189 + content.evalScripts.bind(content).defer();
2190 + }
2191 +
2192 + return element;
2193 + };
2194 + }
2195 +
2196 + if (Prototype.Browser.Opera) {
2197 + Element.Methods.getStyle = Element.Methods.getStyle.wrap(
2198 + function(proceed, element, style) {
2199 + switch (style) {
2200 + case 'left': case 'top': case 'right': case 'bottom':
2201 + if (proceed(element, 'position') === 'static') return null;
2202 + case 'height': case 'width':
2203 + // returns '0px' for hidden elements; we want it to return null
2204 + if (!Element.visible(element)) return null;
2205 +
2206 + // returns the border-box dimensions rather than the content-box
2207 + // dimensions, so we subtract padding and borders from the value
2208 + var dim = parseInt(proceed(element, style), 10);
2209 +
2210 + if (dim !== element['offset' + style.capitalize()])
2211 + return dim + 'px';
2212 +
2213 + var properties;
2214 + if (style === 'height') {
2215 + properties = ['border-top-width', 'padding-top',
2216 + 'padding-bottom', 'border-bottom-width'];
2217 + }
2218 + else {
2219 + properties = ['border-left-width', 'padding-left',
2220 + 'padding-right', 'border-right-width'];
2221 + }
2222 + return properties.inject(dim, function(memo, property) {
2223 + var val = proceed(element, property);
2224 + return val === null ? memo : memo - parseInt(val, 10);
2225 + }) + 'px';
2226 + default: return proceed(element, style);
2227 + }
2228 + }
2229 + );
2230 +
2231 + Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
2232 + function(proceed, element, attribute) {
2233 + if (attribute === 'title') return element.title;
2234 + return proceed(element, attribute);
2235 + }
2236 + );
2237 + }
2238 +
2239 + else if (Prototype.Browser.IE) {
2240 + $w('positionedOffset getOffsetParent viewportOffset').each(function(method) {
2241 + Element.Methods[method] = Element.Methods[method].wrap(
2242 + function(proceed, element) {
2243 + element = $(element);
2244 + var position = element.getStyle('position');
2245 + if (position != 'static') return proceed(element);
2246 + element.setStyle({ position: 'relative' });
2247 + var value = proceed(element);
2248 + element.setStyle({ position: position });
2249 + return value;
2250 + }
2251 + );
2252 + });
2253 +
2254 + Element.Methods.getStyle = function(element, style) {
2255 + element = $(element);
2256 + style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
2257 + var value = element.style[style];
2258 + if (!value && element.currentStyle) value = element.currentStyle[style];
2259 +
2260 + if (style == 'opacity') {
2261 + if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
2262 + if (value[1]) return parseFloat(value[1]) / 100;
2263 + return 1.0;
2264 + }
2265 +
2266 + if (value == 'auto') {
2267 + if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
2268 + return element['offset' + style.capitalize()] + 'px';
2269 + return null;
2270 + }
2271 + return value;
2272 + };
2273 +
2274 + Element.Methods.setOpacity = function(element, value) {
2275 + function stripAlpha(filter){
2276 + return filter.replace(/alpha\([^\)]*\)/gi,'');
2277 + }
2278 + element = $(element);
2279 + var currentStyle = element.currentStyle;
2280 + if ((currentStyle && !currentStyle.hasLayout) ||
2281 + (!currentStyle && element.style.zoom == 'normal'))
2282 + element.style.zoom = 1;
2283 +
2284 + var filter = element.getStyle('filter'), style = element.style;
2285 + if (value == 1 || value === '') {
2286 + (filter = stripAlpha(filter)) ?
2287 + style.filter = filter : style.removeAttribute('filter');
2288 + return element;
2289 + } else if (value < 0.00001) value = 0;
2290 + style.filter = stripAlpha(filter) +
2291 + 'alpha(opacity=' + (value * 100) + ')';
2292 + return element;
2293 + };
2294 +
2295 + Element._attributeTranslations = {
2296 + read: {
2297 + names: {
2298 + 'class': 'className',
2299 + 'for': 'htmlFor'
2300 + },
2301 + values: {
2302 + _getAttr: function(element, attribute) {
2303 + return element.getAttribute(attribute, 2);
2304 + },
2305 + _getAttrNode: function(element, attribute) {
2306 + var node = element.getAttributeNode(attribute);
2307 + return node ? node.value : "";
2308 + },
2309 + _getEv: function(element, attribute) {
2310 + attribute = element.getAttribute(attribute);
2311 + return attribute ? attribute.toString().slice(23, -2) : null;
2312 + },
2313 + _flag: function(element, attribute) {
2314 + return $(element).hasAttribute(attribute) ? attribute : null;
2315 + },
2316 + style: function(element) {
2317 + return element.style.cssText.toLowerCase();
2318 + },
2319 + title: function(element) {
2320 + return element.title;
2321 + }
2322 + }
2323 + }
2324 + };
2325 +
2326 + Element._attributeTranslations.write = {
2327 + names: Object.clone(Element._attributeTranslations.read.names),
2328 + values: {
2329 + checked: function(element, value) {
2330 + element.checked = !!value;
2331 + },
2332 +
2333 + style: function(element, value) {
2334 + element.style.cssText = value ? value : '';
2335 + }
2336 + }
2337 + };
2338 +
2339 + Element._attributeTranslations.has = {};
2340 +
2341 + $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
2342 + 'encType maxLength readOnly longDesc').each(function(attr) {
2343 + Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
2344 + Element._attributeTranslations.has[attr.toLowerCase()] = attr;
2345 + });
2346 +
2347 + (function(v) {
2348 + Object.extend(v, {
2349 + href: v._getAttr,
2350 + src: v._getAttr,
2351 + type: v._getAttr,
2352 + action: v._getAttrNode,
2353 + disabled: v._flag,
2354 + checked: v._flag,
2355 + readonly: v._flag,
2356 + multiple: v._flag,
2357 + onload: v._getEv,
2358 + onunload: v._getEv,
2359 + onclick: v._getEv,
2360 + ondblclick: v._getEv,
2361 + onmousedown: v._getEv,
2362 + onmouseup: v._getEv,
2363 + onmouseover: v._getEv,
2364 + onmousemove: v._getEv,
2365 + onmouseout: v._getEv,
2366 + onfocus: v._getEv,
2367 + onblur: v._getEv,
2368 + onkeypress: v._getEv,
2369 + onkeydown: v._getEv,
2370 + onkeyup: v._getEv,
2371 + onsubmit: v._getEv,
2372 + onreset: v._getEv,
2373 + onselect: v._getEv,
2374 + onchange: v._getEv
2375 + });
2376 + })(Element._attributeTranslations.read.values);
2377 + }
2378 +
2379 + else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
2380 + Element.Methods.setOpacity = function(element, value) {
2381 + element = $(element);
2382 + element.style.opacity = (value == 1) ? 0.999999 :
2383 + (value === '') ? '' : (value < 0.00001) ? 0 : value;
2384 + return element;
2385 + };
2386 + }
2387 +
2388 + else if (Prototype.Browser.WebKit) {
2389 + Element.Methods.setOpacity = function(element, value) {
2390 + element = $(element);
2391 + element.style.opacity = (value == 1 || value === '') ? '' :
2392 + (value < 0.00001) ? 0 : value;
2393 +
2394 + if (value == 1)
2395 + if(element.tagName == 'IMG' && element.width) {
2396 + element.width++; element.width--;
2397 + } else try {
2398 + var n = document.createTextNode(' ');
2399 + element.appendChild(n);
2400 + element.removeChild(n);
2401 + } catch (e) { }
2402 +
2403 + return element;
2404 + };
2405 +
2406 + // Safari returns margins on body which is incorrect if the child is absolutely
2407 + // positioned. For performance reasons, redefine Element#cumulativeOffset for
2408 + // KHTML/WebKit only.
2409 + Element.Methods.cumulativeOffset = function(element) {
2410 + var valueT = 0, valueL = 0;
2411 + do {
2412 + valueT += element.offsetTop || 0;
2413 + valueL += element.offsetLeft || 0;
2414 + if (element.offsetParent == document.body)
2415 + if (Element.getStyle(element, 'position') == 'absolute') break;
2416 +
2417 + element = element.offsetParent;
2418 + } while (element);
2419 +
2420 + return Element._returnOffset(valueL, valueT);
2421 + };
2422 + }
2423 +
2424 + if (Prototype.Browser.IE || Prototype.Browser.Opera) {
2425 + // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements
2426 + Element.Methods.update = function(element, content) {
2427 + element = $(element);
2428 +
2429 + if (content && content.toElement) content = content.toElement();
2430 + if (Object.isElement(content)) return element.update().insert(content);
2431 +
2432 + content = Object.toHTML(content);
2433 + var tagName = element.tagName.toUpperCase();
2434 +
2435 + if (tagName in Element._insertionTranslations.tags) {
2436 + $A(element.childNodes).each(function(node) { element.removeChild(node) });
2437 + Element._getContentFromAnonymousElement(tagName, content.stripScripts())
2438 + .each(function(node) { element.appendChild(node) });
2439 + }
2440 + else element.innerHTML = content.stripScripts();
2441 +
2442 + content.evalScripts.bind(content).defer();
2443 + return element;
2444 + };
2445 + }
2446 +
2447 + if (document.createElement('div').outerHTML) {
2448 + Element.Methods.replace = function(element, content) {
2449 + element = $(element);
2450 +
2451 + if (content && content.toElement) content = content.toElement();
2452 + if (Object.isElement(content)) {
2453 + element.parentNode.replaceChild(content, element);
2454 + return element;
2455 + }
2456 +
2457 + content = Object.toHTML(content);
2458 + var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
2459 +
2460 + if (Element._insertionTranslations.tags[tagName]) {
2461 + var nextSibling = element.next();
2462 + var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
2463 + parent.removeChild(element);
2464 + if (nextSibling)
2465 + fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
2466 + else
2467 + fragments.each(function(node) { parent.appendChild(node) });
2468 + }
2469 + else element.outerHTML = content.stripScripts();
2470 +
2471 + content.evalScripts.bind(content).defer();
2472 + return element;
2473 + };
2474 + }
2475 +
2476 + Element._returnOffset = function(l, t) {
2477 + var result = [l, t];
2478 + result.left = l;
2479 + result.top = t;
2480 + return result;
1501 };
2481 };
1502
2482
1503 - Element._attributeTranslations.values = {
2483 + Element._getContentFromAnonymousElement = function(tagName, html) {
1504 - _getAttr: function(element, attribute) {
2484 + var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
1505 - return element.getAttribute(attribute, 2);
2485 + div.innerHTML = t[0] + html + t[1];
1506 - },
2486 + t[2].times(function() { div = div.firstChild });
1507 -
2487 + return $A(div.childNodes);
1508 - _flag: function(element, attribute) {
2488 + };
1509 - return $(element).hasAttribute(attribute) ? attribute : null;
2489 +
1510 - },
2490 + Element._insertionTranslations = {
1511 -
2491 + before: {
1512 - style: function(element) {
2492 + adjacency: 'beforeBegin',
1513 - return element.style.cssText.toLowerCase();
2493 + insert: function(element, node) {
1514 - },
2494 + element.parentNode.insertBefore(node, element);
1515 -
2495 + },
1516 - title: function(element) {
2496 + initializeRange: function(element, range) {
1517 - var node = element.getAttributeNode('title');
2497 + range.setStartBefore(element);
1518 - return node.specified ? node.nodeValue : null;
2498 + }
2499 + },
2500 + top: {
2501 + adjacency: 'afterBegin',
2502 + insert: function(element, node) {
2503 + element.insertBefore(node, element.firstChild);
2504 + },
2505 + initializeRange: function(element, range) {
2506 + range.selectNodeContents(element);
2507 + range.collapse(true);
2508 + }
2509 + },
2510 + bottom: {
2511 + adjacency: 'beforeEnd',
2512 + insert: function(element, node) {
2513 + element.appendChild(node);
2514 + }
2515 + },
2516 + after: {
2517 + adjacency: 'afterEnd',
2518 + insert: function(element, node) {
2519 + element.parentNode.insertBefore(node, element.nextSibling);
2520 + },
2521 + initializeRange: function(element, range) {
2522 + range.setStartAfter(element);
2523 + }
2524 + },
2525 + tags: {
2526 + TABLE: ['<table>', '</table>', 1],
2527 + TBODY: ['<table><tbody>', '</tbody></table>', 2],
2528 + TR: ['<table><tbody><tr>', '</tr></tbody></table>', 3],
2529 + TD: ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
2530 + SELECT: ['<select>', '</select>', 1]
1519 }
2531 }
1520 };
2532 };
1521
2533
1522 - Object.extend(Element._attributeTranslations.values, {
2534 + (function() {
1523 - href: Element._attributeTranslations.values._getAttr,
2535 + this.bottom.initializeRange = this.top.initializeRange;
1524 - src: Element._attributeTranslations.values._getAttr,
2536 + Object.extend(this.tags, {
1525 - disabled: Element._attributeTranslations.values._flag,
2537 + THEAD: this.tags.TBODY,
1526 - checked: Element._attributeTranslations.values._flag,
2538 + TFOOT: this.tags.TBODY,
1527 - readonly: Element._attributeTranslations.values._flag,
2539 + TH: this.tags.TD
1528 - multiple: Element._attributeTranslations.values._flag
2540 + });
1529 - });
2541 + }).call(Element._insertionTranslations);
1530
2542
1531 Element.Methods.Simulated = {
2543 Element.Methods.Simulated = {
1532 hasAttribute: function(element, attribute) {
2544 hasAttribute: function(element, attribute) {
1533 - var t = Element._attributeTranslations;
2545 + attribute = Element._attributeTranslations.has[attribute] || attribute;
1534 - attribute = t.names[attribute] || attribute;
2546 + var node = $(element).getAttributeNode(attribute);
1535 - return $(element).getAttributeNode(attribute).specified;
2547 + return node && node.specified;
1536 }
2548 }
1537 };
2549 };
1538
2550
1539 - // IE is missing .innerHTML support for TABLE-related elements
2551 + Element.Methods.ByTag = { };
1540 - if (document.all && !window.opera){
1541 - Element.Methods.update = function(element, html) {
1542 - element = $(element);
1543 - html = typeof html == 'undefined' ? '' : html.toString();
1544 - var tagName = element.tagName.toUpperCase();
1545 - if (['THEAD','TBODY','TR','TD'].include(tagName)) {
1546 - var div = document.createElement('div');
1547 - switch (tagName) {
1548 - case 'THEAD':
1549 - case 'TBODY':
1550 - div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>';
1551 - depth = 2;
1552 - break;
1553 - case 'TR':
1554 - div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>';
1555 - depth = 3;
1556 - break;
1557 - case 'TD':
1558 - div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>';
1559 - depth = 4;
1560 - }
1561 - $A(element.childNodes).each(function(node){
1562 - element.removeChild(node)
1563 - });
1564 - depth.times(function(){ div = div.firstChild });
1565 -
1566 - $A(div.childNodes).each(
1567 - function(node){ element.appendChild(node) });
1568 - } else {
1569 - element.innerHTML = html.stripScripts();
1570 - }
1571 - setTimeout(function() {html.evalScripts()}, 10);
1572 - return element;
1573 - }
1574 - };
1575
2552
1576 Object.extend(Element, Element.Methods);
2553 Object.extend(Element, Element.Methods);
1577
2554
1578 - var _nativeExtensions = false;
2555 + if (!Prototype.BrowserFeatures.ElementExtensions &&
1579 -
2556 + document.createElement('div').__proto__) {
1580 - if(/Konqueror|Safari|KHTML/.test(navigator.userAgent))
2557 + window.HTMLElement = { };
1581 - ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) {
2558 + window.HTMLElement.prototype = document.createElement('div').__proto__;
1582 - var className = 'HTML' + tag + 'Element';
2559 + Prototype.BrowserFeatures.ElementExtensions = true;
1583 - if(window[className]) return;
2560 + }
1584 - var klass = window[className] = {};
2561 +
1585 - klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__;
2562 + Element.extend = (function() {
2563 + if (Prototype.BrowserFeatures.SpecificElementExtensions)
2564 + return Prototype.K;
2565 +
2566 + var Methods = { }, ByTag = Element.Methods.ByTag;
2567 +
2568 + var extend = Object.extend(function(element) {
2569 + if (!element || element._extendedByPrototype ||
2570 + element.nodeType != 1 || element == window) return element;
2571 +
2572 + var methods = Object.clone(Methods),
2573 + tagName = element.tagName, property, value;
2574 +
2575 + // extend methods for specific tags
2576 + if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
2577 +
2578 + for (property in methods) {
2579 + value = methods[property];
2580 + if (Object.isFunction(value) && !(property in element))
2581 + element[property] = value.methodize();
2582 + }
2583 +
2584 + element._extendedByPrototype = Prototype.emptyFunction;
2585 + return element;
2586 +
2587 + }, {
2588 + refresh: function() {
2589 + // extend methods for all tags (Safari doesn't need this)
2590 + if (!Prototype.BrowserFeatures.ElementExtensions) {
2591 + Object.extend(Methods, Element.Methods);
2592 + Object.extend(Methods, Element.Methods.Simulated);
2593 + }
2594 + }
1586 });
2595 });
1587
2596
2597 + extend.refresh();
2598 + return extend;
2599 + })();
2600 +
2601 + Element.hasAttribute = function(element, attribute) {
2602 + if (element.hasAttribute) return element.hasAttribute(attribute);
2603 + return Element.Methods.Simulated.hasAttribute(element, attribute);
2604 + };
2605 +
1588 Element.addMethods = function(methods) {
2606 Element.addMethods = function(methods) {
1589 - Object.extend(Element.Methods, methods || {});
2607 + var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
2608 +
2609 + if (!methods) {
2610 + Object.extend(Form, Form.Methods);
2611 + Object.extend(Form.Element, Form.Element.Methods);
2612 + Object.extend(Element.Methods.ByTag, {
2613 + "FORM": Object.clone(Form.Methods),
2614 + "INPUT": Object.clone(Form.Element.Methods),
2615 + "SELECT": Object.clone(Form.Element.Methods),
2616 + "TEXTAREA": Object.clone(Form.Element.Methods)
2617 + });
2618 + }
2619 +
2620 + if (arguments.length == 2) {
2621 + var tagName = methods;
2622 + methods = arguments[1];
2623 + }
2624 +
2625 + if (!tagName) Object.extend(Element.Methods, methods || { });
2626 + else {
2627 + if (Object.isArray(tagName)) tagName.each(extend);
2628 + else extend(tagName);
2629 + }
2630 +
2631 + function extend(tagName) {
2632 + tagName = tagName.toUpperCase();
2633 + if (!Element.Methods.ByTag[tagName])
2634 + Element.Methods.ByTag[tagName] = { };
2635 + Object.extend(Element.Methods.ByTag[tagName], methods);
2636 + }
1590
2637
1591 function copy(methods, destination, onlyIfAbsent) {
2638 function copy(methods, destination, onlyIfAbsent) {
1592 onlyIfAbsent = onlyIfAbsent || false;
2639 onlyIfAbsent = onlyIfAbsent || false;
1593 - var cache = Element.extend.cache;
1594 for (var property in methods) {
2640 for (var property in methods) {
1595 var value = methods[property];
2641 var value = methods[property];
2642 + if (!Object.isFunction(value)) continue;
1596 if (!onlyIfAbsent || !(property in destination))
2643 if (!onlyIfAbsent || !(property in destination))
1597 - destination[property] = cache.findOrStore(value);
2644 + destination[property] = value.methodize();
1598 }
2645 }
1599 }
2646 }
1600
2647
1601 - if (typeof HTMLElement != 'undefined') {
2648 + function findDOMClass(tagName) {
2649 + var klass;
2650 + var trans = {
2651 + "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
2652 + "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
2653 + "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
2654 + "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
2655 + "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
2656 + "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
2657 + "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
2658 + "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
2659 + "FrameSet", "IFRAME": "IFrame"
2660 + };
2661 + if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
2662 + if (window[klass]) return window[klass];
2663 + klass = 'HTML' + tagName + 'Element';
2664 + if (window[klass]) return window[klass];
2665 + klass = 'HTML' + tagName.capitalize() + 'Element';
2666 + if (window[klass]) return window[klass];
2667 +
2668 + window[klass] = { };
2669 + window[klass].prototype = document.createElement(tagName).__proto__;
2670 + return window[klass];
2671 + }
2672 +
2673 + if (F.ElementExtensions) {
1602 copy(Element.Methods, HTMLElement.prototype);
2674 copy(Element.Methods, HTMLElement.prototype);
1603 copy(Element.Methods.Simulated, HTMLElement.prototype, true);
2675 copy(Element.Methods.Simulated, HTMLElement.prototype, true);
1604 - copy(Form.Methods, HTMLFormElement.prototype);
2676 + }
1605 - [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
2677 +
1606 - copy(Form.Element.Methods, klass.prototype);
2678 + if (F.SpecificElementExtensions) {
2679 + for (var tag in Element.Methods.ByTag) {
2680 + var klass = findDOMClass(tag);
2681 + if (Object.isUndefined(klass)) continue;
2682 + copy(T[tag], klass.prototype);
2683 + }
2684 + }
2685 +
2686 + Object.extend(Element, Element.Methods);
2687 + delete Element.ByTag;
2688 +
2689 + if (Element.extend.refresh) Element.extend.refresh();
2690 + Element.cache = { };
2691 + };
2692 +
2693 + document.viewport = {
2694 + getDimensions: function() {
2695 + var dimensions = { };
2696 + var B = Prototype.Browser;
2697 + $w('width height').each(function(d) {
2698 + var D = d.capitalize();
2699 + dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] :
2700 + (B.Opera) ? document.body['client' + D] : document.documentElement['client' + D];
1607 });
2701 });
1608 - _nativeExtensions = true;
2702 + return dimensions;
2703 + },
2704 +
2705 + getWidth: function() {
2706 + return this.getDimensions().width;
2707 + },
2708 +
2709 + getHeight: function() {
2710 + return this.getDimensions().height;
2711 + },
2712 +
2713 + getScrollOffsets: function() {
2714 + return Element._returnOffset(
2715 + window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
2716 + window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
2717 + }
2718 + };
2719 + /* Portions of the Selector class are derived from Jack Slocum’s DomQuery,
2720 + * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
2721 + * license. Please see http://www.yui-ext.com/ for more information. */
2722 +
2723 + var Selector = Class.create({
2724 + initialize: function(expression) {
2725 + this.expression = expression.strip();
2726 + this.compileMatcher();
2727 + },
2728 +
2729 + shouldUseXPath: function() {
2730 + if (!Prototype.BrowserFeatures.XPath) return false;
2731 +
2732 + var e = this.expression;
2733 +
2734 + // Safari 3 chokes on :*-of-type and :empty
2735 + if (Prototype.Browser.WebKit &&
2736 + (e.include("-of-type") || e.include(":empty")))
2737 + return false;
2738 +
2739 + // XPath can't do namespaced attributes, nor can it read
2740 + // the "checked" property from DOM nodes
2741 + if ((/(\[[\w-]*?:|:checked)/).test(this.expression))
2742 + return false;
2743 +
2744 + return true;
2745 + },
2746 +
2747 + compileMatcher: function() {
2748 + if (this.shouldUseXPath())
2749 + return this.compileXPathMatcher();
2750 +
2751 + var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
2752 + c = Selector.criteria, le, p, m;
2753 +
2754 + if (Selector._cache[e]) {
2755 + this.matcher = Selector._cache[e];
2756 + return;
2757 + }
2758 +
2759 + this.matcher = ["this.matcher = function(root) {",
2760 + "var r = root, h = Selector.handlers, c = false, n;"];
2761 +
2762 + while (e && le != e && (/\S/).test(e)) {
2763 + le = e;
2764 + for (var i in ps) {
2765 + p = ps[i];
2766 + if (m = e.match(p)) {
2767 + this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
2768 + new Template(c[i]).evaluate(m));
2769 + e = e.replace(m[0], '');
2770 + break;
2771 + }
2772 + }
2773 + }
2774 +
2775 + this.matcher.push("return h.unique(n);\n}");
2776 + eval(this.matcher.join('\n'));
2777 + Selector._cache[this.expression] = this.matcher;
2778 + },
2779 +
2780 + compileXPathMatcher: function() {
2781 + var e = this.expression, ps = Selector.patterns,
2782 + x = Selector.xpath, le, m;
2783 +
2784 + if (Selector._cache[e]) {
2785 + this.xpath = Selector._cache[e]; return;
2786 + }
2787 +
2788 + this.matcher = ['.//*'];
2789 + while (e && le != e && (/\S/).test(e)) {
2790 + le = e;
2791 + for (var i in ps) {
2792 + if (m = e.match(ps[i])) {
2793 + this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :
2794 + new Template(x[i]).evaluate(m));
2795 + e = e.replace(m[0], '');
2796 + break;
2797 + }
2798 + }
2799 + }
2800 +
2801 + this.xpath = this.matcher.join('');
2802 + Selector._cache[this.expression] = this.xpath;
2803 + },
2804 +
2805 + findElements: function(root) {
2806 + root = root || document;
2807 + if (this.xpath) return document._getElementsByXPath(this.xpath, root);
2808 + return this.matcher(root);
2809 + },
2810 +
2811 + match: function(element) {
2812 + this.tokens = [];
2813 +
2814 + var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
2815 + var le, p, m;
2816 +
2817 + while (e && le !== e && (/\S/).test(e)) {
2818 + le = e;
2819 + for (var i in ps) {
2820 + p = ps[i];
2821 + if (m = e.match(p)) {
2822 + // use the Selector.assertions methods unless the selector
2823 + // is too complex.
2824 + if (as[i]) {
2825 + this.tokens.push([i, Object.clone(m)]);
2826 + e = e.replace(m[0], '');
2827 + } else {
2828 + // reluctantly do a document-wide search
2829 + // and look for a match in the array
2830 + return this.findElements(document).include(element);
2831 + }
2832 + }
2833 + }
2834 + }
2835 +
2836 + var match = true, name, matches;
2837 + for (var i = 0, token; token = this.tokens[i]; i++) {
2838 + name = token[0], matches = token[1];
2839 + if (!Selector.assertions[name](element, matches)) {
2840 + match = false; break;
2841 + }
2842 + }
2843 +
2844 + return match;
2845 + },
2846 +
2847 + toString: function() {
2848 + return this.expression;
2849 + },
2850 +
2851 + inspect: function() {
2852 + return "#<Selector:" + this.expression.inspect() + ">";
1609 }
2853 }
1610 - }
2854 + });
1611 -
2855 +
1612 - var Toggle = new Object();
2856 + Object.extend(Selector, {
1613 - Toggle.display = Element.toggle;
2857 + _cache: { },
1614 -
2858 +
1615 - /*--------------------------------------------------------------------------*/
2859 + xpath: {
1616 -
2860 + descendant: "//*",
1617 - Abstract.Insertion = function(adjacency) {
2861 + child: "/*",
1618 - this.adjacency = adjacency;
2862 + adjacent: "/following-sibling::*[1]",
2863 + laterSibling: '/following-sibling::*',
2864 + tagName: function(m) {
2865 + if (m[1] == '*') return '';
2866 + return "[local-name()='" + m[1].toLowerCase() +
2867 + "' or local-name()='" + m[1].toUpperCase() + "']";
2868 + },
2869 + className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
2870 + id: "[@id='#{1}']",
2871 + attrPresence: function(m) {
2872 + m[1] = m[1].toLowerCase();
2873 + return new Template("[@#{1}]").evaluate(m);
2874 + },
2875 + attr: function(m) {
2876 + m[1] = m[1].toLowerCase();
2877 + m[3] = m[5] || m[6];
2878 + return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
2879 + },
2880 + pseudo: function(m) {
2881 + var h = Selector.xpath.pseudos[m[1]];
2882 + if (!h) return '';
2883 + if (Object.isFunction(h)) return h(m);
2884 + return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
2885 + },
2886 + operators: {
2887 + '=': "[@#{1}='#{3}']",
2888 + '!=': "[@#{1}!='#{3}']",
2889 + '^=': "[starts-with(@#{1}, '#{3}')]",
2890 + '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
2891 + '*=': "[contains(@#{1}, '#{3}')]",
2892 + '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
2893 + '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
2894 + },
2895 + pseudos: {
2896 + 'first-child': '[not(preceding-sibling::*)]',
2897 + 'last-child': '[not(following-sibling::*)]',
2898 + 'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
2899 + 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
2900 + 'checked': "[@checked]",
2901 + 'disabled': "[@disabled]",
2902 + 'enabled': "[not(@disabled)]",
2903 + 'not': function(m) {
2904 + var e = m[6], p = Selector.patterns,
2905 + x = Selector.xpath, le, v;
2906 +
2907 + var exclusion = [];
2908 + while (e && le != e && (/\S/).test(e)) {
2909 + le = e;
2910 + for (var i in p) {
2911 + if (m = e.match(p[i])) {
2912 + v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);
2913 + exclusion.push("(" + v.substring(1, v.length - 1) + ")");
2914 + e = e.replace(m[0], '');
2915 + break;
2916 + }
2917 + }
2918 + }
2919 + return "[not(" + exclusion.join(" and ") + ")]";
2920 + },
2921 + 'nth-child': function(m) {
2922 + return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
2923 + },
2924 + 'nth-last-child': function(m) {
2925 + return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
2926 + },
2927 + 'nth-of-type': function(m) {
2928 + return Selector.xpath.pseudos.nth("position() ", m);
2929 + },
2930 + 'nth-last-of-type': function(m) {
2931 + return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
2932 + },
2933 + 'first-of-type': function(m) {
2934 + m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
2935 + },
2936 + 'last-of-type': function(m) {
2937 + m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
2938 + },
2939 + 'only-of-type': function(m) {
2940 + var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
2941 + },
2942 + nth: function(fragment, m) {
2943 + var mm, formula = m[6], predicate;
2944 + if (formula == 'even') formula = '2n+0';
2945 + if (formula == 'odd') formula = '2n+1';
2946 + if (mm = formula.match(/^(\d+)$/)) // digit only
2947 + return '[' + fragment + "= " + mm[1] + ']';
2948 + if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
2949 + if (mm[1] == "-") mm[1] = -1;
2950 + var a = mm[1] ? Number(mm[1]) : 1;
2951 + var b = mm[2] ? Number(mm[2]) : 0;
2952 + predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
2953 + "((#{fragment} - #{b}) div #{a} >= 0)]";
2954 + return new Template(predicate).evaluate({
2955 + fragment: fragment, a: a, b: b });
2956 + }
2957 + }
2958 + }
2959 + },
2960 +
2961 + criteria: {
2962 + tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
2963 + className: 'n = h.className(n, r, "#{1}", c); c = false;',
2964 + id: 'n = h.id(n, r, "#{1}", c); c = false;',
2965 + attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
2966 + attr: function(m) {
2967 + m[3] = (m[5] || m[6]);
2968 + return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
2969 + },
2970 + pseudo: function(m) {
2971 + if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
2972 + return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
2973 + },
2974 + descendant: 'c = "descendant";',
2975 + child: 'c = "child";',
2976 + adjacent: 'c = "adjacent";',
2977 + laterSibling: 'c = "laterSibling";'
2978 + },
2979 +
2980 + patterns: {
2981 + // combinators must be listed first
2982 + // (and descendant needs to be last combinator)
2983 + laterSibling: /^\s*~\s*/,
2984 + child: /^\s*>\s*/,
2985 + adjacent: /^\s*\+\s*/,
2986 + descendant: /^\s/,
2987 +
2988 + // selectors follow
2989 + tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
2990 + id: /^#([\w\-\*]+)(\b|$)/,
2991 + className: /^\.([\w\-\*]+)(\b|$)/,
2992 + pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s)|(?=:))/,
2993 + attrPresence: /^\[([\w]+)\]/,
2994 + attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
2995 + },
2996 +
2997 + // for Selector.match and Element#match
2998 + assertions: {
2999 + tagName: function(element, matches) {
3000 + return matches[1].toUpperCase() == element.tagName.toUpperCase();
3001 + },
3002 +
3003 + className: function(element, matches) {
3004 + return Element.hasClassName(element, matches[1]);
3005 + },
3006 +
3007 + id: function(element, matches) {
3008 + return element.id === matches[1];
3009 + },
3010 +
3011 + attrPresence: function(element, matches) {
3012 + return Element.hasAttribute(element, matches[1]);
3013 + },
3014 +
3015 + attr: function(element, matches) {
3016 + var nodeValue = Element.readAttribute(element, matches[1]);
3017 + return Selector.operators[matches[2]](nodeValue, matches[3]);
3018 + }
3019 + },
3020 +
3021 + handlers: {
3022 + // UTILITY FUNCTIONS
3023 + // joins two collections
3024 + concat: function(a, b) {
3025 + for (var i = 0, node; node = b[i]; i++)
3026 + a.push(node);
3027 + return a;
3028 + },
3029 +
3030 + // marks an array of nodes for counting
3031 + mark: function(nodes) {
3032 + for (var i = 0, node; node = nodes[i]; i++)
3033 + node._counted = true;
3034 + return nodes;
3035 + },
3036 +
3037 + unmark: function(nodes) {
3038 + for (var i = 0, node; node = nodes[i]; i++)
3039 + node._counted = undefined;
3040 + return nodes;
3041 + },
3042 +
3043 + // mark each child node with its position (for nth calls)
3044 + // "ofType" flag indicates whether we're indexing for nth-of-type
3045 + // rather than nth-child
3046 + index: function(parentNode, reverse, ofType) {
3047 + parentNode._counted = true;
3048 + if (reverse) {
3049 + for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
3050 + var node = nodes[i];
3051 + if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
3052 + }
3053 + } else {
3054 + for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
3055 + if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
3056 + }
3057 + },
3058 +
3059 + // filters out duplicates and extends all nodes
3060 + unique: function(nodes) {
3061 + if (nodes.length == 0) return nodes;
3062 + var results = [], n;
3063 + for (var i = 0, l = nodes.length; i < l; i++)
3064 + if (!(n = nodes[i])._counted) {
3065 + n._counted = true;
3066 + results.push(Element.extend(n));
3067 + }
3068 + return Selector.handlers.unmark(results);
3069 + },
3070 +
3071 + // COMBINATOR FUNCTIONS
3072 + descendant: function(nodes) {
3073 + var h = Selector.handlers;
3074 + for (var i = 0, results = [], node; node = nodes[i]; i++)
3075 + h.concat(results, node.getElementsByTagName('*'));
3076 + return results;
3077 + },
3078 +
3079 + child: function(nodes) {
3080 + var h = Selector.handlers;
3081 + for (var i = 0, results = [], node; node = nodes[i]; i++) {
3082 + for (var j = 0, child; child = node.childNodes[j]; j++)
3083 + if (child.nodeType == 1 && child.tagName != '!') results.push(child);
3084 + }
3085 + return results;
3086 + },
3087 +
3088 + adjacent: function(nodes) {
3089 + for (var i = 0, results = [], node; node = nodes[i]; i++) {
3090 + var next = this.nextElementSibling(node);
3091 + if (next) results.push(next);
3092 + }
3093 + return results;
3094 + },
3095 +
3096 + laterSibling: function(nodes) {
3097 + var h = Selector.handlers;
3098 + for (var i = 0, results = [], node; node = nodes[i]; i++)
3099 + h.concat(results, Element.nextSiblings(node));
3100 + return results;
3101 + },
3102 +
3103 + nextElementSibling: function(node) {
3104 + while (node = node.nextSibling)
3105 + if (node.nodeType == 1) return node;
3106 + return null;
3107 + },
3108 +
3109 + previousElementSibling: function(node) {
3110 + while (node = node.previousSibling)
3111 + if (node.nodeType == 1) return node;
3112 + return null;
3113 + },
3114 +
3115 + // TOKEN FUNCTIONS
3116 + tagName: function(nodes, root, tagName, combinator) {
3117 + tagName = tagName.toUpperCase();
3118 + var results = [], h = Selector.handlers;
3119 + if (nodes) {
3120 + if (combinator) {
3121 + // fastlane for ordinary descendant combinators
3122 + if (combinator == "descendant") {
3123 + for (var i = 0, node; node = nodes[i]; i++)
3124 + h.concat(results, node.getElementsByTagName(tagName));
3125 + return results;
3126 + } else nodes = this[combinator](nodes);
3127 + if (tagName == "*") return nodes;
3128 + }
3129 + for (var i = 0, node; node = nodes[i]; i++)
3130 + if (node.tagName.toUpperCase() == tagName) results.push(node);
3131 + return results;
3132 + } else return root.getElementsByTagName(tagName);
3133 + },
3134 +
3135 + id: function(nodes, root, id, combinator) {
3136 + var targetNode = $(id), h = Selector.handlers;
3137 + if (!targetNode) return [];
3138 + if (!nodes && root == document) return [targetNode];
3139 + if (nodes) {
3140 + if (combinator) {
3141 + if (combinator == 'child') {
3142 + for (var i = 0, node; node = nodes[i]; i++)
3143 + if (targetNode.parentNode == node) return [targetNode];
3144 + } else if (combinator == 'descendant') {
3145 + for (var i = 0, node; node = nodes[i]; i++)
3146 + if (Element.descendantOf(targetNode, node)) return [targetNode];
3147 + } else if (combinator == 'adjacent') {
3148 + for (var i = 0, node; node = nodes[i]; i++)
3149 + if (Selector.handlers.previousElementSibling(targetNode) == node)
3150 + return [targetNode];
3151 + } else nodes = h[combinator](nodes);
3152 + }
3153 + for (var i = 0, node; node = nodes[i]; i++)
3154 + if (node == targetNode) return [targetNode];
3155 + return [];
3156 + }
3157 + return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
3158 + },
3159 +
3160 + className: function(nodes, root, className, combinator) {
3161 + if (nodes && combinator) nodes = this[combinator](nodes);
3162 + return Selector.handlers.byClassName(nodes, root, className);
3163 + },
3164 +
3165 + byClassName: function(nodes, root, className) {
3166 + if (!nodes) nodes = Selector.handlers.descendant([root]);
3167 + var needle = ' ' + className + ' ';
3168 + for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
3169 + nodeClassName = node.className;
3170 + if (nodeClassName.length == 0) continue;
3171 + if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
3172 + results.push(node);
3173 + }
3174 + return results;
3175 + },
3176 +
3177 + attrPresence: function(nodes, root, attr) {
3178 + if (!nodes) nodes = root.getElementsByTagName("*");
3179 + var results = [];
3180 + for (var i = 0, node; node = nodes[i]; i++)
3181 + if (Element.hasAttribute(node, attr)) results.push(node);
3182 + return results;
3183 + },
3184 +
3185 + attr: function(nodes, root, attr, value, operator) {
3186 + if (!nodes) nodes = root.getElementsByTagName("*");
3187 + var handler = Selector.operators[operator], results = [];
3188 + for (var i = 0, node; node = nodes[i]; i++) {
3189 + var nodeValue = Element.readAttribute(node, attr);
3190 + if (nodeValue === null) continue;
3191 + if (handler(nodeValue, value)) results.push(node);
3192 + }
3193 + return results;
3194 + },
3195 +
3196 + pseudo: function(nodes, name, value, root, combinator) {
3197 + if (nodes && combinator) nodes = this[combinator](nodes);
3198 + if (!nodes) nodes = root.getElementsByTagName("*");
3199 + return Selector.pseudos[name](nodes, value, root);
3200 + }
3201 + },
3202 +
3203 + pseudos: {
3204 + 'first-child': function(nodes, value, root) {
3205 + for (var i = 0, results = [], node; node = nodes[i]; i++) {
3206 + if (Selector.handlers.previousElementSibling(node)) continue;
3207 + results.push(node);
3208 + }
3209 + return results;
3210 + },
3211 + 'last-child': function(nodes, value, root) {
3212 + for (var i = 0, results = [], node; node = nodes[i]; i++) {
3213 + if (Selector.handlers.nextElementSibling(node)) continue;
3214 + results.push(node);
3215 + }
3216 + return results;
3217 + },
3218 + 'only-child': function(nodes, value, root) {
3219 + var h = Selector.handlers;
3220 + for (var i = 0, results = [], node; node = nodes[i]; i++)
3221 + if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
3222 + results.push(node);
3223 + return results;
3224 + },
3225 + 'nth-child': function(nodes, formula, root) {
3226 + return Selector.pseudos.nth(nodes, formula, root);
3227 + },
3228 + 'nth-last-child': function(nodes, formula, root) {
3229 + return Selector.pseudos.nth(nodes, formula, root, true);
3230 + },
3231 + 'nth-of-type': function(nodes, formula, root) {
3232 + return Selector.pseudos.nth(nodes, formula, root, false, true);
3233 + },
3234 + 'nth-last-of-type': function(nodes, formula, root) {
3235 + return Selector.pseudos.nth(nodes, formula, root, true, true);
3236 + },
3237 + 'first-of-type': function(nodes, formula, root) {
3238 + return Selector.pseudos.nth(nodes, "1", root, false, true);
3239 + },
3240 + 'last-of-type': function(nodes, formula, root) {
3241 + return Selector.pseudos.nth(nodes, "1", root, true, true);
3242 + },
3243 + 'only-of-type': function(nodes, formula, root) {
3244 + var p = Selector.pseudos;
3245 + return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
3246 + },
3247 +
3248 + // handles the an+b logic
3249 + getIndices: function(a, b, total) {
3250 + if (a == 0) return b > 0 ? [b] : [];
3251 + return $R(1, total).inject([], function(memo, i) {
3252 + if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
3253 + return memo;
3254 + });
3255 + },
3256 +
3257 + // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
3258 + nth: function(nodes, formula, root, reverse, ofType) {
3259 + if (nodes.length == 0) return [];
3260 + if (formula == 'even') formula = '2n+0';
3261 + if (formula == 'odd') formula = '2n+1';
3262 + var h = Selector.handlers, results = [], indexed = [], m;
3263 + h.mark(nodes);
3264 + for (var i = 0, node; node = nodes[i]; i++) {
3265 + if (!node.parentNode._counted) {
3266 + h.index(node.parentNode, reverse, ofType);
3267 + indexed.push(node.parentNode);
3268 + }
3269 + }
3270 + if (formula.match(/^\d+$/)) { // just a number
3271 + formula = Number(formula);
3272 + for (var i = 0, node; node = nodes[i]; i++)
3273 + if (node.nodeIndex == formula) results.push(node);
3274 + } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
3275 + if (m[1] == "-") m[1] = -1;
3276 + var a = m[1] ? Number(m[1]) : 1;
3277 + var b = m[2] ? Number(m[2]) : 0;
3278 + var indices = Selector.pseudos.getIndices(a, b, nodes.length);
3279 + for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
3280 + for (var j = 0; j < l; j++)
3281 + if (node.nodeIndex == indices[j]) results.push(node);
3282 + }
3283 + }
3284 + h.unmark(nodes);
3285 + h.unmark(indexed);
3286 + return results;
3287 + },
3288 +
3289 + 'empty': function(nodes, value, root) {
3290 + for (var i = 0, results = [], node; node = nodes[i]; i++) {
3291 + // IE treats comments as element nodes
3292 + if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
3293 + results.push(node);
3294 + }
3295 + return results;
3296 + },
3297 +
3298 + 'not': function(nodes, selector, root) {
3299 + var h = Selector.handlers, selectorType, m;
3300 + var exclusions = new Selector(selector).findElements(root);
3301 + h.mark(exclusions);
3302 + for (var i = 0, results = [], node; node = nodes[i]; i++)
3303 + if (!node._counted) results.push(node);
3304 + h.unmark(exclusions);
3305 + return results;
3306 + },
3307 +
3308 + 'enabled': function(nodes, value, root) {
3309 + for (var i = 0, results = [], node; node = nodes[i]; i++)
3310 + if (!node.disabled) results.push(node);
3311 + return results;
3312 + },
3313 +
3314 + 'disabled': function(nodes, value, root) {
3315 + for (var i = 0, results = [], node; node = nodes[i]; i++)
3316 + if (node.disabled) results.push(node);
3317 + return results;
3318 + },
3319 +
3320 + 'checked': function(nodes, value, root) {
3321 + for (var i = 0, results = [], node; node = nodes[i]; i++)
3322 + if (node.checked) results.push(node);
3323 + return results;
3324 + }
3325 + },
3326 +
3327 + operators: {
3328 + '=': function(nv, v) { return nv == v; },
3329 + '!=': function(nv, v) { return nv != v; },
3330 + '^=': function(nv, v) { return nv.startsWith(v); },
3331 + '$=': function(nv, v) { return nv.endsWith(v); },
3332 + '*=': function(nv, v) { return nv.include(v); },
3333 + '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
3334 + '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
3335 + },
3336 +
3337 + matchElements: function(elements, expression) {
3338 + var matches = new Selector(expression).findElements(), h = Selector.handlers;
3339 + h.mark(matches);
3340 + for (var i = 0, results = [], element; element = elements[i]; i++)
3341 + if (element._counted) results.push(element);
3342 + h.unmark(matches);
3343 + return results;
3344 + },
3345 +
3346 + findElement: function(elements, expression, index) {
3347 + if (Object.isNumber(expression)) {
3348 + index = expression; expression = false;
3349 + }
3350 + return Selector.matchElements(elements, expression || '*')[index || 0];
3351 + },
3352 +
3353 + findChildElements: function(element, expressions) {
3354 + var exprs = expressions.join(',');
3355 + expressions = [];
3356 + exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
3357 + expressions.push(m[1].strip());
3358 + });
3359 + var results = [], h = Selector.handlers;
3360 + for (var i = 0, l = expressions.length, selector; i < l; i++) {
3361 + selector = new Selector(expressions[i].strip());
3362 + h.concat(results, selector.findElements(element));
3363 + }
3364 + return (l > 1) ? h.unique(results) : results;
3365 + }
3366 + });
3367 +
3368 + if (Prototype.Browser.IE) {
3369 + // IE returns comment nodes on getElementsByTagName("*").
3370 + // Filter them out.
3371 + Selector.handlers.concat = function(a, b) {
3372 + for (var i = 0, node; node = b[i]; i++)
3373 + if (node.tagName !== "!") a.push(node);
3374 + return a;
3375 + };
1619 }
3376 }
1620
3377
1621 - Abstract.Insertion.prototype = {
3378 + function $$() {
1622 - initialize: function(element, content) {
3379 + return Selector.findChildElements(document, $A(arguments));
1623 - this.element = $(element);
3380 + }
1624 - this.content = content.stripScripts();
3381 + var Form = {
1625 -
3382 + reset: function(form) {
1626 - if (this.adjacency && this.element.insertAdjacentHTML) {
3383 + $(form).reset();
1627 - try {
3384 + return form;
1628 - this.element.insertAdjacentHTML(this.adjacency, this.content);
3385 + },
1629 - } catch (e) {
3386 +
1630 - var tagName = this.element.tagName.toUpperCase();
3387 + serializeElements: function(elements, options) {
1631 - if (['TBODY', 'TR'].include(tagName)) {
3388 + if (typeof options != 'object') options = { hash: !!options };
1632 - this.insertContent(this.contentFromAnonymousTable());
3389 + else if (Object.isUndefined(options.hash)) options.hash = true;
1633 - } else {
3390 + var key, value, submitted = false, submit = options.submit;
1634 - throw e;
3391 +
3392 + var data = elements.inject({ }, function(result, element) {
3393 + if (!element.disabled && element.name) {
3394 + key = element.name; value = $(element).getValue();
3395 + if (value != null && (element.type != 'submit' || (!submitted &&
3396 + submit !== false && (!submit || key == submit) && (submitted = true)))) {
3397 + if (key in result) {
3398 + // a key is already present; construct an array of values
3399 + if (!Object.isArray(result[key])) result[key] = [result[key]];
3400 + result[key].push(value);
3401 + }
3402 + else result[key] = value;
1635 }
3403 }
1636 }
3404 }
1637 - } else {
3405 + return result;
1638 - this.range = this.element.ownerDocument.createRange();
3406 + });
1639 - if (this.initializeRange) this.initializeRange();
3407 +
1640 - this.insertContent([this.range.createContextualFragment(this.content)]);
3408 + return options.hash ? data : Object.toQueryString(data);
3409 + }
3410 + };
3411 +
3412 + Form.Methods = {
3413 + serialize: function(form, options) {
3414 + return Form.serializeElements(Form.getElements(form), options);
3415 + },
3416 +
3417 + getElements: function(form) {
3418 + return $A($(form).getElementsByTagName('*')).inject([],
3419 + function(elements, child) {
3420 + if (Form.Element.Serializers[child.tagName.toLowerCase()])
3421 + elements.push(Element.extend(child));
3422 + return elements;
3423 + }
3424 + );
3425 + },
3426 +
3427 + getInputs: function(form, typeName, name) {
3428 + form = $(form);
3429 + var inputs = form.getElementsByTagName('input');
3430 +
3431 + if (!typeName && !name) return $A(inputs).map(Element.extend);
3432 +
3433 + for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
3434 + var input = inputs[i];
3435 + if ((typeName && input.type != typeName) || (name && input.name != name))
3436 + continue;
3437 + matchingInputs.push(Element.extend(input));
3438 + }
3439 +
3440 + return matchingInputs;
3441 + },
3442 +
3443 + disable: function(form) {
3444 + form = $(form);
3445 + Form.getElements(form).invoke('disable');
3446 + return form;
3447 + },
3448 +
3449 + enable: function(form) {
3450 + form = $(form);
3451 + Form.getElements(form).invoke('enable');
3452 + return form;
3453 + },
3454 +
3455 + findFirstElement: function(form) {
3456 + var elements = $(form).getElements().findAll(function(element) {
3457 + return 'hidden' != element.type && !element.disabled;
3458 + });
3459 + var firstByIndex = elements.findAll(function(element) {
3460 + return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
3461 + }).sortBy(function(element) { return element.tabIndex }).first();
3462 +
3463 + return firstByIndex ? firstByIndex : elements.find(function(element) {
3464 + return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
3465 + });
3466 + },
3467 +
3468 + focusFirstElement: function(form) {
3469 + form = $(form);
3470 + form.findFirstElement().activate();
3471 + return form;
3472 + },
3473 +
3474 + request: function(form, options) {
3475 + form = $(form), options = Object.clone(options || { });
3476 +
3477 + var params = options.parameters, action = form.readAttribute('action') || '';
3478 + if (action.blank()) action = window.location.href;
3479 + options.parameters = form.serialize(true);
3480 +
3481 + if (params) {
3482 + if (Object.isString(params)) params = params.toQueryParams();
3483 + Object.extend(options.parameters, params);
1641 }
3484 }
1642
3485
1643 - setTimeout(function() {content.evalScripts()}, 10);
3486 + if (form.hasAttribute('method') && !options.method)
1644 - },
3487 + options.method = form.method;
1645 -
3488 +
1646 - contentFromAnonymousTable: function() {
3489 + return new Ajax.Request(action, options);
1647 - var div = document.createElement('div');
3490 + }
1648 - div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
3491 + };
1649 - return $A(div.childNodes[0].childNodes[0].childNodes);
3492 +
3493 + /*--------------------------------------------------------------------------*/
3494 +
3495 + Form.Element = {
3496 + focus: function(element) {
3497 + $(element).focus();
3498 + return element;
3499 + },
3500 +
3501 + select: function(element) {
3502 + $(element).select();
3503 + return element;
3504 + }
3505 + };
3506 +
3507 + Form.Element.Methods = {
3508 + serialize: function(element) {
3509 + element = $(element);
3510 + if (!element.disabled && element.name) {
3511 + var value = element.getValue();
3512 + if (value != undefined) {
3513 + var pair = { };
3514 + pair[element.name] = value;
3515 + return Object.toQueryString(pair);
3516 + }
3517 + }
3518 + return '';
3519 + },
3520 +
3521 + getValue: function(element) {
3522 + element = $(element);
3523 + var method = element.tagName.toLowerCase();
3524 + return Form.Element.Serializers[method](element);
3525 + },
3526 +
3527 + setValue: function(element, value) {
3528 + element = $(element);
3529 + var method = element.tagName.toLowerCase();
3530 + Form.Element.Serializers[method](element, value);
3531 + return element;
3532 + },
3533 +
3534 + clear: function(element) {
3535 + $(element).value = '';
3536 + return element;
3537 + },
3538 +
3539 + present: function(element) {
3540 + return $(element).value != '';
3541 + },
3542 +
3543 + activate: function(element) {
3544 + element = $(element);
3545 + try {
3546 + element.focus();
3547 + if (element.select && (element.tagName.toLowerCase() != 'input' ||
3548 + !['button', 'reset', 'submit'].include(element.type)))
3549 + element.select();
3550 + } catch (e) { }
3551 + return element;
3552 + },
3553 +
3554 + disable: function(element) {
3555 + element = $(element);
3556 + element.blur();
3557 + element.disabled = true;
3558 + return element;
3559 + },
3560 +
3561 + enable: function(element) {
3562 + element = $(element);
3563 + element.disabled = false;
3564 + return element;
1650 }
3565 }
1651 - }
3566 + };
1652 -
3567 +
1653 - var Insertion = new Object();
3568 + /*--------------------------------------------------------------------------*/
1654 -
3569 +
1655 - Insertion.Before = Class.create();
3570 + var Field = Form.Element;
1656 - Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
3571 + var $F = Form.Element.Methods.getValue;
1657 - initializeRange: function() {
3572 +
1658 - this.range.setStartBefore(this.element);
3573 + /*--------------------------------------------------------------------------*/
1659 - },
3574 +
1660 -
3575 + Form.Element.Serializers = {
1661 - insertContent: function(fragments) {
3576 + input: function(element, value) {
1662 - fragments.each((function(fragment) {
3577 + switch (element.type.toLowerCase()) {
1663 - this.element.parentNode.insertBefore(fragment, this.element);
3578 + case 'checkbox':
1664 - }).bind(this));
3579 + case 'radio':
3580 + return Form.Element.Serializers.inputSelector(element, value);
3581 + default:
3582 + return Form.Element.Serializers.textarea(element, value);
3583 + }
3584 + },
3585 +
3586 + inputSelector: function(element, value) {
3587 + if (Object.isUndefined(value)) return element.checked ? element.value : null;
3588 + else element.checked = !!value;
3589 + },
3590 +
3591 + textarea: function(element, value) {
3592 + if (Object.isUndefined(value)) return element.value;
3593 + else element.value = value;
3594 + },
3595 +
3596 + select: function(element, index) {
3597 + if (Object.isUndefined(index))
3598 + return this[element.type == 'select-one' ?
3599 + 'selectOne' : 'selectMany'](element);
3600 + else {
3601 + var opt, value, single = !Object.isArray(index);
3602 + for (var i = 0, length = element.length; i < length; i++) {
3603 + opt = element.options[i];
3604 + value = this.optionValue(opt);
3605 + if (single) {
3606 + if (value == index) {
3607 + opt.selected = true;
3608 + return;
3609 + }
3610 + }
3611 + else opt.selected = index.include(value);
3612 + }
3613 + }
3614 + },
3615 +
3616 + selectOne: function(element) {
3617 + var index = element.selectedIndex;
3618 + return index >= 0 ? this.optionValue(element.options[index]) : null;
3619 + },
3620 +
3621 + selectMany: function(element) {
3622 + var values, length = element.length;
3623 + if (!length) return null;
3624 +
3625 + for (var i = 0, values = []; i < length; i++) {
3626 + var opt = element.options[i];
3627 + if (opt.selected) values.push(this.optionValue(opt));
3628 + }
3629 + return values;
3630 + },
3631 +
3632 + optionValue: function(opt) {
3633 + // extend element because hasAttribute may not be native
3634 + return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
3635 + }
3636 + };
3637 +
3638 + /*--------------------------------------------------------------------------*/
3639 +
3640 + Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
3641 + initialize: function($super, element, frequency, callback) {
3642 + $super(callback, frequency);
3643 + this.element = $(element);
3644 + this.lastValue = this.getValue();
3645 + },
3646 +
3647 + execute: function() {
3648 + var value = this.getValue();
3649 + if (Object.isString(this.lastValue) && Object.isString(value) ?
3650 + this.lastValue != value : String(this.lastValue) != String(value)) {
3651 + this.callback(this.element, value);
3652 + this.lastValue = value;
3653 + }
3654 + }
3655 + });
3656 +
3657 + Form.Element.Observer = Class.create(Abstract.TimedObserver, {
3658 + getValue: function() {
3659 + return Form.Element.getValue(this.element);
3660 + }
3661 + });
3662 +
3663 + Form.Observer = Class.create(Abstract.TimedObserver, {
3664 + getValue: function() {
3665 + return Form.serialize(this.element);
3666 + }
3667 + });
3668 +
3669 + /*--------------------------------------------------------------------------*/
3670 +
3671 + Abstract.EventObserver = Class.create({
3672 + initialize: function(element, callback) {
3673 + this.element = $(element);
3674 + this.callback = callback;
3675 +
3676 + this.lastValue = this.getValue();
3677 + if (this.element.tagName.toLowerCase() == 'form')
3678 + this.registerFormCallbacks();
3679 + else
3680 + this.registerCallback(this.element);
3681 + },
3682 +
3683 + onElementEvent: function() {
3684 + var value = this.getValue();
3685 + if (this.lastValue != value) {
3686 + this.callback(this.element, value);
3687 + this.lastValue = value;
3688 + }
3689 + },
3690 +
3691 + registerFormCallbacks: function() {
3692 + Form.getElements(this.element).each(this.registerCallback, this);
3693 + },
3694 +
3695 + registerCallback: function(element) {
3696 + if (element.type) {
3697 + switch (element.type.toLowerCase()) {
3698 + case 'checkbox':
3699 + case 'radio':
3700 + Event.observe(element, 'click', this.onElementEvent.bind(this));
3701 + break;
3702 + default:
3703 + Event.observe(element, 'change', this.onElementEvent.bind(this));
3704 + break;
3705 + }
3706 + }
3707 + }
3708 + });
3709 +
3710 + Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
3711 + getValue: function() {
3712 + return Form.Element.getValue(this.element);
3713 + }
3714 + });
3715 +
3716 + Form.EventObserver = Class.create(Abstract.EventObserver, {
3717 + getValue: function() {
3718 + return Form.serialize(this.element);
3719 + }
3720 + });
3721 + if (!window.Event) var Event = { };
3722 +
3723 + Object.extend(Event, {
3724 + KEY_BACKSPACE: 8,
3725 + KEY_TAB: 9,
3726 + KEY_RETURN: 13,
3727 + KEY_ESC: 27,
3728 + KEY_LEFT: 37,
3729 + KEY_UP: 38,
3730 + KEY_RIGHT: 39,
3731 + KEY_DOWN: 40,
3732 + KEY_DELETE: 46,
3733 + KEY_HOME: 36,
3734 + KEY_END: 35,
3735 + KEY_PAGEUP: 33,
3736 + KEY_PAGEDOWN: 34,
3737 + KEY_INSERT: 45,
3738 +
3739 + cache: { },
3740 +
3741 + relatedTarget: function(event) {
3742 + var element;
3743 + switch(event.type) {
3744 + case 'mouseover': element = event.fromElement; break;
3745 + case 'mouseout': element = event.toElement; break;
3746 + default: return null;
3747 + }
3748 + return Element.extend(element);
1665 }
3749 }
1666 });
3750 });
1667
3751
1668 - Insertion.Top = Class.create();
3752 + Event.Methods = (function() {
1669 - Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
3753 + var isButton;
1670 - initializeRange: function() {
3754 +
1671 - this.range.selectNodeContents(this.element);
3755 + if (Prototype.Browser.IE) {
1672 - this.range.collapse(true);
3756 + var buttonMap = { 0: 1, 1: 4, 2: 2 };
1673 - },
3757 + isButton = function(event, code) {
1674 -
3758 + return event.button == buttonMap[code];
1675 - insertContent: function(fragments) {
3759 + };
1676 - fragments.reverse(false).each((function(fragment) {
3760 +
1677 - this.element.insertBefore(fragment, this.element.firstChild);
3761 + } else if (Prototype.Browser.WebKit) {
1678 - }).bind(this));
3762 + isButton = function(event, code) {
3763 + switch (code) {
3764 + case 0: return event.which == 1 && !event.metaKey;
3765 + case 1: return event.which == 1 && event.metaKey;
3766 + default: return false;
3767 + }
3768 + };
3769 +
3770 + } else {
3771 + isButton = function(event, code) {
3772 + return event.which ? (event.which === code + 1) : (event.button === code);
3773 + };
3774 + }
3775 +
3776 + return {
3777 + isLeftClick: function(event) { return isButton(event, 0) },
3778 + isMiddleClick: function(event) { return isButton(event, 1) },
3779 + isRightClick: function(event) { return isButton(event, 2) },
3780 +
3781 + element: function(event) {
3782 + var node = Event.extend(event).target;
3783 + return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node);
3784 + },
3785 +
3786 + findElement: function(event, expression) {
3787 + var element = Event.element(event);
3788 + if (!expression) return element;
3789 + var elements = [element].concat(element.ancestors());
3790 + return Selector.findElement(elements, expression, 0);
3791 + },
3792 +
3793 + pointer: function(event) {
3794 + return {
3795 + x: event.pageX || (event.clientX +
3796 + (document.documentElement.scrollLeft || document.body.scrollLeft)),
3797 + y: event.pageY || (event.clientY +
3798 + (document.documentElement.scrollTop || document.body.scrollTop))
3799 + };
3800 + },
3801 +
3802 + pointerX: function(event) { return Event.pointer(event).x },
3803 + pointerY: function(event) { return Event.pointer(event).y },
3804 +
3805 + stop: function(event) {
3806 + Event.extend(event);
3807 + event.preventDefault();
3808 + event.stopPropagation();
3809 + event.stopped = true;
3810 + }
3811 + };
3812 + })();
3813 +
3814 + Event.extend = (function() {
3815 + var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
3816 + m[name] = Event.Methods[name].methodize();
3817 + return m;
3818 + });
3819 +
3820 + if (Prototype.Browser.IE) {
3821 + Object.extend(methods, {
3822 + stopPropagation: function() { this.cancelBubble = true },
3823 + preventDefault: function() { this.returnValue = false },
3824 + inspect: function() { return "[object Event]" }
3825 + });
3826 +
3827 + return function(event) {
3828 + if (!event) return false;
3829 + if (event._extendedByPrototype) return event;
3830 +
3831 + event._extendedByPrototype = Prototype.emptyFunction;
3832 + var pointer = Event.pointer(event);
3833 + Object.extend(event, {
3834 + target: event.srcElement,
3835 + relatedTarget: Event.relatedTarget(event),
3836 + pageX: pointer.x,
3837 + pageY: pointer.y
3838 + });
3839 + return Object.extend(event, methods);
3840 + };
3841 +
3842 + } else {
3843 + Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__;
3844 + Object.extend(Event.prototype, methods);
3845 + return Prototype.K;
3846 + }
3847 + })();
3848 +
3849 + Object.extend(Event, (function() {
3850 + var cache = Event.cache;
3851 +
3852 + function getEventID(element) {
3853 + if (element._eventID) return element._eventID;
3854 + arguments.callee.id = arguments.callee.id || 1;
3855 + return element._eventID = ++arguments.callee.id;
3856 + }
3857 +
3858 + function getDOMEventName(eventName) {
3859 + if (eventName && eventName.include(':')) return "dataavailable";
3860 + return eventName;
3861 + }
3862 +
3863 + function getCacheForID(id) {
3864 + return cache[id] = cache[id] || { };
3865 + }
3866 +
3867 + function getWrappersForEventName(id, eventName) {
3868 + var c = getCacheForID(id);
3869 + return c[eventName] = c[eventName] || [];
1679 }
3870 }
3871 +
3872 + function createWrapper(element, eventName, handler) {
3873 + var id = getEventID(element);
3874 + var c = getWrappersForEventName(id, eventName);
3875 + if (c.pluck("handler").include(handler)) return false;
3876 +
3877 + var wrapper = function(event) {
3878 + if (!Event || !Event.extend ||
3879 + (event.eventName && event.eventName != eventName))
3880 + return false;
3881 +
3882 + Event.extend(event);
3883 + handler.call(element, event)
3884 + };
3885 +
3886 + wrapper.handler = handler;
3887 + c.push(wrapper);
3888 + return wrapper;
3889 + }
3890 +
3891 + function findWrapper(id, eventName, handler) {
3892 + var c = getWrappersForEventName(id, eventName);
3893 + return c.find(function(wrapper) { return wrapper.handler == handler });
3894 + }
3895 +
3896 + function destroyWrapper(id, eventName, handler) {
3897 + var c = getCacheForID(id);
3898 + if (!c[eventName]) return false;
3899 + c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
3900 + }
3901 +
3902 + function destroyCache() {
3903 + for (var id in cache)
3904 + for (var eventName in cache[id])
3905 + cache[id][eventName] = null;
3906 + }
3907 +
3908 + if (window.attachEvent) {
3909 + window.attachEvent("onunload", destroyCache);
3910 + }
3911 +
3912 + return {
3913 + observe: function(element, eventName, handler) {
3914 + element = $(element);
3915 + var name = getDOMEventName(eventName);
3916 +
3917 + var wrapper = createWrapper(element, eventName, handler);
3918 + if (!wrapper) return element;
3919 +
3920 + if (element.addEventListener) {
3921 + element.addEventListener(name, wrapper, false);
3922 + } else {
3923 + element.attachEvent("on" + name, wrapper);
3924 + }
3925 +
3926 + return element;
3927 + },
3928 +
3929 + stopObserving: function(element, eventName, handler) {
3930 + element = $(element);
3931 + var id = getEventID(element), name = getDOMEventName(eventName);
3932 +
3933 + if (!handler && eventName) {
3934 + getWrappersForEventName(id, eventName).each(function(wrapper) {
3935 + element.stopObserving(eventName, wrapper.handler);
3936 + });
3937 + return element;
3938 +
3939 + } else if (!eventName) {
3940 + Object.keys(getCacheForID(id)).each(function(eventName) {
3941 + element.stopObserving(eventName);
3942 + });
3943 + return element;
3944 + }
3945 +
3946 + var wrapper = findWrapper(id, eventName, handler);
3947 + if (!wrapper) return element;
3948 +
3949 + if (element.removeEventListener) {
3950 + element.removeEventListener(name, wrapper, false);
3951 + } else {
3952 + element.detachEvent("on" + name, wrapper);
3953 + }
3954 +
3955 + destroyWrapper(id, eventName, handler);
3956 +
3957 + return element;
3958 + },
3959 +
3960 + fire: function(element, eventName, memo) {
3961 + element = $(element);
3962 + if (element == document && document.createEvent && !element.dispatchEvent)
3963 + element = document.documentElement;
3964 +
3965 + if (document.createEvent) {
3966 + var event = document.createEvent("HTMLEvents");
3967 + event.initEvent("dataavailable", true, true);
3968 + } else {
3969 + var event = document.createEventObject();
3970 + event.eventType = "ondataavailable";
3971 + }
3972 +
3973 + event.eventName = eventName;
3974 + event.memo = memo || { };
3975 +
3976 + if (document.createEvent) {
3977 + element.dispatchEvent(event);
3978 + } else {
3979 + element.fireEvent(event.eventType, event);
3980 + }
3981 +
3982 + return Event.extend(event);
3983 + }
3984 + };
3985 + })());
3986 +
3987 + Object.extend(Event, Event.Methods);
3988 +
3989 + Element.addMethods({
3990 + fire: Event.fire,
3991 + observe: Event.observe,
3992 + stopObserving: Event.stopObserving
1680 });
3993 });
1681
3994
1682 - Insertion.Bottom = Class.create();
3995 + Object.extend(document, {
1683 - Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
3996 + fire: Element.Methods.fire.methodize(),
1684 - initializeRange: function() {
3997 + observe: Element.Methods.observe.methodize(),
1685 - this.range.selectNodeContents(this.element);
3998 + stopObserving: Element.Methods.stopObserving.methodize()
1686 - this.range.collapse(this.element);
1687 - },
1688 -
1689 - insertContent: function(fragments) {
1690 - fragments.each((function(fragment) {
1691 - this.element.appendChild(fragment);
1692 - }).bind(this));
1693 - }
1694 });
3999 });
1695
4000
1696 - Insertion.After = Class.create();
4001 + (function() {
1697 - Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
4002 + /* Support for the DOMContentLoaded event is based on work by Dan Webb,
1698 - initializeRange: function() {
4003 + Matthias Miller, Dean Edwards and John Resig. */
1699 - this.range.setStartAfter(this.element);
4004 +
1700 - },
4005 + var timer, fired = false;
1701 -
4006 +
1702 - insertContent: function(fragments) {
4007 + function fireContentLoadedEvent() {
1703 - fragments.each((function(fragment) {
4008 + if (fired) return;
1704 - this.element.parentNode.insertBefore(fragment,
4009 + if (timer) window.clearInterval(timer);
1705 - this.element.nextSibling);
4010 + document.fire("dom:loaded");
1706 - }).bind(this));
4011 + fired = true;
4012 + }
4013 +
4014 + if (document.addEventListener) {
4015 + if (Prototype.Browser.WebKit) {
4016 + timer = window.setInterval(function() {
4017 + if (/loaded|complete/.test(document.readyState))
4018 + fireContentLoadedEvent();
4019 + }, 0);
4020 +
4021 + Event.observe(window, "load", fireContentLoadedEvent);
4022 +
4023 + } else {
4024 + document.addEventListener("DOMContentLoaded",
4025 + fireContentLoadedEvent, false);
4026 + }
4027 +
4028 + } else {
4029 + document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>");
4030 + $("__onDOMContentLoaded").onreadystatechange = function() {
4031 + if (this.readyState == "complete") {
4032 + this.onreadystatechange = null;
4033 + fireContentLoadedEvent();
4034 + }
4035 + };
4036 + }
4037 + })();
4038 + /*------------------------------- DEPRECATED -------------------------------*/
4039 +
4040 + Hash.toQueryString = Object.toQueryString;
4041 +
4042 + var Toggle = { display: Element.toggle };
4043 +
4044 + Element.Methods.childOf = Element.Methods.descendantOf;
4045 +
4046 + var Insertion = {
4047 + Before: function(element, content) {
4048 + return Element.insert(element, {before:content});
4049 + },
4050 +
4051 + Top: function(element, content) {
4052 + return Element.insert(element, {top:content});
4053 + },
4054 +
4055 + Bottom: function(element, content) {
4056 + return Element.insert(element, {bottom:content});
4057 + },
4058 +
4059 + After: function(element, content) {
4060 + return Element.insert(element, {after:content});
1707 }
4061 }
1708 - });
4062 + };
4063 +
4064 + var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
4065 +
4066 + // This should be moved to script.aculo.us; notice the deprecated methods
4067 + // further below, that map to the newer Element methods.
4068 + var Position = {
4069 + // set to true if needed, warning: firefox performance problems
4070 + // NOT neeeded for page scrolling, only if draggable contained in
4071 + // scrollable elements
4072 + includeScrollOffsets: false,
4073 +
4074 + // must be called before calling withinIncludingScrolloffset, every time the
4075 + // page is scrolled
4076 + prepare: function() {
4077 + this.deltaX = window.pageXOffset
4078 + || document.documentElement.scrollLeft
4079 + || document.body.scrollLeft
4080 + || 0;
4081 + this.deltaY = window.pageYOffset
4082 + || document.documentElement.scrollTop
4083 + || document.body.scrollTop
4084 + || 0;
4085 + },
4086 +
4087 + // caches x/y coordinate pair to use with overlap
4088 + within: function(element, x, y) {
4089 + if (this.includeScrollOffsets)
4090 + return this.withinIncludingScrolloffsets(element, x, y);
4091 + this.xcomp = x;
4092 + this.ycomp = y;
4093 + this.offset = Element.cumulativeOffset(element);
4094 +
4095 + return (y >= this.offset[1] &&
4096 + y < this.offset[1] + element.offsetHeight &&
4097 + x >= this.offset[0] &&
4098 + x < this.offset[0] + element.offsetWidth);
4099 + },
4100 +
4101 + withinIncludingScrolloffsets: function(element, x, y) {
4102 + var offsetcache = Element.cumulativeScrollOffset(element);
4103 +
4104 + this.xcomp = x + offsetcache[0] - this.deltaX;
4105 + this.ycomp = y + offsetcache[1] - this.deltaY;
4106 + this.offset = Element.cumulativeOffset(element);
4107 +
4108 + return (this.ycomp >= this.offset[1] &&
4109 + this.ycomp < this.offset[1] + element.offsetHeight &&
4110 + this.xcomp >= this.offset[0] &&
4111 + this.xcomp < this.offset[0] + element.offsetWidth);
4112 + },
4113 +
4114 + // within must be called directly before
4115 + overlap: function(mode, element) {
4116 + if (!mode) return 0;
4117 + if (mode == 'vertical')
4118 + return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
4119 + element.offsetHeight;
4120 + if (mode == 'horizontal')
4121 + return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
4122 + element.offsetWidth;
4123 + },
4124 +
4125 + // Deprecation layer -- use newer Element methods now (1.5.2).
4126 +
4127 + cumulativeOffset: Element.Methods.cumulativeOffset,
4128 +
4129 + positionedOffset: Element.Methods.positionedOffset,
4130 +
4131 + absolutize: function(element) {
4132 + Position.prepare();
4133 + return Element.absolutize(element);
4134 + },
4135 +
4136 + relativize: function(element) {
4137 + Position.prepare();
4138 + return Element.relativize(element);
4139 + },
4140 +
4141 + realOffset: Element.Methods.cumulativeScrollOffset,
4142 +
4143 + offsetParent: Element.Methods.getOffsetParent,
4144 +
4145 + page: Element.Methods.viewportOffset,
4146 +
4147 + clone: function(source, target, options) {
4148 + options = options || { };
4149 + return Element.clonePosition(target, source, options);
4150 + }
4151 + };
4152 +
4153 + /*--------------------------------------------------------------------------*/
4154 +
4155 + if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
4156 + function iter(name) {
4157 + return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
4158 + }
4159 +
4160 + instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
4161 + function(element, className) {
4162 + className = className.toString().strip();
4163 + var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
4164 + return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
4165 + } : function(element, className) {
4166 + className = className.toString().strip();
4167 + var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
4168 + if (!classNames && !className) return elements;
4169 +
4170 + var nodes = $(element).getElementsByTagName('*');
4171 + className = ' ' + className + ' ';
4172 +
4173 + for (var i = 0, child, cn; child = nodes[i]; i++) {
4174 + if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
4175 + (classNames && classNames.all(function(name) {
4176 + return !name.toString().blank() && cn.include(' ' + name + ' ');
4177 + }))))
4178 + elements.push(Element.extend(child));
4179 + }
4180 + return elements;
4181 + };
4182 +
4183 + return function(className, parentElement) {
4184 + return $(parentElement || document.body).getElementsByClassName(className);
4185 + };
4186 + }(Element.Methods);
1709
4187
1710 /*--------------------------------------------------------------------------*/
4188 /*--------------------------------------------------------------------------*/
1711
4189
@@ -1741,775 +4219,7
1741 };
4219 };
1742
4220
1743 Object.extend(Element.ClassNames.prototype, Enumerable);
4221 Object.extend(Element.ClassNames.prototype, Enumerable);
1744 - var Selector = Class.create();
1745 - Selector.prototype = {
1746 - initialize: function(expression) {
1747 - this.params = {classNames: []};
1748 - this.expression = expression.toString().strip();
1749 - this.parseExpression();
1750 - this.compileMatcher();
1751 - },
1752 -
1753 - parseExpression: function() {
1754 - function abort(message) { throw 'Parse error in selector: ' + message; }
1755 -
1756 - if (this.expression == '') abort('empty expression');
1757 -
1758 - var params = this.params, expr = this.expression, match, modifier, clause, rest;
1759 - while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
1760 - params.attributes = params.attributes || [];
1761 - params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
1762 - expr = match[1];
1763 - }
1764 -
1765 - if (expr == '*') return this.params.wildcard = true;
1766 -
1767 - while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
1768 - modifier = match[1], clause = match[2], rest = match[3];
1769 - switch (modifier) {
1770 - case '#': params.id = clause; break;
1771 - case '.': params.classNames.push(clause); break;
1772 - case '':
1773 - case undefined: params.tagName = clause.toUpperCase(); break;
1774 - default: abort(expr.inspect());
1775 - }
1776 - expr = rest;
1777 - }
1778 -
1779 - if (expr.length > 0) abort(expr.inspect());
1780 - },
1781 -
1782 - buildMatchExpression: function() {
1783 - var params = this.params, conditions = [], clause;
1784 -
1785 - if (params.wildcard)
1786 - conditions.push('true');
1787 - if (clause = params.id)
1788 - conditions.push('element.readAttribute("id") == ' + clause.inspect());
1789 - if (clause = params.tagName)
1790 - conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
1791 - if ((clause = params.classNames).length > 0)
1792 - for (var i = 0, length = clause.length; i < length; i++)
1793 - conditions.push('element.hasClassName(' + clause[i].inspect() + ')');
1794 - if (clause = params.attributes) {
1795 - clause.each(function(attribute) {
1796 - var value = 'element.readAttribute(' + attribute.name.inspect() + ')';
1797 - var splitValueBy = function(delimiter) {
1798 - return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
1799 - }
1800 -
1801 - switch (attribute.operator) {
1802 - case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break;
1803 - case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
1804 - case '|=': conditions.push(
1805 - splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
1806 - ); break;
1807 - case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break;
1808 - case '':
1809 - case undefined: conditions.push('element.hasAttribute(' + attribute.name.inspect() + ')'); break;
1810 - default: throw 'Unknown operator ' + attribute.operator + ' in selector';
1811 - }
1812 - });
1813 - }
1814 -
1815 - return conditions.join(' && ');
1816 - },
1817 -
1818 - compileMatcher: function() {
1819 - this.match = new Function('element', 'if (!element.tagName) return false; \
1820 - element = $(element); \
1821 - return ' + this.buildMatchExpression());
1822 - },
1823 -
1824 - findElements: function(scope) {
1825 - var element;
1826 -
1827 - if (element = $(this.params.id))
1828 - if (this.match(element))
1829 - if (!scope || Element.childOf(element, scope))
1830 - return [element];
1831 -
1832 - scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
1833 -
1834 - var results = [];
1835 - for (var i = 0, length = scope.length; i < length; i++)
1836 - if (this.match(element = scope[i]))
1837 - results.push(Element.extend(element));
1838 -
1839 - return results;
1840 - },
1841 -
1842 - toString: function() {
1843 - return this.expression;
1844 - }
1845 - }
1846 -
1847 - Object.extend(Selector, {
1848 - matchElements: function(elements, expression) {
1849 - var selector = new Selector(expression);
1850 - return elements.select(selector.match.bind(selector)).map(Element.extend);
1851 - },
1852 -
1853 - findElement: function(elements, expression, index) {
1854 - if (typeof expression == 'number') index = expression, expression = false;
1855 - return Selector.matchElements(elements, expression || '*')[index || 0];
1856 - },
1857 -
1858 - findChildElements: function(element, expressions) {
1859 - return expressions.map(function(expression) {
1860 - return expression.match(/[^\s"]+(?:"[^"]*"[^\s"]+)*/g).inject([null], function(results, expr) {
1861 - var selector = new Selector(expr);
1862 - return results.inject([], function(elements, result) {
1863 - return elements.concat(selector.findElements(result || element));
1864 - });
1865 - });
1866 - }).flatten();
1867 - }
1868 - });
1869 -
1870 - function $$() {
1871 - return Selector.findChildElements(document, $A(arguments));
1872 - }
1873 - var Form = {
1874 - reset: function(form) {
1875 - $(form).reset();
1876 - return form;
1877 - },
1878 -
1879 - serializeElements: function(elements, getHash) {
1880 - var data = elements.inject({}, function(result, element) {
1881 - if (!element.disabled && element.name) {
1882 - var key = element.name, value = $(element).getValue();
1883 - if (value != undefined) {
1884 - if (result[key]) {
1885 - if (result[key].constructor != Array) result[key] = [result[key]];
1886 - result[key].push(value);
1887 - }
1888 - else result[key] = value;
1889 - }
1890 - }
1891 - return result;
1892 - });
1893 -
1894 - return getHash ? data : Hash.toQueryString(data);
1895 - }
1896 - };
1897 -
1898 - Form.Methods = {
1899 - serialize: function(form, getHash) {
1900 - return Form.serializeElements(Form.getElements(form), getHash);
1901 - },
1902 -
1903 - getElements: function(form) {
1904 - return $A($(form).getElementsByTagName('*')).inject([],
1905 - function(elements, child) {
1906 - if (Form.Element.Serializers[child.tagName.toLowerCase()])
1907 - elements.push(Element.extend(child));
1908 - return elements;
1909 - }
1910 - );
1911 - },
1912 -
1913 - getInputs: function(form, typeName, name) {
1914 - form = $(form);
1915 - var inputs = form.getElementsByTagName('input');
1916 -
1917 - if (!typeName && !name) return $A(inputs).map(Element.extend);
1918 -
1919 - for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
1920 - var input = inputs[i];
1921 - if ((typeName && input.type != typeName) || (name && input.name != name))
1922 - continue;
1923 - matchingInputs.push(Element.extend(input));
1924 - }
1925 -
1926 - return matchingInputs;
1927 - },
1928 -
1929 - disable: function(form) {
1930 - form = $(form);
1931 - form.getElements().each(function(element) {
1932 - element.blur();
1933 - element.disabled = 'true';
1934 - });
1935 - return form;
1936 - },
1937 -
1938 - enable: function(form) {
1939 - form = $(form);
1940 - form.getElements().each(function(element) {
1941 - element.disabled = '';
1942 - });
1943 - return form;
1944 - },
1945 -
1946 - findFirstElement: function(form) {
1947 - return $(form).getElements().find(function(element) {
1948 - return element.type != 'hidden' && !element.disabled &&
1949 - ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
1950 - });
1951 - },
1952 -
1953 - focusFirstElement: function(form) {
1954 - form = $(form);
1955 - form.findFirstElement().activate();
1956 - return form;
1957 - }
1958 - }
1959 -
1960 - Object.extend(Form, Form.Methods);
1961 -
1962 - /*--------------------------------------------------------------------------*/
1963 -
1964 - Form.Element = {
1965 - focus: function(element) {
1966 - $(element).focus();
1967 - return element;
1968 - },
1969 -
1970 - select: function(element) {
1971 - $(element).select();
1972 - return element;
1973 - }
1974 - }
1975 -
1976 - Form.Element.Methods = {
1977 - serialize: function(element) {
1978 - element = $(element);
1979 - if (!element.disabled && element.name) {
1980 - var value = element.getValue();
1981 - if (value != undefined) {
1982 - var pair = {};
1983 - pair[element.name] = value;
1984 - return Hash.toQueryString(pair);
1985 - }
1986 - }
1987 - return '';
1988 - },
1989 -
1990 - getValue: function(element) {
1991 - element = $(element);
1992 - var method = element.tagName.toLowerCase();
1993 - return Form.Element.Serializers[method](element);
1994 - },
1995 -
1996 - clear: function(element) {
1997 - $(element).value = '';
1998 - return element;
1999 - },
2000 -
2001 - present: function(element) {
2002 - return $(element).value != '';
2003 - },
2004 -
2005 - activate: function(element) {
2006 - element = $(element);
2007 - element.focus();
2008 - if (element.select && ( element.tagName.toLowerCase() != 'input' ||
2009 - !['button', 'reset', 'submit'].include(element.type) ) )
2010 - element.select();
2011 - return element;
2012 - },
2013 -
2014 - disable: function(element) {
2015 - element = $(element);
2016 - element.disabled = true;
2017 - return element;
2018 - },
2019 -
2020 - enable: function(element) {
2021 - element = $(element);
2022 - element.blur();
2023 - element.disabled = false;
2024 - return element;
2025 - }
2026 - }
2027 -
2028 - Object.extend(Form.Element, Form.Element.Methods);
2029 - var Field = Form.Element;
2030 - var $F = Form.Element.getValue;
2031 -
2032 - /*--------------------------------------------------------------------------*/
2033 -
2034 - Form.Element.Serializers = {
2035 - input: function(element) {
2036 - switch (element.type.toLowerCase()) {
2037 - case 'checkbox':
2038 - case 'radio':
2039 - return Form.Element.Serializers.inputSelector(element);
2040 - default:
2041 - return Form.Element.Serializers.textarea(element);
2042 - }
2043 - },
2044 -
2045 - inputSelector: function(element) {
2046 - return element.checked ? element.value : null;
2047 - },
2048 -
2049 - textarea: function(element) {
2050 - return element.value;
2051 - },
2052 -
2053 - select: function(element) {
2054 - return this[element.type == 'select-one' ?
2055 - 'selectOne' : 'selectMany'](element);
2056 - },
2057 -
2058 - selectOne: function(element) {
2059 - var index = element.selectedIndex;
2060 - return index >= 0 ? this.optionValue(element.options[index]) : null;
2061 - },
2062 -
2063 - selectMany: function(element) {
2064 - var values, length = element.length;
2065 - if (!length) return null;
2066 -
2067 - for (var i = 0, values = []; i < length; i++) {
2068 - var opt = element.options[i];
2069 - if (opt.selected) values.push(this.optionValue(opt));
2070 - }
2071 - return values;
2072 - },
2073 -
2074 - optionValue: function(opt) {
2075 - // extend element because hasAttribute may not be native
2076 - return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
2077 - }
2078 - }
2079 -
2080 - /*--------------------------------------------------------------------------*/
2081 -
2082 - Abstract.TimedObserver = function() {}
2083 - Abstract.TimedObserver.prototype = {
2084 - initialize: function(element, frequency, callback) {
2085 - this.frequency = frequency;
2086 - this.element = $(element);
2087 - this.callback = callback;
2088 -
2089 - this.lastValue = this.getValue();
2090 - this.registerCallback();
2091 - },
2092 -
2093 - registerCallback: function() {
2094 - setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
2095 - },
2096 -
2097 - onTimerEvent: function() {
2098 - var value = this.getValue();
2099 - var changed = ('string' == typeof this.lastValue && 'string' == typeof value
2100 - ? this.lastValue != value : String(this.lastValue) != String(value));
2101 - if (changed) {
2102 - this.callback(this.element, value);
2103 - this.lastValue = value;
2104 - }
2105 - }
2106 - }
2107 -
2108 - Form.Element.Observer = Class.create();
2109 - Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
2110 - getValue: function() {
2111 - return Form.Element.getValue(this.element);
2112 - }
2113 - });
2114 -
2115 - Form.Observer = Class.create();
2116 - Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
2117 - getValue: function() {
2118 - return Form.serialize(this.element);
2119 - }
2120 - });
2121
4222
2122 /*--------------------------------------------------------------------------*/
4223 /*--------------------------------------------------------------------------*/
2123
4224
2124 - Abstract.EventObserver = function() {}
2125 - Abstract.EventObserver.prototype = {
2126 - initialize: function(element, callback) {
2127 - this.element = $(element);
2128 - this.callback = callback;
2129 -
2130 - this.lastValue = this.getValue();
2131 - if (this.element.tagName.toLowerCase() == 'form')
2132 - this.registerFormCallbacks();
2133 - else
2134 - this.registerCallback(this.element);
2135 - },
2136 -
2137 - onElementEvent: function() {
2138 - var value = this.getValue();
2139 - if (this.lastValue != value) {
2140 - this.callback(this.element, value);
2141 - this.lastValue = value;
2142 - }
2143 - },
2144 -
2145 - registerFormCallbacks: function() {
2146 - Form.getElements(this.element).each(this.registerCallback.bind(this));
2147 - },
2148 -
2149 - registerCallback: function(element) {
2150 - if (element.type) {
2151 - switch (element.type.toLowerCase()) {
2152 - case 'checkbox':
2153 - case 'radio':
2154 - Event.observe(element, 'click', this.onElementEvent.bind(this));
2155 - break;
2156 - default:
2157 - Event.observe(element, 'change', this.onElementEvent.bind(this));
2158 - break;
2159 - }
2160 - }
2161 - }
2162 - }
2163 -
2164 - Form.Element.EventObserver = Class.create();
2165 - Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
2166 - getValue: function() {
2167 - return Form.Element.getValue(this.element);
2168 - }
2169 - });
2170 -
2171 - Form.EventObserver = Class.create();
2172 - Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
2173 - getValue: function() {
2174 - return Form.serialize(this.element);
2175 - }
2176 - });
2177 - if (!window.Event) {
2178 - var Event = new Object();
2179 - }
2180 -
2181 - Object.extend(Event, {
2182 - KEY_BACKSPACE: 8,
2183 - KEY_TAB: 9,
2184 - KEY_RETURN: 13,
2185 - KEY_ESC: 27,
2186 - KEY_LEFT: 37,
2187 - KEY_UP: 38,
2188 - KEY_RIGHT: 39,
2189 - KEY_DOWN: 40,
2190 - KEY_DELETE: 46,
2191 - KEY_HOME: 36,
2192 - KEY_END: 35,
2193 - KEY_PAGEUP: 33,
2194 - KEY_PAGEDOWN: 34,
2195 -
2196 - element: function(event) {
2197 - return event.target || event.srcElement;
2198 - },
2199 -
2200 - isLeftClick: function(event) {
2201 - return (((event.which) && (event.which == 1)) ||
2202 - ((event.button) && (event.button == 1)));
2203 - },
2204 -
2205 - pointerX: function(event) {
2206 - return event.pageX || (event.clientX +
2207 - (document.documentElement.scrollLeft || document.body.scrollLeft));
2208 - },
2209 -
2210 - pointerY: function(event) {
2211 - return event.pageY || (event.clientY +
2212 - (document.documentElement.scrollTop || document.body.scrollTop));
2213 - },
2214 -
2215 - stop: function(event) {
2216 - if (event.preventDefault) {
2217 - event.preventDefault();
2218 - event.stopPropagation();
2219 - } else {
2220 - event.returnValue = false;
2221 - event.cancelBubble = true;
2222 - }
2223 - },
2224 -
2225 - // find the first node with the given tagName, starting from the
2226 - // node the event was triggered on; traverses the DOM upwards
2227 - findElement: function(event, tagName) {
2228 - var element = Event.element(event);
2229 - while (element.parentNode && (!element.tagName ||
2230 - (element.tagName.toUpperCase() != tagName.toUpperCase())))
2231 - element = element.parentNode;
2232 - return element;
2233 - },
2234 -
2235 - observers: false,
2236 -
2237 - _observeAndCache: function(element, name, observer, useCapture) {
2238 - if (!this.observers) this.observers = [];
2239 - if (element.addEventListener) {
2240 - this.observers.push([element, name, observer, useCapture]);
2241 - element.addEventListener(name, observer, useCapture);
2242 - } else if (element.attachEvent) {
2243 - this.observers.push([element, name, observer, useCapture]);
2244 - element.attachEvent('on' + name, observer);
2245 - }
2246 - },
2247 -
2248 - unloadCache: function() {
2249 - if (!Event.observers) return;
2250 - for (var i = 0, length = Event.observers.length; i < length; i++) {
2251 - Event.stopObserving.apply(this, Event.observers[i]);
2252 - Event.observers[i][0] = null;
2253 - }
2254 - Event.observers = false;
2255 - },
2256 -
2257 - observe: function(element, name, observer, useCapture) {
2258 - element = $(element);
2259 - useCapture = useCapture || false;
2260 -
2261 - if (name == 'keypress' &&
2262 - (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
2263 - || element.attachEvent))
2264 - name = 'keydown';
2265 -
2266 - Event._observeAndCache(element, name, observer, useCapture);
2267 - },
2268 -
2269 - stopObserving: function(element, name, observer, useCapture) {
2270 - element = $(element);
2271 - useCapture = useCapture || false;
2272 -
2273 - if (name == 'keypress' &&
2274 - (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
2275 - || element.detachEvent))
2276 - name = 'keydown';
2277 -
2278 - if (element.removeEventListener) {
2279 - element.removeEventListener(name, observer, useCapture);
2280 - } else if (element.detachEvent) {
2281 - try {
2282 - element.detachEvent('on' + name, observer);
2283 - } catch (e) {}
2284 - }
2285 - }
2286 - });
2287 -
2288 - /* prevent memory leaks in IE */
2289 - if (navigator.appVersion.match(/\bMSIE\b/))
2290 - Event.observe(window, 'unload', Event.unloadCache, false);
2291 - var Position = {
2292 - // set to true if needed, warning: firefox performance problems
2293 - // NOT neeeded for page scrolling, only if draggable contained in
2294 - // scrollable elements
2295 - includeScrollOffsets: false,
2296 -
2297 - // must be called before calling withinIncludingScrolloffset, every time the
2298 - // page is scrolled
2299 - prepare: function() {
2300 - this.deltaX = window.pageXOffset
2301 - || document.documentElement.scrollLeft
2302 - || document.body.scrollLeft
2303 - || 0;
2304 - this.deltaY = window.pageYOffset
2305 - || document.documentElement.scrollTop
2306 - || document.body.scrollTop
2307 - || 0;
2308 - },
2309 -
2310 - realOffset: function(element) {
2311 - var valueT = 0, valueL = 0;
2312 - do {
2313 - valueT += element.scrollTop || 0;
2314 - valueL += element.scrollLeft || 0;
2315 - element = element.parentNode;
2316 - } while (element);
2317 - return [valueL, valueT];
2318 - },
2319 -
2320 - cumulativeOffset: function(element) {
2321 - var valueT = 0, valueL = 0;
2322 - do {
2323 - valueT += element.offsetTop || 0;
2324 - valueL += element.offsetLeft || 0;
2325 - element = element.offsetParent;
2326 - } while (element);
2327 - return [valueL, valueT];
2328 - },
2329 -
2330 - positionedOffset: function(element) {
2331 - var valueT = 0, valueL = 0;
2332 - do {
2333 - valueT += element.offsetTop || 0;
2334 - valueL += element.offsetLeft || 0;
2335 - element = element.offsetParent;
2336 - if (element) {
2337 - if(element.tagName=='BODY') break;
2338 - var p = Element.getStyle(element, 'position');
2339 - if (p == 'relative' || p == 'absolute') break;
2340 - }
2341 - } while (element);
2342 - return [valueL, valueT];
2343 - },
2344 -
2345 - offsetParent: function(element) {
2346 - if (element.offsetParent) return element.offsetParent;
2347 - if (element == document.body) return element;
2348 -
2349 - while ((element = element.parentNode) && element != document.body)
2350 - if (Element.getStyle(element, 'position') != 'static')
2351 - return element;
2352 -
2353 - return document.body;
2354 - },
2355 -
2356 - // caches x/y coordinate pair to use with overlap
2357 - within: function(element, x, y) {
2358 - if (this.includeScrollOffsets)
2359 - return this.withinIncludingScrolloffsets(element, x, y);
2360 - this.xcomp = x;
2361 - this.ycomp = y;
2362 - this.offset = this.cumulativeOffset(element);
2363 -
2364 - return (y >= this.offset[1] &&
2365 - y < this.offset[1] + element.offsetHeight &&
2366 - x >= this.offset[0] &&
2367 - x < this.offset[0] + element.offsetWidth);
2368 - },
2369 -
2370 - withinIncludingScrolloffsets: function(element, x, y) {
2371 - var offsetcache = this.realOffset(element);
2372 -
2373 - this.xcomp = x + offsetcache[0] - this.deltaX;
2374 - this.ycomp = y + offsetcache[1] - this.deltaY;
2375 - this.offset = this.cumulativeOffset(element);
2376 -
2377 - return (this.ycomp >= this.offset[1] &&
2378 - this.ycomp < this.offset[1] + element.offsetHeight &&
2379 - this.xcomp >= this.offset[0] &&
2380 - this.xcomp < this.offset[0] + element.offsetWidth);
2381 - },
2382 -
2383 - // within must be called directly before
2384 - overlap: function(mode, element) {
2385 - if (!mode) return 0;
2386 - if (mode == 'vertical')
2387 - return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
2388 - element.offsetHeight;
2389 - if (mode == 'horizontal')
2390 - return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
2391 - element.offsetWidth;
2392 - },
2393 -
2394 - page: function(forElement) {
2395 - var valueT = 0, valueL = 0;
2396 -
2397 - var element = forElement;
2398 - do {
2399 - valueT += element.offsetTop || 0;
2400 - valueL += element.offsetLeft || 0;
2401 -
2402 - // Safari fix
2403 - if (element.offsetParent==document.body)
2404 - if (Element.getStyle(element,'position')=='absolute') break;
2405 -
2406 - } while (element = element.offsetParent);
2407 -
2408 - element = forElement;
2409 - do {
2410 - if (!window.opera || element.tagName=='BODY') {
2411 - valueT -= element.scrollTop || 0;
2412 - valueL -= element.scrollLeft || 0;
2413 - }
2414 - } while (element = element.parentNode);
2415 -
2416 - return [valueL, valueT];
2417 - },
2418 -
2419 - clone: function(source, target) {
2420 - var options = Object.extend({
2421 - setLeft: true,
2422 - setTop: true,
2423 - setWidth: true,
2424 - setHeight: true,
2425 - offsetTop: 0,
2426 - offsetLeft: 0
2427 - }, arguments[2] || {})
2428 -
2429 - // find page position of source
2430 - source = $(source);
2431 - var p = Position.page(source);
2432 -
2433 - // find coordinate system to use
2434 - target = $(target);
2435 - var delta = [0, 0];
2436 - var parent = null;
2437 - // delta [0,0] will do fine with position: fixed elements,
2438 - // position:absolute needs offsetParent deltas
2439 - if (Element.getStyle(target,'position') == 'absolute') {
2440 - parent = Position.offsetParent(target);
2441 - delta = Position.page(parent);
2442 - }
2443 -
2444 - // correct by body offsets (fixes Safari)
2445 - if (parent == document.body) {
2446 - delta[0] -= document.body.offsetLeft;
2447 - delta[1] -= document.body.offsetTop;
2448 - }
2449 -
2450 - // set position
2451 - if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
2452 - if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
2453 - if(options.setWidth) target.style.width = source.offsetWidth + 'px';
2454 - if(options.setHeight) target.style.height = source.offsetHeight + 'px';
2455 - },
2456 -
2457 - absolutize: function(element) {
2458 - element = $(element);
2459 - if (element.style.position == 'absolute') return;
2460 - Position.prepare();
2461 -
2462 - var offsets = Position.positionedOffset(element);
2463 - var top = offsets[1];
2464 - var left = offsets[0];
2465 - var width = element.clientWidth;
2466 - var height = element.clientHeight;
2467 -
2468 - element._originalLeft = left - parseFloat(element.style.left || 0);
2469 - element._originalTop = top - parseFloat(element.style.top || 0);
2470 - element._originalWidth = element.style.width;
2471 - element._originalHeight = element.style.height;
2472 -
2473 - element.style.position = 'absolute';
2474 - element.style.top = top + 'px';
2475 - element.style.left = left + 'px';
2476 - element.style.width = width + 'px';
2477 - element.style.height = height + 'px';
2478 - },
2479 -
2480 - relativize: function(element) {
2481 - element = $(element);
2482 - if (element.style.position == 'relative') return;
2483 - Position.prepare();
2484 -
2485 - element.style.position = 'relative';
2486 - var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
2487 - var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
2488 -
2489 - element.style.top = top + 'px';
2490 - element.style.left = left + 'px';
2491 - element.style.height = element._originalHeight;
2492 - element.style.width = element._originalWidth;
2493 - }
2494 - }
2495 -
2496 - // Safari returns margins on body which is incorrect if the child is absolutely
2497 - // positioned. For performance reasons, redefine Position.cumulativeOffset for
2498 - // KHTML/WebKit only.
2499 - if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
2500 - Position.cumulativeOffset = function(element) {
2501 - var valueT = 0, valueL = 0;
2502 - do {
2503 - valueT += element.offsetTop || 0;
2504 - valueL += element.offsetLeft || 0;
2505 - if (element.offsetParent == document.body)
2506 - if (Element.getStyle(element, 'position') == 'absolute') break;
2507 -
2508 - element = element.offsetParent;
2509 - } while (element);
2510 -
2511 - return [valueL, valueT];
2512 - }
2513 - }
2514 -
2515 Element.addMethods(); No newline at end of file
4225 Element.addMethods();
You need to be logged in to leave comments. Login now