taskr 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.txt +0 -0
- data/GPLv3-LICENSE.txt +674 -0
- data/History.txt +0 -0
- data/Manifest.txt +25 -0
- data/README.txt +14 -0
- data/Rakefile +58 -0
- data/bin/taskr +35 -0
- data/bin/taskr-ctl +32 -0
- data/config.example.yml +100 -0
- data/examples/active_resource_client_example.rb +36 -0
- data/examples/php_client_example.php +85 -0
- data/lib/public/prototype.js +3271 -0
- data/lib/public/taskr.css +45 -0
- data/lib/taskr.rb +83 -0
- data/lib/taskr/actions.rb +230 -0
- data/lib/taskr/controllers.rb +164 -0
- data/lib/taskr/environment.rb +48 -0
- data/lib/taskr/helpers.rb +79 -0
- data/lib/taskr/models.rb +238 -0
- data/lib/taskr/version.rb +9 -0
- data/lib/taskr/views.rb +276 -0
- data/setup.rb +1585 -0
- data/test.rb +3 -0
- data/test/taskr_test.rb +11 -0
- data/test/test_helper.rb +2 -0
- metadata +102 -0
data/History.txt
ADDED
File without changes
|
data/Manifest.txt
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
CHANGELOG.txt
|
2
|
+
GPLv3-LICENSE.txt
|
3
|
+
History.txt
|
4
|
+
Manifest.txt
|
5
|
+
README.txt
|
6
|
+
Rakefile
|
7
|
+
bin/taskr
|
8
|
+
bin/taskr-ctl
|
9
|
+
config.example.yml
|
10
|
+
examples/active_resource_client_example.rb
|
11
|
+
examples/php_client_example.php
|
12
|
+
lib/public/prototype.js
|
13
|
+
lib/public/taskr.css
|
14
|
+
lib/taskr.rb
|
15
|
+
lib/taskr/actions.rb
|
16
|
+
lib/taskr/controllers.rb
|
17
|
+
lib/taskr/environment.rb
|
18
|
+
lib/taskr/helpers.rb
|
19
|
+
lib/taskr/models.rb
|
20
|
+
lib/taskr/version.rb
|
21
|
+
lib/taskr/views.rb
|
22
|
+
setup.rb
|
23
|
+
test.rb
|
24
|
+
test/taskr_test.rb
|
25
|
+
test/test_helper.rb
|
data/README.txt
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
=== LICENSE ===
|
2
|
+
|
3
|
+
This program is free software: you can redistribute it and/or modify
|
4
|
+
it under the terms of the GNU General Public License as published by
|
5
|
+
the Free Software Foundation, either version 3 of the License, or
|
6
|
+
(at your option) any later version.
|
7
|
+
|
8
|
+
This program is distributed in the hope that it will be useful,
|
9
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
GNU General Public License for more details.
|
12
|
+
|
13
|
+
You should have received a copy of the GNU General Public License
|
14
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
data/Rakefile
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/clean'
|
4
|
+
require 'rake/testtask'
|
5
|
+
require 'rake/packagetask'
|
6
|
+
require 'rake/gempackagetask'
|
7
|
+
require 'rake/rdoctask'
|
8
|
+
require 'rake/contrib/rubyforgepublisher'
|
9
|
+
require 'fileutils'
|
10
|
+
require 'hoe'
|
11
|
+
include FileUtils
|
12
|
+
require File.join(File.dirname(__FILE__), 'lib', 'taskr', 'version')
|
13
|
+
|
14
|
+
AUTHOR = "URBACON\mzukowski" # can also be an array of Authors
|
15
|
+
EMAIL = "your contact email for bug fixes and info"
|
16
|
+
DESCRIPTION = "description of gem"
|
17
|
+
GEM_NAME = "taskr" # what ppl will type to install your gem
|
18
|
+
RUBYFORGE_PROJECT = "taskr" # The unix name for your project
|
19
|
+
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
20
|
+
|
21
|
+
|
22
|
+
NAME = "taskr"
|
23
|
+
REV = nil
|
24
|
+
#REV = `svn info`[/Revision: (\d+)/, 1] rescue nil
|
25
|
+
VERS = ENV['VERSION'] || (Taskr::VERSION::STRING + (REV ? ".#{REV}" : ""))
|
26
|
+
CLEAN.include ['**/.*.sw?', '*.gem', '.config']
|
27
|
+
RDOC_OPTS = ['--quiet', '--title', "taskr documentation",
|
28
|
+
"--opname", "index.html",
|
29
|
+
"--line-numbers",
|
30
|
+
"--main", "README",
|
31
|
+
"--inline-source"]
|
32
|
+
|
33
|
+
class Hoe
|
34
|
+
def extra_deps
|
35
|
+
@extra_deps.reject { |x| Array(x).first == 'hoe' }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Generate all the Rake tasks
|
40
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
41
|
+
hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
42
|
+
p.author = AUTHOR
|
43
|
+
p.description = DESCRIPTION
|
44
|
+
p.email = EMAIL
|
45
|
+
p.summary = DESCRIPTION
|
46
|
+
p.url = HOMEPATH
|
47
|
+
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
48
|
+
p.test_globs = ["test/**/*_test.rb"]
|
49
|
+
p.clean_globs = CLEAN #An array of file patterns to delete on clean.
|
50
|
+
|
51
|
+
# == Optional
|
52
|
+
#p.changes - A description of the release's latest changes.
|
53
|
+
#p.extra_deps - An array of rubygem dependencies.
|
54
|
+
#p.spec_extras - A hash of extra values to set in the gemspec.
|
55
|
+
|
56
|
+
p.extra_deps = ['picnic', ['reststop', '~>0.2.0'], 'openwferu-scheduler']
|
57
|
+
p.spec_extras = {:executables => ['taskr', 'taskr-ctl']}
|
58
|
+
end
|
data/bin/taskr
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# ---------------------------------------------------------------------
|
4
|
+
# This file is part of Taskr (http://ruby-taskr.googlecode.com/).
|
5
|
+
#
|
6
|
+
# Taskr is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# Taskr is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with Taskr. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
# ---------------------------------------------------------------------
|
19
|
+
|
20
|
+
if File.exists?(picnic = File.expand_path(File.dirname(File.expand_path(__FILE__))+'/../vendor/picnic/lib'))
|
21
|
+
$: << picnic
|
22
|
+
elsif File.exists?(picnic = File.expand_path(File.dirname(File.expand_path(__FILE__))+'/../../picnic/lib'))
|
23
|
+
$: << picnic
|
24
|
+
else
|
25
|
+
require 'rubygems'
|
26
|
+
end
|
27
|
+
|
28
|
+
require 'picnic/cli'
|
29
|
+
|
30
|
+
cli = Picnic::Cli.new(
|
31
|
+
'taskr',
|
32
|
+
:app_path => File.expand_path(File.dirname(File.expand_path(__FILE__)))
|
33
|
+
)
|
34
|
+
|
35
|
+
cli.handle_cli_input
|
data/bin/taskr-ctl
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# ---------------------------------------------------------------------
|
4
|
+
# This file is part of Taskr (http://ruby-taskr.googlecode.com/).
|
5
|
+
#
|
6
|
+
# Taskr is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later verTaskr
|
10
|
+
#
|
11
|
+
# Taskr is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with Taskr. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
# ---------------------------------------------------------------------
|
19
|
+
|
20
|
+
if File.exists?(picnic = File.expand_path(File.dirname(File.expand_path(__FILE__))+'/../vendor/picnic/lib'))
|
21
|
+
$: << picnic
|
22
|
+
elsif File.exists?(picnic = File.expand_path(File.dirname(File.expand_path(__FILE__))+'/../../picnic/lib'))
|
23
|
+
$: << picnic
|
24
|
+
else
|
25
|
+
require 'rubygems'
|
26
|
+
end
|
27
|
+
|
28
|
+
require 'picnic/service_control'
|
29
|
+
|
30
|
+
ctl = Picnic::ServiceControl.new('taskr')
|
31
|
+
|
32
|
+
ctl.handle_cli_input
|
data/config.example.yml
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
# This is a configuration file for the Taskr RESTful scheduler daemon.
|
2
|
+
|
3
|
+
# AN IMPORTANT NOTE ABOUT YAML CONFIGURATION FILES:
|
4
|
+
# !!! Be sure to use spaces instead of tabs for indentation, as YAML is very
|
5
|
+
# !!! sensitive to white-space inconsistencies!
|
6
|
+
|
7
|
+
##### HTTP SERVER #####################################################################
|
8
|
+
|
9
|
+
# Under what HTTP environment are you running the Fluxr server? The following methods
|
10
|
+
# are currently supported:
|
11
|
+
#
|
12
|
+
# webrick -- simple stand-alone HTTP server; this is the default method
|
13
|
+
# mongrel -- fast stand-alone HTTP server; much faster than webrick, but
|
14
|
+
# you'll have to first install the mongrel gem
|
15
|
+
#
|
16
|
+
|
17
|
+
### webrick example
|
18
|
+
|
19
|
+
server: webrick
|
20
|
+
port: 7007
|
21
|
+
|
22
|
+
### webrick SSL example
|
23
|
+
|
24
|
+
#server: webrick
|
25
|
+
#port: 443
|
26
|
+
#ssl_cert: /path/to/your/ssl.pem
|
27
|
+
|
28
|
+
# if the private key is separate from cert:
|
29
|
+
#ssl_key: /path/to/your/private_key.pem
|
30
|
+
|
31
|
+
|
32
|
+
### mongrel example
|
33
|
+
|
34
|
+
#server: mongrel
|
35
|
+
#port: 7007
|
36
|
+
|
37
|
+
# It is possible to run mongrel over SSL, but you will need to use a reverse proxy
|
38
|
+
# (try Pound or Apache).
|
39
|
+
|
40
|
+
|
41
|
+
##### DATABASE ########################################################################
|
42
|
+
|
43
|
+
# Taskr needs a database to persist its state between restarts.
|
44
|
+
#
|
45
|
+
# By default, we use MySQL, since it is widely used and does not require any additional
|
46
|
+
# ruby libraries besides ActiveRecord.
|
47
|
+
#
|
48
|
+
# With MySQL, your config would be something like the following:
|
49
|
+
# (be sure to create the taskr database in MySQL beforehand,
|
50
|
+
# i.e. `mysqladmin -u root create taskr`)
|
51
|
+
|
52
|
+
database:
|
53
|
+
adapter: mysql
|
54
|
+
database: taskr
|
55
|
+
username: root
|
56
|
+
password:
|
57
|
+
host: localhost
|
58
|
+
|
59
|
+
|
60
|
+
# Instead of MySQL you can use SQLite3, PostgreSQL, MSSQL, or anything else supported
|
61
|
+
# by ActiveRecord.
|
62
|
+
#
|
63
|
+
# If you do not have a database server available, you can try using the SQLite3
|
64
|
+
# back-end. SQLite3 does not require it's own server. Instead all data is stored
|
65
|
+
# in local files. For SQLite3, your configuration would look something like the
|
66
|
+
# following (don't forget to install the 'sqlite3-ruby' gem first!):
|
67
|
+
#
|
68
|
+
#database:
|
69
|
+
# adapter: sqlite3
|
70
|
+
# dbfile: /var/lib/taskr.db
|
71
|
+
|
72
|
+
|
73
|
+
##### AUTHENTICATION ##################################################################
|
74
|
+
|
75
|
+
# Taskr supports basic HTTP authentication. Uncomment this if you want Taskr to demand
|
76
|
+
# a username and password from clients. Note that this isn't very secure unless
|
77
|
+
# you run Taskr over HTTPS (see the webrick SSL example above).
|
78
|
+
|
79
|
+
#authentication:
|
80
|
+
# username: taskr
|
81
|
+
# password: task!
|
82
|
+
|
83
|
+
|
84
|
+
##### LOGGING #########################################################################
|
85
|
+
|
86
|
+
# This log is where you'll want to look in case of problems.
|
87
|
+
#
|
88
|
+
# By default, we will try to create a log file named 'taskr.log' in the current
|
89
|
+
# directory (the directory where you're running taskr from). A better place to put
|
90
|
+
# the log is in /var/log, but you will have to run taskr as root or otherwise give
|
91
|
+
# it permissions.
|
92
|
+
#
|
93
|
+
# Set the level to DEBUG if you want more detailed logging. Other options are
|
94
|
+
# INFO, WARN, and ERROR (DEBUG is most verbose, ERROR is least).
|
95
|
+
|
96
|
+
log:
|
97
|
+
file: taskr.log
|
98
|
+
level: DEBUG
|
99
|
+
# file: /var/log/taskr.log
|
100
|
+
# level: INFO
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'active_resource'
|
2
|
+
|
3
|
+
# Define the proxy class
|
4
|
+
class Task < ActiveResource::Base
|
5
|
+
self.site = 'http://taskr.example.com'
|
6
|
+
end
|
7
|
+
|
8
|
+
# Retrieve a list of all the Tasks
|
9
|
+
tasks = Task.find(:all)
|
10
|
+
|
11
|
+
# Print each Task's details for debugging
|
12
|
+
tasks.each {|t| puts t.inspect}
|
13
|
+
|
14
|
+
# Retrieve a specific Task
|
15
|
+
task = Task.find(123)
|
16
|
+
|
17
|
+
# Print the Task's name
|
18
|
+
puts task.name
|
19
|
+
|
20
|
+
# Create a new Task to be executed every 10 seconds
|
21
|
+
task = Task.new
|
22
|
+
task.name = "My Example Task"
|
23
|
+
task.schedule_method = 'every'
|
24
|
+
task.schedule_when = '10s'
|
25
|
+
task.actions = [
|
26
|
+
{:action_class_name => 'Ruby', :code => "puts 'Hello World!'"},
|
27
|
+
{:action_class_name => 'Ruby', :code => "puts 'Goodbye!'"}
|
28
|
+
]
|
29
|
+
|
30
|
+
# Save the new Task -- the Task is not scheduled for execution until
|
31
|
+
# it is saved.
|
32
|
+
task.save
|
33
|
+
|
34
|
+
# Deleting a task
|
35
|
+
id = 123
|
36
|
+
Task.delete(id)
|
@@ -0,0 +1,85 @@
|
|
1
|
+
<?php
|
2
|
+
|
3
|
+
/**
|
4
|
+
To use this exmple, you will need the Zend Framework from:
|
5
|
+
|
6
|
+
http://framework.zend.com/download
|
7
|
+
|
8
|
+
For more information on using the Zendr_Rest_Client, see:
|
9
|
+
|
10
|
+
- http://framework.zend.com/manual/en/zend.rest.client.html
|
11
|
+
- http://www.pixelated-dreams.com/archives/243-Next-Generation-REST-Web-Services-Client.html
|
12
|
+
**/
|
13
|
+
|
14
|
+
require 'Zend/Rest/Client.php';
|
15
|
+
|
16
|
+
$taskr_site_url = "http://localhost:7007";
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
/**
|
21
|
+
Retreiving the list of all scheduled Tasks
|
22
|
+
**/
|
23
|
+
|
24
|
+
$rest = new Zend_Rest_Client($taskr_site_url);
|
25
|
+
$tasks = $rest->get("/tasks.xml");
|
26
|
+
|
27
|
+
// $tasks is a SimpleXml object, so calling print_r($result) will let
|
28
|
+
// you see all of its data.
|
29
|
+
//
|
30
|
+
// Here's an example of how to print out all of the tasks as an HTML list:
|
31
|
+
|
32
|
+
echo "<ul>";
|
33
|
+
foreach ($tasks->task as $task) {
|
34
|
+
echo "<li>".$task->name."</li>";
|
35
|
+
echo "<ul>";
|
36
|
+
echo "<li>execute ".$task->{'schedule-method'}." ".$task->{'schedule-when'}."</li>";
|
37
|
+
echo "<li>created by ".$task->{'created-by'}." on ".$task->{'created-on'}."</li>";
|
38
|
+
}
|
39
|
+
echo "</ul>";
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
/**
|
44
|
+
Retreiving a specific task
|
45
|
+
**/
|
46
|
+
|
47
|
+
$id = 6;
|
48
|
+
$rest = new Zend_Rest_Client($taskr_site_url);
|
49
|
+
$task = $rest->get("/tasks/$id.xml");
|
50
|
+
|
51
|
+
// print the Task's name
|
52
|
+
echo $task->name;
|
53
|
+
// print the type of the first action in this task
|
54
|
+
echo $task->{'task-actions'}->{'task-action'}[0]->{'action-class-name'};
|
55
|
+
|
56
|
+
|
57
|
+
/**
|
58
|
+
Creating a new task, to be executed every 10 seconds
|
59
|
+
**/
|
60
|
+
|
61
|
+
$data = array(
|
62
|
+
'name' => "My Example Task",
|
63
|
+
'schedule_method' => "every",
|
64
|
+
'schedule_when' => "10s",
|
65
|
+
'actions' => array(
|
66
|
+
array('action_class_name' => "Ruby",
|
67
|
+
'code' => 'puts "Hello World!"'),
|
68
|
+
array('action_class_name' => "Ruby",
|
69
|
+
'code' => 'puts "Goodbye!"')
|
70
|
+
)
|
71
|
+
);
|
72
|
+
|
73
|
+
$rest = new Zend_Rest_Client($taskr_site_url);
|
74
|
+
$rest->post('/tasks.xml', $data);
|
75
|
+
|
76
|
+
|
77
|
+
/**
|
78
|
+
Deleting a task
|
79
|
+
**/
|
80
|
+
|
81
|
+
$id = 6;
|
82
|
+
$rest = new Zend_Rest_Client($taskr_site_url);
|
83
|
+
$task = $rest->delete("/tasks/$id.xml");
|
84
|
+
|
85
|
+
?>
|
@@ -0,0 +1,3271 @@
|
|
1
|
+
/* Prototype JavaScript framework, version 1.5.1
|
2
|
+
* (c) 2005-2007 Sam Stephenson
|
3
|
+
*
|
4
|
+
* Prototype is freely distributable under the terms of an MIT-style license.
|
5
|
+
* For details, see the Prototype web site: http://www.prototypejs.org/
|
6
|
+
*
|
7
|
+
/*--------------------------------------------------------------------------*/
|
8
|
+
|
9
|
+
var Prototype = {
|
10
|
+
Version: '1.5.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
|
+
},
|
18
|
+
|
19
|
+
BrowserFeatures: {
|
20
|
+
XPath: !!document.evaluate,
|
21
|
+
ElementExtensions: !!window.HTMLElement,
|
22
|
+
SpecificElementExtensions:
|
23
|
+
(document.createElement('div').__proto__ !==
|
24
|
+
document.createElement('form').__proto__)
|
25
|
+
},
|
26
|
+
|
27
|
+
ScriptFragment: '<script[^>]*>([\u0001-\uFFFF]*?)</script>',
|
28
|
+
JSONFilter: /^\/\*-secure-\s*(.*)\s*\*\/\s*$/,
|
29
|
+
|
30
|
+
emptyFunction: function() { },
|
31
|
+
K: function(x) { return x }
|
32
|
+
}
|
33
|
+
|
34
|
+
var Class = {
|
35
|
+
create: function() {
|
36
|
+
return function() {
|
37
|
+
this.initialize.apply(this, arguments);
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
var Abstract = new Object();
|
43
|
+
|
44
|
+
Object.extend = function(destination, source) {
|
45
|
+
for (var property in source) {
|
46
|
+
destination[property] = source[property];
|
47
|
+
}
|
48
|
+
return destination;
|
49
|
+
}
|
50
|
+
|
51
|
+
Object.extend(Object, {
|
52
|
+
inspect: function(object) {
|
53
|
+
try {
|
54
|
+
if (object === undefined) return 'undefined';
|
55
|
+
if (object === null) return 'null';
|
56
|
+
return object.inspect ? object.inspect() : object.toString();
|
57
|
+
} catch (e) {
|
58
|
+
if (e instanceof RangeError) return '...';
|
59
|
+
throw e;
|
60
|
+
}
|
61
|
+
},
|
62
|
+
|
63
|
+
toJSON: function(object) {
|
64
|
+
var type = typeof object;
|
65
|
+
switch(type) {
|
66
|
+
case 'undefined':
|
67
|
+
case 'function':
|
68
|
+
case 'unknown': return;
|
69
|
+
case 'boolean': return object.toString();
|
70
|
+
}
|
71
|
+
if (object === null) return 'null';
|
72
|
+
if (object.toJSON) return object.toJSON();
|
73
|
+
if (object.ownerDocument === document) return;
|
74
|
+
var results = [];
|
75
|
+
for (var property in object) {
|
76
|
+
var value = Object.toJSON(object[property]);
|
77
|
+
if (value !== undefined)
|
78
|
+
results.push(property.toJSON() + ': ' + value);
|
79
|
+
}
|
80
|
+
return '{' + results.join(', ') + '}';
|
81
|
+
},
|
82
|
+
|
83
|
+
keys: function(object) {
|
84
|
+
var keys = [];
|
85
|
+
for (var property in object)
|
86
|
+
keys.push(property);
|
87
|
+
return keys;
|
88
|
+
},
|
89
|
+
|
90
|
+
values: function(object) {
|
91
|
+
var values = [];
|
92
|
+
for (var property in object)
|
93
|
+
values.push(object[property]);
|
94
|
+
return values;
|
95
|
+
},
|
96
|
+
|
97
|
+
clone: function(object) {
|
98
|
+
return Object.extend({}, object);
|
99
|
+
}
|
100
|
+
});
|
101
|
+
|
102
|
+
Function.prototype.bind = function() {
|
103
|
+
var __method = this, args = $A(arguments), object = args.shift();
|
104
|
+
return function() {
|
105
|
+
return __method.apply(object, args.concat($A(arguments)));
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
Function.prototype.bindAsEventListener = function(object) {
|
110
|
+
var __method = this, args = $A(arguments), object = args.shift();
|
111
|
+
return function(event) {
|
112
|
+
return __method.apply(object, [event || window.event].concat(args));
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
116
|
+
Object.extend(Number.prototype, {
|
117
|
+
toColorPart: function() {
|
118
|
+
return this.toPaddedString(2, 16);
|
119
|
+
},
|
120
|
+
|
121
|
+
succ: function() {
|
122
|
+
return this + 1;
|
123
|
+
},
|
124
|
+
|
125
|
+
times: function(iterator) {
|
126
|
+
$R(0, this, true).each(iterator);
|
127
|
+
return this;
|
128
|
+
},
|
129
|
+
|
130
|
+
toPaddedString: function(length, radix) {
|
131
|
+
var string = this.toString(radix || 10);
|
132
|
+
return '0'.times(length - string.length) + string;
|
133
|
+
},
|
134
|
+
|
135
|
+
toJSON: function() {
|
136
|
+
return isFinite(this) ? this.toString() : 'null';
|
137
|
+
}
|
138
|
+
});
|
139
|
+
|
140
|
+
Date.prototype.toJSON = function() {
|
141
|
+
return '"' + this.getFullYear() + '-' +
|
142
|
+
(this.getMonth() + 1).toPaddedString(2) + '-' +
|
143
|
+
this.getDate().toPaddedString(2) + 'T' +
|
144
|
+
this.getHours().toPaddedString(2) + ':' +
|
145
|
+
this.getMinutes().toPaddedString(2) + ':' +
|
146
|
+
this.getSeconds().toPaddedString(2) + '"';
|
147
|
+
};
|
148
|
+
|
149
|
+
var Try = {
|
150
|
+
these: function() {
|
151
|
+
var returnValue;
|
152
|
+
|
153
|
+
for (var i = 0, length = arguments.length; i < length; i++) {
|
154
|
+
var lambda = arguments[i];
|
155
|
+
try {
|
156
|
+
returnValue = lambda();
|
157
|
+
break;
|
158
|
+
} catch (e) {}
|
159
|
+
}
|
160
|
+
|
161
|
+
return returnValue;
|
162
|
+
}
|
163
|
+
}
|
164
|
+
|
165
|
+
/*--------------------------------------------------------------------------*/
|
166
|
+
|
167
|
+
var PeriodicalExecuter = Class.create();
|
168
|
+
PeriodicalExecuter.prototype = {
|
169
|
+
initialize: function(callback, frequency) {
|
170
|
+
this.callback = callback;
|
171
|
+
this.frequency = frequency;
|
172
|
+
this.currentlyExecuting = false;
|
173
|
+
|
174
|
+
this.registerCallback();
|
175
|
+
},
|
176
|
+
|
177
|
+
registerCallback: function() {
|
178
|
+
this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
|
179
|
+
},
|
180
|
+
|
181
|
+
stop: function() {
|
182
|
+
if (!this.timer) return;
|
183
|
+
clearInterval(this.timer);
|
184
|
+
this.timer = null;
|
185
|
+
},
|
186
|
+
|
187
|
+
onTimerEvent: function() {
|
188
|
+
if (!this.currentlyExecuting) {
|
189
|
+
try {
|
190
|
+
this.currentlyExecuting = true;
|
191
|
+
this.callback(this);
|
192
|
+
} finally {
|
193
|
+
this.currentlyExecuting = false;
|
194
|
+
}
|
195
|
+
}
|
196
|
+
}
|
197
|
+
}
|
198
|
+
Object.extend(String, {
|
199
|
+
interpret: function(value) {
|
200
|
+
return value == null ? '' : String(value);
|
201
|
+
},
|
202
|
+
specialChar: {
|
203
|
+
'\b': '\\b',
|
204
|
+
'\t': '\\t',
|
205
|
+
'\n': '\\n',
|
206
|
+
'\f': '\\f',
|
207
|
+
'\r': '\\r',
|
208
|
+
'\\': '\\\\'
|
209
|
+
}
|
210
|
+
});
|
211
|
+
|
212
|
+
Object.extend(String.prototype, {
|
213
|
+
gsub: function(pattern, replacement) {
|
214
|
+
var result = '', source = this, match;
|
215
|
+
replacement = arguments.callee.prepareReplacement(replacement);
|
216
|
+
|
217
|
+
while (source.length > 0) {
|
218
|
+
if (match = source.match(pattern)) {
|
219
|
+
result += source.slice(0, match.index);
|
220
|
+
result += String.interpret(replacement(match));
|
221
|
+
source = source.slice(match.index + match[0].length);
|
222
|
+
} else {
|
223
|
+
result += source, source = '';
|
224
|
+
}
|
225
|
+
}
|
226
|
+
return result;
|
227
|
+
},
|
228
|
+
|
229
|
+
sub: function(pattern, replacement, count) {
|
230
|
+
replacement = this.gsub.prepareReplacement(replacement);
|
231
|
+
count = count === undefined ? 1 : count;
|
232
|
+
|
233
|
+
return this.gsub(pattern, function(match) {
|
234
|
+
if (--count < 0) return match[0];
|
235
|
+
return replacement(match);
|
236
|
+
});
|
237
|
+
},
|
238
|
+
|
239
|
+
scan: function(pattern, iterator) {
|
240
|
+
this.gsub(pattern, iterator);
|
241
|
+
return this;
|
242
|
+
},
|
243
|
+
|
244
|
+
truncate: function(length, truncation) {
|
245
|
+
length = length || 30;
|
246
|
+
truncation = truncation === undefined ? '...' : truncation;
|
247
|
+
return this.length > length ?
|
248
|
+
this.slice(0, length - truncation.length) + truncation : this;
|
249
|
+
},
|
250
|
+
|
251
|
+
strip: function() {
|
252
|
+
return this.replace(/^\s+/, '').replace(/\s+$/, '');
|
253
|
+
},
|
254
|
+
|
255
|
+
stripTags: function() {
|
256
|
+
return this.replace(/<\/?[^>]+>/gi, '');
|
257
|
+
},
|
258
|
+
|
259
|
+
stripScripts: function() {
|
260
|
+
return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
|
261
|
+
},
|
262
|
+
|
263
|
+
extractScripts: function() {
|
264
|
+
var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
|
265
|
+
var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
|
266
|
+
return (this.match(matchAll) || []).map(function(scriptTag) {
|
267
|
+
return (scriptTag.match(matchOne) || ['', ''])[1];
|
268
|
+
});
|
269
|
+
},
|
270
|
+
|
271
|
+
evalScripts: function() {
|
272
|
+
return this.extractScripts().map(function(script) { return eval(script) });
|
273
|
+
},
|
274
|
+
|
275
|
+
escapeHTML: function() {
|
276
|
+
var self = arguments.callee;
|
277
|
+
self.text.data = this;
|
278
|
+
return self.div.innerHTML;
|
279
|
+
},
|
280
|
+
|
281
|
+
unescapeHTML: function() {
|
282
|
+
var div = document.createElement('div');
|
283
|
+
div.innerHTML = this.stripTags();
|
284
|
+
return div.childNodes[0] ? (div.childNodes.length > 1 ?
|
285
|
+
$A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
|
286
|
+
div.childNodes[0].nodeValue) : '';
|
287
|
+
},
|
288
|
+
|
289
|
+
toQueryParams: function(separator) {
|
290
|
+
var match = this.strip().match(/([^?#]*)(#.*)?$/);
|
291
|
+
if (!match) return {};
|
292
|
+
|
293
|
+
return match[1].split(separator || '&').inject({}, function(hash, pair) {
|
294
|
+
if ((pair = pair.split('='))[0]) {
|
295
|
+
var key = decodeURIComponent(pair.shift());
|
296
|
+
var value = pair.length > 1 ? pair.join('=') : pair[0];
|
297
|
+
if (value != undefined) value = decodeURIComponent(value);
|
298
|
+
|
299
|
+
if (key in hash) {
|
300
|
+
if (hash[key].constructor != Array) hash[key] = [hash[key]];
|
301
|
+
hash[key].push(value);
|
302
|
+
}
|
303
|
+
else hash[key] = value;
|
304
|
+
}
|
305
|
+
return hash;
|
306
|
+
});
|
307
|
+
},
|
308
|
+
|
309
|
+
toArray: function() {
|
310
|
+
return this.split('');
|
311
|
+
},
|
312
|
+
|
313
|
+
succ: function() {
|
314
|
+
return this.slice(0, this.length - 1) +
|
315
|
+
String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
|
316
|
+
},
|
317
|
+
|
318
|
+
times: function(count) {
|
319
|
+
var result = '';
|
320
|
+
for (var i = 0; i < count; i++) result += this;
|
321
|
+
return result;
|
322
|
+
},
|
323
|
+
|
324
|
+
camelize: function() {
|
325
|
+
var parts = this.split('-'), len = parts.length;
|
326
|
+
if (len == 1) return parts[0];
|
327
|
+
|
328
|
+
var camelized = this.charAt(0) == '-'
|
329
|
+
? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
|
330
|
+
: parts[0];
|
331
|
+
|
332
|
+
for (var i = 1; i < len; i++)
|
333
|
+
camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
|
334
|
+
|
335
|
+
return camelized;
|
336
|
+
},
|
337
|
+
|
338
|
+
capitalize: function() {
|
339
|
+
return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
|
340
|
+
},
|
341
|
+
|
342
|
+
underscore: function() {
|
343
|
+
return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
|
344
|
+
},
|
345
|
+
|
346
|
+
dasherize: function() {
|
347
|
+
return this.gsub(/_/,'-');
|
348
|
+
},
|
349
|
+
|
350
|
+
inspect: function(useDoubleQuotes) {
|
351
|
+
var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
|
352
|
+
var character = String.specialChar[match[0]];
|
353
|
+
return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
|
354
|
+
});
|
355
|
+
if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
|
356
|
+
return "'" + escapedString.replace(/'/g, '\\\'') + "'";
|
357
|
+
},
|
358
|
+
|
359
|
+
toJSON: function() {
|
360
|
+
return this.inspect(true);
|
361
|
+
},
|
362
|
+
|
363
|
+
unfilterJSON: function(filter) {
|
364
|
+
return this.sub(filter || Prototype.JSONFilter, '#{1}');
|
365
|
+
},
|
366
|
+
|
367
|
+
evalJSON: function(sanitize) {
|
368
|
+
var json = this.unfilterJSON();
|
369
|
+
try {
|
370
|
+
if (!sanitize || (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(json)))
|
371
|
+
return eval('(' + json + ')');
|
372
|
+
} catch (e) { }
|
373
|
+
throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
|
374
|
+
},
|
375
|
+
|
376
|
+
include: function(pattern) {
|
377
|
+
return this.indexOf(pattern) > -1;
|
378
|
+
},
|
379
|
+
|
380
|
+
startsWith: function(pattern) {
|
381
|
+
return this.indexOf(pattern) === 0;
|
382
|
+
},
|
383
|
+
|
384
|
+
endsWith: function(pattern) {
|
385
|
+
var d = this.length - pattern.length;
|
386
|
+
return d >= 0 && this.lastIndexOf(pattern) === d;
|
387
|
+
},
|
388
|
+
|
389
|
+
empty: function() {
|
390
|
+
return this == '';
|
391
|
+
},
|
392
|
+
|
393
|
+
blank: function() {
|
394
|
+
return /^\s*$/.test(this);
|
395
|
+
}
|
396
|
+
});
|
397
|
+
|
398
|
+
if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
|
399
|
+
escapeHTML: function() {
|
400
|
+
return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
401
|
+
},
|
402
|
+
unescapeHTML: function() {
|
403
|
+
return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
404
|
+
}
|
405
|
+
});
|
406
|
+
|
407
|
+
String.prototype.gsub.prepareReplacement = function(replacement) {
|
408
|
+
if (typeof replacement == 'function') return replacement;
|
409
|
+
var template = new Template(replacement);
|
410
|
+
return function(match) { return template.evaluate(match) };
|
411
|
+
}
|
412
|
+
|
413
|
+
String.prototype.parseQuery = String.prototype.toQueryParams;
|
414
|
+
|
415
|
+
Object.extend(String.prototype.escapeHTML, {
|
416
|
+
div: document.createElement('div'),
|
417
|
+
text: document.createTextNode('')
|
418
|
+
});
|
419
|
+
|
420
|
+
with (String.prototype.escapeHTML) div.appendChild(text);
|
421
|
+
|
422
|
+
var Template = Class.create();
|
423
|
+
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
|
424
|
+
Template.prototype = {
|
425
|
+
initialize: function(template, pattern) {
|
426
|
+
this.template = template.toString();
|
427
|
+
this.pattern = pattern || Template.Pattern;
|
428
|
+
},
|
429
|
+
|
430
|
+
evaluate: function(object) {
|
431
|
+
return this.template.gsub(this.pattern, function(match) {
|
432
|
+
var before = match[1];
|
433
|
+
if (before == '\\') return match[2];
|
434
|
+
return before + String.interpret(object[match[3]]);
|
435
|
+
});
|
436
|
+
}
|
437
|
+
}
|
438
|
+
|
439
|
+
var $break = {}, $continue = new Error('"throw $continue" is deprecated, use "return" instead');
|
440
|
+
|
441
|
+
var Enumerable = {
|
442
|
+
each: function(iterator) {
|
443
|
+
var index = 0;
|
444
|
+
try {
|
445
|
+
this._each(function(value) {
|
446
|
+
iterator(value, index++);
|
447
|
+
});
|
448
|
+
} catch (e) {
|
449
|
+
if (e != $break) throw e;
|
450
|
+
}
|
451
|
+
return this;
|
452
|
+
},
|
453
|
+
|
454
|
+
eachSlice: function(number, iterator) {
|
455
|
+
var index = -number, slices = [], array = this.toArray();
|
456
|
+
while ((index += number) < array.length)
|
457
|
+
slices.push(array.slice(index, index+number));
|
458
|
+
return slices.map(iterator);
|
459
|
+
},
|
460
|
+
|
461
|
+
all: function(iterator) {
|
462
|
+
var result = true;
|
463
|
+
this.each(function(value, index) {
|
464
|
+
result = result && !!(iterator || Prototype.K)(value, index);
|
465
|
+
if (!result) throw $break;
|
466
|
+
});
|
467
|
+
return result;
|
468
|
+
},
|
469
|
+
|
470
|
+
any: function(iterator) {
|
471
|
+
var result = false;
|
472
|
+
this.each(function(value, index) {
|
473
|
+
if (result = !!(iterator || Prototype.K)(value, index))
|
474
|
+
throw $break;
|
475
|
+
});
|
476
|
+
return result;
|
477
|
+
},
|
478
|
+
|
479
|
+
collect: function(iterator) {
|
480
|
+
var results = [];
|
481
|
+
this.each(function(value, index) {
|
482
|
+
results.push((iterator || Prototype.K)(value, index));
|
483
|
+
});
|
484
|
+
return results;
|
485
|
+
},
|
486
|
+
|
487
|
+
detect: function(iterator) {
|
488
|
+
var result;
|
489
|
+
this.each(function(value, index) {
|
490
|
+
if (iterator(value, index)) {
|
491
|
+
result = value;
|
492
|
+
throw $break;
|
493
|
+
}
|
494
|
+
});
|
495
|
+
return result;
|
496
|
+
},
|
497
|
+
|
498
|
+
findAll: function(iterator) {
|
499
|
+
var results = [];
|
500
|
+
this.each(function(value, index) {
|
501
|
+
if (iterator(value, index))
|
502
|
+
results.push(value);
|
503
|
+
});
|
504
|
+
return results;
|
505
|
+
},
|
506
|
+
|
507
|
+
grep: function(pattern, iterator) {
|
508
|
+
var results = [];
|
509
|
+
this.each(function(value, index) {
|
510
|
+
var stringValue = value.toString();
|
511
|
+
if (stringValue.match(pattern))
|
512
|
+
results.push((iterator || Prototype.K)(value, index));
|
513
|
+
})
|
514
|
+
return results;
|
515
|
+
},
|
516
|
+
|
517
|
+
include: function(object) {
|
518
|
+
var found = false;
|
519
|
+
this.each(function(value) {
|
520
|
+
if (value == object) {
|
521
|
+
found = true;
|
522
|
+
throw $break;
|
523
|
+
}
|
524
|
+
});
|
525
|
+
return found;
|
526
|
+
},
|
527
|
+
|
528
|
+
inGroupsOf: function(number, fillWith) {
|
529
|
+
fillWith = fillWith === undefined ? null : fillWith;
|
530
|
+
return this.eachSlice(number, function(slice) {
|
531
|
+
while(slice.length < number) slice.push(fillWith);
|
532
|
+
return slice;
|
533
|
+
});
|
534
|
+
},
|
535
|
+
|
536
|
+
inject: function(memo, iterator) {
|
537
|
+
this.each(function(value, index) {
|
538
|
+
memo = iterator(memo, value, index);
|
539
|
+
});
|
540
|
+
return memo;
|
541
|
+
},
|
542
|
+
|
543
|
+
invoke: function(method) {
|
544
|
+
var args = $A(arguments).slice(1);
|
545
|
+
return this.map(function(value) {
|
546
|
+
return value[method].apply(value, args);
|
547
|
+
});
|
548
|
+
},
|
549
|
+
|
550
|
+
max: function(iterator) {
|
551
|
+
var result;
|
552
|
+
this.each(function(value, index) {
|
553
|
+
value = (iterator || Prototype.K)(value, index);
|
554
|
+
if (result == undefined || value >= result)
|
555
|
+
result = value;
|
556
|
+
});
|
557
|
+
return result;
|
558
|
+
},
|
559
|
+
|
560
|
+
min: function(iterator) {
|
561
|
+
var result;
|
562
|
+
this.each(function(value, index) {
|
563
|
+
value = (iterator || Prototype.K)(value, index);
|
564
|
+
if (result == undefined || value < result)
|
565
|
+
result = value;
|
566
|
+
});
|
567
|
+
return result;
|
568
|
+
},
|
569
|
+
|
570
|
+
partition: function(iterator) {
|
571
|
+
var trues = [], falses = [];
|
572
|
+
this.each(function(value, index) {
|
573
|
+
((iterator || Prototype.K)(value, index) ?
|
574
|
+
trues : falses).push(value);
|
575
|
+
});
|
576
|
+
return [trues, falses];
|
577
|
+
},
|
578
|
+
|
579
|
+
pluck: function(property) {
|
580
|
+
var results = [];
|
581
|
+
this.each(function(value, index) {
|
582
|
+
results.push(value[property]);
|
583
|
+
});
|
584
|
+
return results;
|
585
|
+
},
|
586
|
+
|
587
|
+
reject: function(iterator) {
|
588
|
+
var results = [];
|
589
|
+
this.each(function(value, index) {
|
590
|
+
if (!iterator(value, index))
|
591
|
+
results.push(value);
|
592
|
+
});
|
593
|
+
return results;
|
594
|
+
},
|
595
|
+
|
596
|
+
sortBy: function(iterator) {
|
597
|
+
return this.map(function(value, index) {
|
598
|
+
return {value: value, criteria: iterator(value, index)};
|
599
|
+
}).sort(function(left, right) {
|
600
|
+
var a = left.criteria, b = right.criteria;
|
601
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
602
|
+
}).pluck('value');
|
603
|
+
},
|
604
|
+
|
605
|
+
toArray: function() {
|
606
|
+
return this.map();
|
607
|
+
},
|
608
|
+
|
609
|
+
zip: function() {
|
610
|
+
var iterator = Prototype.K, args = $A(arguments);
|
611
|
+
if (typeof args.last() == 'function')
|
612
|
+
iterator = args.pop();
|
613
|
+
|
614
|
+
var collections = [this].concat(args).map($A);
|
615
|
+
return this.map(function(value, index) {
|
616
|
+
return iterator(collections.pluck(index));
|
617
|
+
});
|
618
|
+
},
|
619
|
+
|
620
|
+
size: function() {
|
621
|
+
return this.toArray().length;
|
622
|
+
},
|
623
|
+
|
624
|
+
inspect: function() {
|
625
|
+
return '#<Enumerable:' + this.toArray().inspect() + '>';
|
626
|
+
}
|
627
|
+
}
|
628
|
+
|
629
|
+
Object.extend(Enumerable, {
|
630
|
+
map: Enumerable.collect,
|
631
|
+
find: Enumerable.detect,
|
632
|
+
select: Enumerable.findAll,
|
633
|
+
member: Enumerable.include,
|
634
|
+
entries: Enumerable.toArray
|
635
|
+
});
|
636
|
+
var $A = Array.from = function(iterable) {
|
637
|
+
if (!iterable) return [];
|
638
|
+
if (iterable.toArray) {
|
639
|
+
return iterable.toArray();
|
640
|
+
} else {
|
641
|
+
var results = [];
|
642
|
+
for (var i = 0, length = iterable.length; i < length; i++)
|
643
|
+
results.push(iterable[i]);
|
644
|
+
return results;
|
645
|
+
}
|
646
|
+
}
|
647
|
+
|
648
|
+
if (Prototype.Browser.WebKit) {
|
649
|
+
$A = Array.from = function(iterable) {
|
650
|
+
if (!iterable) return [];
|
651
|
+
if (!(typeof iterable == 'function' && iterable == '[object NodeList]') &&
|
652
|
+
iterable.toArray) {
|
653
|
+
return iterable.toArray();
|
654
|
+
} else {
|
655
|
+
var results = [];
|
656
|
+
for (var i = 0, length = iterable.length; i < length; i++)
|
657
|
+
results.push(iterable[i]);
|
658
|
+
return results;
|
659
|
+
}
|
660
|
+
}
|
661
|
+
}
|
662
|
+
|
663
|
+
Object.extend(Array.prototype, Enumerable);
|
664
|
+
|
665
|
+
if (!Array.prototype._reverse)
|
666
|
+
Array.prototype._reverse = Array.prototype.reverse;
|
667
|
+
|
668
|
+
Object.extend(Array.prototype, {
|
669
|
+
_each: function(iterator) {
|
670
|
+
for (var i = 0, length = this.length; i < length; i++)
|
671
|
+
iterator(this[i]);
|
672
|
+
},
|
673
|
+
|
674
|
+
clear: function() {
|
675
|
+
this.length = 0;
|
676
|
+
return this;
|
677
|
+
},
|
678
|
+
|
679
|
+
first: function() {
|
680
|
+
return this[0];
|
681
|
+
},
|
682
|
+
|
683
|
+
last: function() {
|
684
|
+
return this[this.length - 1];
|
685
|
+
},
|
686
|
+
|
687
|
+
compact: function() {
|
688
|
+
return this.select(function(value) {
|
689
|
+
return value != null;
|
690
|
+
});
|
691
|
+
},
|
692
|
+
|
693
|
+
flatten: function() {
|
694
|
+
return this.inject([], function(array, value) {
|
695
|
+
return array.concat(value && value.constructor == Array ?
|
696
|
+
value.flatten() : [value]);
|
697
|
+
});
|
698
|
+
},
|
699
|
+
|
700
|
+
without: function() {
|
701
|
+
var values = $A(arguments);
|
702
|
+
return this.select(function(value) {
|
703
|
+
return !values.include(value);
|
704
|
+
});
|
705
|
+
},
|
706
|
+
|
707
|
+
indexOf: function(object) {
|
708
|
+
for (var i = 0, length = this.length; i < length; i++)
|
709
|
+
if (this[i] == object) return i;
|
710
|
+
return -1;
|
711
|
+
},
|
712
|
+
|
713
|
+
reverse: function(inline) {
|
714
|
+
return (inline !== false ? this : this.toArray())._reverse();
|
715
|
+
},
|
716
|
+
|
717
|
+
reduce: function() {
|
718
|
+
return this.length > 1 ? this : this[0];
|
719
|
+
},
|
720
|
+
|
721
|
+
uniq: function(sorted) {
|
722
|
+
return this.inject([], function(array, value, index) {
|
723
|
+
if (0 == index || (sorted ? array.last() != value : !array.include(value)))
|
724
|
+
array.push(value);
|
725
|
+
return array;
|
726
|
+
});
|
727
|
+
},
|
728
|
+
|
729
|
+
clone: function() {
|
730
|
+
return [].concat(this);
|
731
|
+
},
|
732
|
+
|
733
|
+
size: function() {
|
734
|
+
return this.length;
|
735
|
+
},
|
736
|
+
|
737
|
+
inspect: function() {
|
738
|
+
return '[' + this.map(Object.inspect).join(', ') + ']';
|
739
|
+
},
|
740
|
+
|
741
|
+
toJSON: function() {
|
742
|
+
var results = [];
|
743
|
+
this.each(function(object) {
|
744
|
+
var value = Object.toJSON(object);
|
745
|
+
if (value !== undefined) results.push(value);
|
746
|
+
});
|
747
|
+
return '[' + results.join(', ') + ']';
|
748
|
+
}
|
749
|
+
});
|
750
|
+
|
751
|
+
Array.prototype.toArray = Array.prototype.clone;
|
752
|
+
|
753
|
+
function $w(string) {
|
754
|
+
string = string.strip();
|
755
|
+
return string ? string.split(/\s+/) : [];
|
756
|
+
}
|
757
|
+
|
758
|
+
if (Prototype.Browser.Opera){
|
759
|
+
Array.prototype.concat = function() {
|
760
|
+
var array = [];
|
761
|
+
for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
|
762
|
+
for (var i = 0, length = arguments.length; i < length; i++) {
|
763
|
+
if (arguments[i].constructor == Array) {
|
764
|
+
for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
|
765
|
+
array.push(arguments[i][j]);
|
766
|
+
} else {
|
767
|
+
array.push(arguments[i]);
|
768
|
+
}
|
769
|
+
}
|
770
|
+
return array;
|
771
|
+
}
|
772
|
+
}
|
773
|
+
var Hash = function(object) {
|
774
|
+
if (object instanceof Hash) this.merge(object);
|
775
|
+
else Object.extend(this, object || {});
|
776
|
+
};
|
777
|
+
|
778
|
+
Object.extend(Hash, {
|
779
|
+
toQueryString: function(obj) {
|
780
|
+
var parts = [];
|
781
|
+
parts.add = arguments.callee.addPair;
|
782
|
+
|
783
|
+
this.prototype._each.call(obj, function(pair) {
|
784
|
+
if (!pair.key) return;
|
785
|
+
var value = pair.value;
|
786
|
+
|
787
|
+
if (value && typeof value == 'object') {
|
788
|
+
if (value.constructor == Array) value.each(function(value) {
|
789
|
+
parts.add(pair.key, value);
|
790
|
+
});
|
791
|
+
return;
|
792
|
+
}
|
793
|
+
parts.add(pair.key, value);
|
794
|
+
});
|
795
|
+
|
796
|
+
return parts.join('&');
|
797
|
+
},
|
798
|
+
|
799
|
+
toJSON: function(object) {
|
800
|
+
var results = [];
|
801
|
+
this.prototype._each.call(object, function(pair) {
|
802
|
+
var value = Object.toJSON(pair.value);
|
803
|
+
if (value !== undefined) results.push(pair.key.toJSON() + ': ' + value);
|
804
|
+
});
|
805
|
+
return '{' + results.join(', ') + '}';
|
806
|
+
}
|
807
|
+
});
|
808
|
+
|
809
|
+
Hash.toQueryString.addPair = function(key, value, prefix) {
|
810
|
+
key = encodeURIComponent(key);
|
811
|
+
if (value === undefined) this.push(key);
|
812
|
+
else this.push(key + '=' + (value == null ? '' : encodeURIComponent(value)));
|
813
|
+
}
|
814
|
+
|
815
|
+
Object.extend(Hash.prototype, Enumerable);
|
816
|
+
Object.extend(Hash.prototype, {
|
817
|
+
_each: function(iterator) {
|
818
|
+
for (var key in this) {
|
819
|
+
var value = this[key];
|
820
|
+
if (value && value == Hash.prototype[key]) continue;
|
821
|
+
|
822
|
+
var pair = [key, value];
|
823
|
+
pair.key = key;
|
824
|
+
pair.value = value;
|
825
|
+
iterator(pair);
|
826
|
+
}
|
827
|
+
},
|
828
|
+
|
829
|
+
keys: function() {
|
830
|
+
return this.pluck('key');
|
831
|
+
},
|
832
|
+
|
833
|
+
values: function() {
|
834
|
+
return this.pluck('value');
|
835
|
+
},
|
836
|
+
|
837
|
+
merge: function(hash) {
|
838
|
+
return $H(hash).inject(this, function(mergedHash, pair) {
|
839
|
+
mergedHash[pair.key] = pair.value;
|
840
|
+
return mergedHash;
|
841
|
+
});
|
842
|
+
},
|
843
|
+
|
844
|
+
remove: function() {
|
845
|
+
var result;
|
846
|
+
for(var i = 0, length = arguments.length; i < length; i++) {
|
847
|
+
var value = this[arguments[i]];
|
848
|
+
if (value !== undefined){
|
849
|
+
if (result === undefined) result = value;
|
850
|
+
else {
|
851
|
+
if (result.constructor != Array) result = [result];
|
852
|
+
result.push(value)
|
853
|
+
}
|
854
|
+
}
|
855
|
+
delete this[arguments[i]];
|
856
|
+
}
|
857
|
+
return result;
|
858
|
+
},
|
859
|
+
|
860
|
+
toQueryString: function() {
|
861
|
+
return Hash.toQueryString(this);
|
862
|
+
},
|
863
|
+
|
864
|
+
inspect: function() {
|
865
|
+
return '#<Hash:{' + this.map(function(pair) {
|
866
|
+
return pair.map(Object.inspect).join(': ');
|
867
|
+
}).join(', ') + '}>';
|
868
|
+
},
|
869
|
+
|
870
|
+
toJSON: function() {
|
871
|
+
return Hash.toJSON(this);
|
872
|
+
}
|
873
|
+
});
|
874
|
+
|
875
|
+
function $H(object) {
|
876
|
+
if (object instanceof Hash) return object;
|
877
|
+
return new Hash(object);
|
878
|
+
};
|
879
|
+
|
880
|
+
// Safari iterates over shadowed properties
|
881
|
+
if (function() {
|
882
|
+
var i = 0, Test = function(value) { this.key = value };
|
883
|
+
Test.prototype.key = 'foo';
|
884
|
+
for (var property in new Test('bar')) i++;
|
885
|
+
return i > 1;
|
886
|
+
}()) Hash.prototype._each = function(iterator) {
|
887
|
+
var cache = [];
|
888
|
+
for (var key in this) {
|
889
|
+
var value = this[key];
|
890
|
+
if ((value && value == Hash.prototype[key]) || cache.include(key)) continue;
|
891
|
+
cache.push(key);
|
892
|
+
var pair = [key, value];
|
893
|
+
pair.key = key;
|
894
|
+
pair.value = value;
|
895
|
+
iterator(pair);
|
896
|
+
}
|
897
|
+
};
|
898
|
+
ObjectRange = Class.create();
|
899
|
+
Object.extend(ObjectRange.prototype, Enumerable);
|
900
|
+
Object.extend(ObjectRange.prototype, {
|
901
|
+
initialize: function(start, end, exclusive) {
|
902
|
+
this.start = start;
|
903
|
+
this.end = end;
|
904
|
+
this.exclusive = exclusive;
|
905
|
+
},
|
906
|
+
|
907
|
+
_each: function(iterator) {
|
908
|
+
var value = this.start;
|
909
|
+
while (this.include(value)) {
|
910
|
+
iterator(value);
|
911
|
+
value = value.succ();
|
912
|
+
}
|
913
|
+
},
|
914
|
+
|
915
|
+
include: function(value) {
|
916
|
+
if (value < this.start)
|
917
|
+
return false;
|
918
|
+
if (this.exclusive)
|
919
|
+
return value < this.end;
|
920
|
+
return value <= this.end;
|
921
|
+
}
|
922
|
+
});
|
923
|
+
|
924
|
+
var $R = function(start, end, exclusive) {
|
925
|
+
return new ObjectRange(start, end, exclusive);
|
926
|
+
}
|
927
|
+
|
928
|
+
var Ajax = {
|
929
|
+
getTransport: function() {
|
930
|
+
return Try.these(
|
931
|
+
function() {return new XMLHttpRequest()},
|
932
|
+
function() {return new ActiveXObject('Msxml2.XMLHTTP')},
|
933
|
+
function() {return new ActiveXObject('Microsoft.XMLHTTP')}
|
934
|
+
) || false;
|
935
|
+
},
|
936
|
+
|
937
|
+
activeRequestCount: 0
|
938
|
+
}
|
939
|
+
|
940
|
+
Ajax.Responders = {
|
941
|
+
responders: [],
|
942
|
+
|
943
|
+
_each: function(iterator) {
|
944
|
+
this.responders._each(iterator);
|
945
|
+
},
|
946
|
+
|
947
|
+
register: function(responder) {
|
948
|
+
if (!this.include(responder))
|
949
|
+
this.responders.push(responder);
|
950
|
+
},
|
951
|
+
|
952
|
+
unregister: function(responder) {
|
953
|
+
this.responders = this.responders.without(responder);
|
954
|
+
},
|
955
|
+
|
956
|
+
dispatch: function(callback, request, transport, json) {
|
957
|
+
this.each(function(responder) {
|
958
|
+
if (typeof responder[callback] == 'function') {
|
959
|
+
try {
|
960
|
+
responder[callback].apply(responder, [request, transport, json]);
|
961
|
+
} catch (e) {}
|
962
|
+
}
|
963
|
+
});
|
964
|
+
}
|
965
|
+
};
|
966
|
+
|
967
|
+
Object.extend(Ajax.Responders, Enumerable);
|
968
|
+
|
969
|
+
Ajax.Responders.register({
|
970
|
+
onCreate: function() {
|
971
|
+
Ajax.activeRequestCount++;
|
972
|
+
},
|
973
|
+
onComplete: function() {
|
974
|
+
Ajax.activeRequestCount--;
|
975
|
+
}
|
976
|
+
});
|
977
|
+
|
978
|
+
Ajax.Base = function() {};
|
979
|
+
Ajax.Base.prototype = {
|
980
|
+
setOptions: function(options) {
|
981
|
+
this.options = {
|
982
|
+
method: 'post',
|
983
|
+
asynchronous: true,
|
984
|
+
contentType: 'application/x-www-form-urlencoded',
|
985
|
+
encoding: 'UTF-8',
|
986
|
+
parameters: ''
|
987
|
+
}
|
988
|
+
Object.extend(this.options, options || {});
|
989
|
+
|
990
|
+
this.options.method = this.options.method.toLowerCase();
|
991
|
+
if (typeof this.options.parameters == 'string')
|
992
|
+
this.options.parameters = this.options.parameters.toQueryParams();
|
993
|
+
}
|
994
|
+
}
|
995
|
+
|
996
|
+
Ajax.Request = Class.create();
|
997
|
+
Ajax.Request.Events =
|
998
|
+
['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
|
999
|
+
|
1000
|
+
Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
|
1001
|
+
_complete: false,
|
1002
|
+
|
1003
|
+
initialize: function(url, options) {
|
1004
|
+
this.transport = Ajax.getTransport();
|
1005
|
+
this.setOptions(options);
|
1006
|
+
this.request(url);
|
1007
|
+
},
|
1008
|
+
|
1009
|
+
request: function(url) {
|
1010
|
+
this.url = url;
|
1011
|
+
this.method = this.options.method;
|
1012
|
+
var params = Object.clone(this.options.parameters);
|
1013
|
+
|
1014
|
+
if (!['get', 'post'].include(this.method)) {
|
1015
|
+
// simulate other verbs over post
|
1016
|
+
params['_method'] = this.method;
|
1017
|
+
this.method = 'post';
|
1018
|
+
}
|
1019
|
+
|
1020
|
+
this.parameters = params;
|
1021
|
+
|
1022
|
+
if (params = Hash.toQueryString(params)) {
|
1023
|
+
// when GET, append parameters to URL
|
1024
|
+
if (this.method == 'get')
|
1025
|
+
this.url += (this.url.include('?') ? '&' : '?') + params;
|
1026
|
+
else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
|
1027
|
+
params += '&_=';
|
1028
|
+
}
|
1029
|
+
|
1030
|
+
try {
|
1031
|
+
if (this.options.onCreate) this.options.onCreate(this.transport);
|
1032
|
+
Ajax.Responders.dispatch('onCreate', this, this.transport);
|
1033
|
+
|
1034
|
+
this.transport.open(this.method.toUpperCase(), this.url,
|
1035
|
+
this.options.asynchronous);
|
1036
|
+
|
1037
|
+
if (this.options.asynchronous)
|
1038
|
+
setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
|
1039
|
+
|
1040
|
+
this.transport.onreadystatechange = this.onStateChange.bind(this);
|
1041
|
+
this.setRequestHeaders();
|
1042
|
+
|
1043
|
+
this.body = this.method == 'post' ? (this.options.postBody || params) : null;
|
1044
|
+
this.transport.send(this.body);
|
1045
|
+
|
1046
|
+
/* Force Firefox to handle ready state 4 for synchronous requests */
|
1047
|
+
if (!this.options.asynchronous && this.transport.overrideMimeType)
|
1048
|
+
this.onStateChange();
|
1049
|
+
|
1050
|
+
}
|
1051
|
+
catch (e) {
|
1052
|
+
this.dispatchException(e);
|
1053
|
+
}
|
1054
|
+
},
|
1055
|
+
|
1056
|
+
onStateChange: function() {
|
1057
|
+
var readyState = this.transport.readyState;
|
1058
|
+
if (readyState > 1 && !((readyState == 4) && this._complete))
|
1059
|
+
this.respondToReadyState(this.transport.readyState);
|
1060
|
+
},
|
1061
|
+
|
1062
|
+
setRequestHeaders: function() {
|
1063
|
+
var headers = {
|
1064
|
+
'X-Requested-With': 'XMLHttpRequest',
|
1065
|
+
'X-Prototype-Version': Prototype.Version,
|
1066
|
+
'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
|
1067
|
+
};
|
1068
|
+
|
1069
|
+
if (this.method == 'post') {
|
1070
|
+
headers['Content-type'] = this.options.contentType +
|
1071
|
+
(this.options.encoding ? '; charset=' + this.options.encoding : '');
|
1072
|
+
|
1073
|
+
/* Force "Connection: close" for older Mozilla browsers to work
|
1074
|
+
* around a bug where XMLHttpRequest sends an incorrect
|
1075
|
+
* Content-length header. See Mozilla Bugzilla #246651.
|
1076
|
+
*/
|
1077
|
+
if (this.transport.overrideMimeType &&
|
1078
|
+
(navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
|
1079
|
+
headers['Connection'] = 'close';
|
1080
|
+
}
|
1081
|
+
|
1082
|
+
// user-defined headers
|
1083
|
+
if (typeof this.options.requestHeaders == 'object') {
|
1084
|
+
var extras = this.options.requestHeaders;
|
1085
|
+
|
1086
|
+
if (typeof extras.push == 'function')
|
1087
|
+
for (var i = 0, length = extras.length; i < length; i += 2)
|
1088
|
+
headers[extras[i]] = extras[i+1];
|
1089
|
+
else
|
1090
|
+
$H(extras).each(function(pair) { headers[pair.key] = pair.value });
|
1091
|
+
}
|
1092
|
+
|
1093
|
+
for (var name in headers)
|
1094
|
+
this.transport.setRequestHeader(name, headers[name]);
|
1095
|
+
},
|
1096
|
+
|
1097
|
+
success: function() {
|
1098
|
+
return !this.transport.status
|
1099
|
+
|| (this.transport.status >= 200 && this.transport.status < 300);
|
1100
|
+
},
|
1101
|
+
|
1102
|
+
respondToReadyState: function(readyState) {
|
1103
|
+
var state = Ajax.Request.Events[readyState];
|
1104
|
+
var transport = this.transport, json = this.evalJSON();
|
1105
|
+
|
1106
|
+
if (state == 'Complete') {
|
1107
|
+
try {
|
1108
|
+
this._complete = true;
|
1109
|
+
(this.options['on' + this.transport.status]
|
1110
|
+
|| this.options['on' + (this.success() ? 'Success' : 'Failure')]
|
1111
|
+
|| Prototype.emptyFunction)(transport, json);
|
1112
|
+
} catch (e) {
|
1113
|
+
this.dispatchException(e);
|
1114
|
+
}
|
1115
|
+
|
1116
|
+
var contentType = this.getHeader('Content-type');
|
1117
|
+
if (contentType && contentType.strip().
|
1118
|
+
match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
|
1119
|
+
this.evalResponse();
|
1120
|
+
}
|
1121
|
+
|
1122
|
+
try {
|
1123
|
+
(this.options['on' + state] || Prototype.emptyFunction)(transport, json);
|
1124
|
+
Ajax.Responders.dispatch('on' + state, this, transport, json);
|
1125
|
+
} catch (e) {
|
1126
|
+
this.dispatchException(e);
|
1127
|
+
}
|
1128
|
+
|
1129
|
+
if (state == 'Complete') {
|
1130
|
+
// avoid memory leak in MSIE: clean up
|
1131
|
+
this.transport.onreadystatechange = Prototype.emptyFunction;
|
1132
|
+
}
|
1133
|
+
},
|
1134
|
+
|
1135
|
+
getHeader: function(name) {
|
1136
|
+
try {
|
1137
|
+
return this.transport.getResponseHeader(name);
|
1138
|
+
} catch (e) { return null }
|
1139
|
+
},
|
1140
|
+
|
1141
|
+
evalJSON: function() {
|
1142
|
+
try {
|
1143
|
+
var json = this.getHeader('X-JSON');
|
1144
|
+
return json ? json.evalJSON() : null;
|
1145
|
+
} catch (e) { return null }
|
1146
|
+
},
|
1147
|
+
|
1148
|
+
evalResponse: function() {
|
1149
|
+
try {
|
1150
|
+
return eval((this.transport.responseText || '').unfilterJSON());
|
1151
|
+
} catch (e) {
|
1152
|
+
this.dispatchException(e);
|
1153
|
+
}
|
1154
|
+
},
|
1155
|
+
|
1156
|
+
dispatchException: function(exception) {
|
1157
|
+
(this.options.onException || Prototype.emptyFunction)(this, exception);
|
1158
|
+
Ajax.Responders.dispatch('onException', this, exception);
|
1159
|
+
}
|
1160
|
+
});
|
1161
|
+
|
1162
|
+
Ajax.Updater = Class.create();
|
1163
|
+
|
1164
|
+
Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
|
1165
|
+
initialize: function(container, url, options) {
|
1166
|
+
this.container = {
|
1167
|
+
success: (container.success || container),
|
1168
|
+
failure: (container.failure || (container.success ? null : container))
|
1169
|
+
}
|
1170
|
+
|
1171
|
+
this.transport = Ajax.getTransport();
|
1172
|
+
this.setOptions(options);
|
1173
|
+
|
1174
|
+
var onComplete = this.options.onComplete || Prototype.emptyFunction;
|
1175
|
+
this.options.onComplete = (function(transport, param) {
|
1176
|
+
this.updateContent();
|
1177
|
+
onComplete(transport, param);
|
1178
|
+
}).bind(this);
|
1179
|
+
|
1180
|
+
this.request(url);
|
1181
|
+
},
|
1182
|
+
|
1183
|
+
updateContent: function() {
|
1184
|
+
var receiver = this.container[this.success() ? 'success' : 'failure'];
|
1185
|
+
var response = this.transport.responseText;
|
1186
|
+
|
1187
|
+
if (!this.options.evalScripts) response = response.stripScripts();
|
1188
|
+
|
1189
|
+
if (receiver = $(receiver)) {
|
1190
|
+
if (this.options.insertion)
|
1191
|
+
new this.options.insertion(receiver, response);
|
1192
|
+
else
|
1193
|
+
receiver.update(response);
|
1194
|
+
}
|
1195
|
+
|
1196
|
+
if (this.success()) {
|
1197
|
+
if (this.onComplete)
|
1198
|
+
setTimeout(this.onComplete.bind(this), 10);
|
1199
|
+
}
|
1200
|
+
}
|
1201
|
+
});
|
1202
|
+
|
1203
|
+
Ajax.PeriodicalUpdater = Class.create();
|
1204
|
+
Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
|
1205
|
+
initialize: function(container, url, options) {
|
1206
|
+
this.setOptions(options);
|
1207
|
+
this.onComplete = this.options.onComplete;
|
1208
|
+
|
1209
|
+
this.frequency = (this.options.frequency || 2);
|
1210
|
+
this.decay = (this.options.decay || 1);
|
1211
|
+
|
1212
|
+
this.updater = {};
|
1213
|
+
this.container = container;
|
1214
|
+
this.url = url;
|
1215
|
+
|
1216
|
+
this.start();
|
1217
|
+
},
|
1218
|
+
|
1219
|
+
start: function() {
|
1220
|
+
this.options.onComplete = this.updateComplete.bind(this);
|
1221
|
+
this.onTimerEvent();
|
1222
|
+
},
|
1223
|
+
|
1224
|
+
stop: function() {
|
1225
|
+
this.updater.options.onComplete = undefined;
|
1226
|
+
clearTimeout(this.timer);
|
1227
|
+
(this.onComplete || Prototype.emptyFunction).apply(this, arguments);
|
1228
|
+
},
|
1229
|
+
|
1230
|
+
updateComplete: function(request) {
|
1231
|
+
if (this.options.decay) {
|
1232
|
+
this.decay = (request.responseText == this.lastText ?
|
1233
|
+
this.decay * this.options.decay : 1);
|
1234
|
+
|
1235
|
+
this.lastText = request.responseText;
|
1236
|
+
}
|
1237
|
+
this.timer = setTimeout(this.onTimerEvent.bind(this),
|
1238
|
+
this.decay * this.frequency * 1000);
|
1239
|
+
},
|
1240
|
+
|
1241
|
+
onTimerEvent: function() {
|
1242
|
+
this.updater = new Ajax.Updater(this.container, this.url, this.options);
|
1243
|
+
}
|
1244
|
+
});
|
1245
|
+
function $(element) {
|
1246
|
+
if (arguments.length > 1) {
|
1247
|
+
for (var i = 0, elements = [], length = arguments.length; i < length; i++)
|
1248
|
+
elements.push($(arguments[i]));
|
1249
|
+
return elements;
|
1250
|
+
}
|
1251
|
+
if (typeof element == 'string')
|
1252
|
+
element = document.getElementById(element);
|
1253
|
+
return Element.extend(element);
|
1254
|
+
}
|
1255
|
+
|
1256
|
+
if (Prototype.BrowserFeatures.XPath) {
|
1257
|
+
document._getElementsByXPath = function(expression, parentElement) {
|
1258
|
+
var results = [];
|
1259
|
+
var query = document.evaluate(expression, $(parentElement) || document,
|
1260
|
+
null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
1261
|
+
for (var i = 0, length = query.snapshotLength; i < length; i++)
|
1262
|
+
results.push(query.snapshotItem(i));
|
1263
|
+
return results;
|
1264
|
+
};
|
1265
|
+
|
1266
|
+
document.getElementsByClassName = function(className, parentElement) {
|
1267
|
+
var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
|
1268
|
+
return document._getElementsByXPath(q, parentElement);
|
1269
|
+
}
|
1270
|
+
|
1271
|
+
} else document.getElementsByClassName = function(className, parentElement) {
|
1272
|
+
var children = ($(parentElement) || document.body).getElementsByTagName('*');
|
1273
|
+
var elements = [], child;
|
1274
|
+
for (var i = 0, length = children.length; i < length; i++) {
|
1275
|
+
child = children[i];
|
1276
|
+
if (Element.hasClassName(child, className))
|
1277
|
+
elements.push(Element.extend(child));
|
1278
|
+
}
|
1279
|
+
return elements;
|
1280
|
+
};
|
1281
|
+
|
1282
|
+
/*--------------------------------------------------------------------------*/
|
1283
|
+
|
1284
|
+
if (!window.Element) var Element = {};
|
1285
|
+
|
1286
|
+
Element.extend = function(element) {
|
1287
|
+
var F = Prototype.BrowserFeatures;
|
1288
|
+
if (!element || !element.tagName || element.nodeType == 3 ||
|
1289
|
+
element._extended || F.SpecificElementExtensions || element == window)
|
1290
|
+
return element;
|
1291
|
+
|
1292
|
+
var methods = {}, tagName = element.tagName, cache = Element.extend.cache,
|
1293
|
+
T = Element.Methods.ByTag;
|
1294
|
+
|
1295
|
+
// extend methods for all tags (Safari doesn't need this)
|
1296
|
+
if (!F.ElementExtensions) {
|
1297
|
+
Object.extend(methods, Element.Methods),
|
1298
|
+
Object.extend(methods, Element.Methods.Simulated);
|
1299
|
+
}
|
1300
|
+
|
1301
|
+
// extend methods for specific tags
|
1302
|
+
if (T[tagName]) Object.extend(methods, T[tagName]);
|
1303
|
+
|
1304
|
+
for (var property in methods) {
|
1305
|
+
var value = methods[property];
|
1306
|
+
if (typeof value == 'function' && !(property in element))
|
1307
|
+
element[property] = cache.findOrStore(value);
|
1308
|
+
}
|
1309
|
+
|
1310
|
+
element._extended = Prototype.emptyFunction;
|
1311
|
+
return element;
|
1312
|
+
};
|
1313
|
+
|
1314
|
+
Element.extend.cache = {
|
1315
|
+
findOrStore: function(value) {
|
1316
|
+
return this[value] = this[value] || function() {
|
1317
|
+
return value.apply(null, [this].concat($A(arguments)));
|
1318
|
+
}
|
1319
|
+
}
|
1320
|
+
};
|
1321
|
+
|
1322
|
+
Element.Methods = {
|
1323
|
+
visible: function(element) {
|
1324
|
+
return $(element).style.display != 'none';
|
1325
|
+
},
|
1326
|
+
|
1327
|
+
toggle: function(element) {
|
1328
|
+
element = $(element);
|
1329
|
+
Element[Element.visible(element) ? 'hide' : 'show'](element);
|
1330
|
+
return element;
|
1331
|
+
},
|
1332
|
+
|
1333
|
+
hide: function(element) {
|
1334
|
+
$(element).style.display = 'none';
|
1335
|
+
return element;
|
1336
|
+
},
|
1337
|
+
|
1338
|
+
show: function(element) {
|
1339
|
+
$(element).style.display = '';
|
1340
|
+
return element;
|
1341
|
+
},
|
1342
|
+
|
1343
|
+
remove: function(element) {
|
1344
|
+
element = $(element);
|
1345
|
+
element.parentNode.removeChild(element);
|
1346
|
+
return element;
|
1347
|
+
},
|
1348
|
+
|
1349
|
+
update: function(element, html) {
|
1350
|
+
html = typeof html == 'undefined' ? '' : html.toString();
|
1351
|
+
$(element).innerHTML = html.stripScripts();
|
1352
|
+
setTimeout(function() {html.evalScripts()}, 10);
|
1353
|
+
return element;
|
1354
|
+
},
|
1355
|
+
|
1356
|
+
replace: function(element, html) {
|
1357
|
+
element = $(element);
|
1358
|
+
html = typeof html == 'undefined' ? '' : html.toString();
|
1359
|
+
if (element.outerHTML) {
|
1360
|
+
element.outerHTML = html.stripScripts();
|
1361
|
+
} else {
|
1362
|
+
var range = element.ownerDocument.createRange();
|
1363
|
+
range.selectNodeContents(element);
|
1364
|
+
element.parentNode.replaceChild(
|
1365
|
+
range.createContextualFragment(html.stripScripts()), element);
|
1366
|
+
}
|
1367
|
+
setTimeout(function() {html.evalScripts()}, 10);
|
1368
|
+
return element;
|
1369
|
+
},
|
1370
|
+
|
1371
|
+
inspect: function(element) {
|
1372
|
+
element = $(element);
|
1373
|
+
var result = '<' + element.tagName.toLowerCase();
|
1374
|
+
$H({'id': 'id', 'className': 'class'}).each(function(pair) {
|
1375
|
+
var property = pair.first(), attribute = pair.last();
|
1376
|
+
var value = (element[property] || '').toString();
|
1377
|
+
if (value) result += ' ' + attribute + '=' + value.inspect(true);
|
1378
|
+
});
|
1379
|
+
return result + '>';
|
1380
|
+
},
|
1381
|
+
|
1382
|
+
recursivelyCollect: function(element, property) {
|
1383
|
+
element = $(element);
|
1384
|
+
var elements = [];
|
1385
|
+
while (element = element[property])
|
1386
|
+
if (element.nodeType == 1)
|
1387
|
+
elements.push(Element.extend(element));
|
1388
|
+
return elements;
|
1389
|
+
},
|
1390
|
+
|
1391
|
+
ancestors: function(element) {
|
1392
|
+
return $(element).recursivelyCollect('parentNode');
|
1393
|
+
},
|
1394
|
+
|
1395
|
+
descendants: function(element) {
|
1396
|
+
return $A($(element).getElementsByTagName('*')).each(Element.extend);
|
1397
|
+
},
|
1398
|
+
|
1399
|
+
firstDescendant: function(element) {
|
1400
|
+
element = $(element).firstChild;
|
1401
|
+
while (element && element.nodeType != 1) element = element.nextSibling;
|
1402
|
+
return $(element);
|
1403
|
+
},
|
1404
|
+
|
1405
|
+
immediateDescendants: function(element) {
|
1406
|
+
if (!(element = $(element).firstChild)) return [];
|
1407
|
+
while (element && element.nodeType != 1) element = element.nextSibling;
|
1408
|
+
if (element) return [element].concat($(element).nextSiblings());
|
1409
|
+
return [];
|
1410
|
+
},
|
1411
|
+
|
1412
|
+
previousSiblings: function(element) {
|
1413
|
+
return $(element).recursivelyCollect('previousSibling');
|
1414
|
+
},
|
1415
|
+
|
1416
|
+
nextSiblings: function(element) {
|
1417
|
+
return $(element).recursivelyCollect('nextSibling');
|
1418
|
+
},
|
1419
|
+
|
1420
|
+
siblings: function(element) {
|
1421
|
+
element = $(element);
|
1422
|
+
return element.previousSiblings().reverse().concat(element.nextSiblings());
|
1423
|
+
},
|
1424
|
+
|
1425
|
+
match: function(element, selector) {
|
1426
|
+
if (typeof selector == 'string')
|
1427
|
+
selector = new Selector(selector);
|
1428
|
+
return selector.match($(element));
|
1429
|
+
},
|
1430
|
+
|
1431
|
+
up: function(element, expression, index) {
|
1432
|
+
element = $(element);
|
1433
|
+
if (arguments.length == 1) return $(element.parentNode);
|
1434
|
+
var ancestors = element.ancestors();
|
1435
|
+
return expression ? Selector.findElement(ancestors, expression, index) :
|
1436
|
+
ancestors[index || 0];
|
1437
|
+
},
|
1438
|
+
|
1439
|
+
down: function(element, expression, index) {
|
1440
|
+
element = $(element);
|
1441
|
+
if (arguments.length == 1) return element.firstDescendant();
|
1442
|
+
var descendants = element.descendants();
|
1443
|
+
return expression ? Selector.findElement(descendants, expression, index) :
|
1444
|
+
descendants[index || 0];
|
1445
|
+
},
|
1446
|
+
|
1447
|
+
previous: function(element, expression, index) {
|
1448
|
+
element = $(element);
|
1449
|
+
if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
|
1450
|
+
var previousSiblings = element.previousSiblings();
|
1451
|
+
return expression ? Selector.findElement(previousSiblings, expression, index) :
|
1452
|
+
previousSiblings[index || 0];
|
1453
|
+
},
|
1454
|
+
|
1455
|
+
next: function(element, expression, index) {
|
1456
|
+
element = $(element);
|
1457
|
+
if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
|
1458
|
+
var nextSiblings = element.nextSiblings();
|
1459
|
+
return expression ? Selector.findElement(nextSiblings, expression, index) :
|
1460
|
+
nextSiblings[index || 0];
|
1461
|
+
},
|
1462
|
+
|
1463
|
+
getElementsBySelector: function() {
|
1464
|
+
var args = $A(arguments), element = $(args.shift());
|
1465
|
+
return Selector.findChildElements(element, args);
|
1466
|
+
},
|
1467
|
+
|
1468
|
+
getElementsByClassName: function(element, className) {
|
1469
|
+
return document.getElementsByClassName(className, element);
|
1470
|
+
},
|
1471
|
+
|
1472
|
+
readAttribute: function(element, name) {
|
1473
|
+
element = $(element);
|
1474
|
+
if (Prototype.Browser.IE) {
|
1475
|
+
if (!element.attributes) return null;
|
1476
|
+
var t = Element._attributeTranslations;
|
1477
|
+
if (t.values[name]) return t.values[name](element, name);
|
1478
|
+
if (t.names[name]) name = t.names[name];
|
1479
|
+
var attribute = element.attributes[name];
|
1480
|
+
return attribute ? attribute.nodeValue : null;
|
1481
|
+
}
|
1482
|
+
return element.getAttribute(name);
|
1483
|
+
},
|
1484
|
+
|
1485
|
+
getHeight: function(element) {
|
1486
|
+
return $(element).getDimensions().height;
|
1487
|
+
},
|
1488
|
+
|
1489
|
+
getWidth: function(element) {
|
1490
|
+
return $(element).getDimensions().width;
|
1491
|
+
},
|
1492
|
+
|
1493
|
+
classNames: function(element) {
|
1494
|
+
return new Element.ClassNames(element);
|
1495
|
+
},
|
1496
|
+
|
1497
|
+
hasClassName: function(element, className) {
|
1498
|
+
if (!(element = $(element))) return;
|
1499
|
+
var elementClassName = element.className;
|
1500
|
+
if (elementClassName.length == 0) return false;
|
1501
|
+
if (elementClassName == className ||
|
1502
|
+
elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
|
1503
|
+
return true;
|
1504
|
+
return false;
|
1505
|
+
},
|
1506
|
+
|
1507
|
+
addClassName: function(element, className) {
|
1508
|
+
if (!(element = $(element))) return;
|
1509
|
+
Element.classNames(element).add(className);
|
1510
|
+
return element;
|
1511
|
+
},
|
1512
|
+
|
1513
|
+
removeClassName: function(element, className) {
|
1514
|
+
if (!(element = $(element))) return;
|
1515
|
+
Element.classNames(element).remove(className);
|
1516
|
+
return element;
|
1517
|
+
},
|
1518
|
+
|
1519
|
+
toggleClassName: function(element, className) {
|
1520
|
+
if (!(element = $(element))) return;
|
1521
|
+
Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
|
1522
|
+
return element;
|
1523
|
+
},
|
1524
|
+
|
1525
|
+
observe: function() {
|
1526
|
+
Event.observe.apply(Event, arguments);
|
1527
|
+
return $A(arguments).first();
|
1528
|
+
},
|
1529
|
+
|
1530
|
+
stopObserving: function() {
|
1531
|
+
Event.stopObserving.apply(Event, arguments);
|
1532
|
+
return $A(arguments).first();
|
1533
|
+
},
|
1534
|
+
|
1535
|
+
// removes whitespace-only text node children
|
1536
|
+
cleanWhitespace: function(element) {
|
1537
|
+
element = $(element);
|
1538
|
+
var node = element.firstChild;
|
1539
|
+
while (node) {
|
1540
|
+
var nextNode = node.nextSibling;
|
1541
|
+
if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
|
1542
|
+
element.removeChild(node);
|
1543
|
+
node = nextNode;
|
1544
|
+
}
|
1545
|
+
return element;
|
1546
|
+
},
|
1547
|
+
|
1548
|
+
empty: function(element) {
|
1549
|
+
return $(element).innerHTML.blank();
|
1550
|
+
},
|
1551
|
+
|
1552
|
+
descendantOf: function(element, ancestor) {
|
1553
|
+
element = $(element), ancestor = $(ancestor);
|
1554
|
+
while (element = element.parentNode)
|
1555
|
+
if (element == ancestor) return true;
|
1556
|
+
return false;
|
1557
|
+
},
|
1558
|
+
|
1559
|
+
scrollTo: function(element) {
|
1560
|
+
element = $(element);
|
1561
|
+
var pos = Position.cumulativeOffset(element);
|
1562
|
+
window.scrollTo(pos[0], pos[1]);
|
1563
|
+
return element;
|
1564
|
+
},
|
1565
|
+
|
1566
|
+
getStyle: function(element, style) {
|
1567
|
+
element = $(element);
|
1568
|
+
style = style == 'float' ? 'cssFloat' : style.camelize();
|
1569
|
+
var value = element.style[style];
|
1570
|
+
if (!value) {
|
1571
|
+
var css = document.defaultView.getComputedStyle(element, null);
|
1572
|
+
value = css ? css[style] : null;
|
1573
|
+
}
|
1574
|
+
if (style == 'opacity') return value ? parseFloat(value) : 1.0;
|
1575
|
+
return value == 'auto' ? null : value;
|
1576
|
+
},
|
1577
|
+
|
1578
|
+
getOpacity: function(element) {
|
1579
|
+
return $(element).getStyle('opacity');
|
1580
|
+
},
|
1581
|
+
|
1582
|
+
setStyle: function(element, styles, camelized) {
|
1583
|
+
element = $(element);
|
1584
|
+
var elementStyle = element.style;
|
1585
|
+
|
1586
|
+
for (var property in styles)
|
1587
|
+
if (property == 'opacity') element.setOpacity(styles[property])
|
1588
|
+
else
|
1589
|
+
elementStyle[(property == 'float' || property == 'cssFloat') ?
|
1590
|
+
(elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
|
1591
|
+
(camelized ? property : property.camelize())] = styles[property];
|
1592
|
+
|
1593
|
+
return element;
|
1594
|
+
},
|
1595
|
+
|
1596
|
+
setOpacity: function(element, value) {
|
1597
|
+
element = $(element);
|
1598
|
+
element.style.opacity = (value == 1 || value === '') ? '' :
|
1599
|
+
(value < 0.00001) ? 0 : value;
|
1600
|
+
return element;
|
1601
|
+
},
|
1602
|
+
|
1603
|
+
getDimensions: function(element) {
|
1604
|
+
element = $(element);
|
1605
|
+
var display = $(element).getStyle('display');
|
1606
|
+
if (display != 'none' && display != null) // Safari bug
|
1607
|
+
return {width: element.offsetWidth, height: element.offsetHeight};
|
1608
|
+
|
1609
|
+
// All *Width and *Height properties give 0 on elements with display none,
|
1610
|
+
// so enable the element temporarily
|
1611
|
+
var els = element.style;
|
1612
|
+
var originalVisibility = els.visibility;
|
1613
|
+
var originalPosition = els.position;
|
1614
|
+
var originalDisplay = els.display;
|
1615
|
+
els.visibility = 'hidden';
|
1616
|
+
els.position = 'absolute';
|
1617
|
+
els.display = 'block';
|
1618
|
+
var originalWidth = element.clientWidth;
|
1619
|
+
var originalHeight = element.clientHeight;
|
1620
|
+
els.display = originalDisplay;
|
1621
|
+
els.position = originalPosition;
|
1622
|
+
els.visibility = originalVisibility;
|
1623
|
+
return {width: originalWidth, height: originalHeight};
|
1624
|
+
},
|
1625
|
+
|
1626
|
+
makePositioned: function(element) {
|
1627
|
+
element = $(element);
|
1628
|
+
var pos = Element.getStyle(element, 'position');
|
1629
|
+
if (pos == 'static' || !pos) {
|
1630
|
+
element._madePositioned = true;
|
1631
|
+
element.style.position = 'relative';
|
1632
|
+
// Opera returns the offset relative to the positioning context, when an
|
1633
|
+
// element is position relative but top and left have not been defined
|
1634
|
+
if (window.opera) {
|
1635
|
+
element.style.top = 0;
|
1636
|
+
element.style.left = 0;
|
1637
|
+
}
|
1638
|
+
}
|
1639
|
+
return element;
|
1640
|
+
},
|
1641
|
+
|
1642
|
+
undoPositioned: function(element) {
|
1643
|
+
element = $(element);
|
1644
|
+
if (element._madePositioned) {
|
1645
|
+
element._madePositioned = undefined;
|
1646
|
+
element.style.position =
|
1647
|
+
element.style.top =
|
1648
|
+
element.style.left =
|
1649
|
+
element.style.bottom =
|
1650
|
+
element.style.right = '';
|
1651
|
+
}
|
1652
|
+
return element;
|
1653
|
+
},
|
1654
|
+
|
1655
|
+
makeClipping: function(element) {
|
1656
|
+
element = $(element);
|
1657
|
+
if (element._overflow) return element;
|
1658
|
+
element._overflow = element.style.overflow || 'auto';
|
1659
|
+
if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
|
1660
|
+
element.style.overflow = 'hidden';
|
1661
|
+
return element;
|
1662
|
+
},
|
1663
|
+
|
1664
|
+
undoClipping: function(element) {
|
1665
|
+
element = $(element);
|
1666
|
+
if (!element._overflow) return element;
|
1667
|
+
element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
|
1668
|
+
element._overflow = null;
|
1669
|
+
return element;
|
1670
|
+
}
|
1671
|
+
};
|
1672
|
+
|
1673
|
+
Object.extend(Element.Methods, {
|
1674
|
+
childOf: Element.Methods.descendantOf,
|
1675
|
+
childElements: Element.Methods.immediateDescendants
|
1676
|
+
});
|
1677
|
+
|
1678
|
+
if (Prototype.Browser.Opera) {
|
1679
|
+
Element.Methods._getStyle = Element.Methods.getStyle;
|
1680
|
+
Element.Methods.getStyle = function(element, style) {
|
1681
|
+
switch(style) {
|
1682
|
+
case 'left':
|
1683
|
+
case 'top':
|
1684
|
+
case 'right':
|
1685
|
+
case 'bottom':
|
1686
|
+
if (Element._getStyle(element, 'position') == 'static') return null;
|
1687
|
+
default: return Element._getStyle(element, style);
|
1688
|
+
}
|
1689
|
+
};
|
1690
|
+
}
|
1691
|
+
else if (Prototype.Browser.IE) {
|
1692
|
+
Element.Methods.getStyle = function(element, style) {
|
1693
|
+
element = $(element);
|
1694
|
+
style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
|
1695
|
+
var value = element.style[style];
|
1696
|
+
if (!value && element.currentStyle) value = element.currentStyle[style];
|
1697
|
+
|
1698
|
+
if (style == 'opacity') {
|
1699
|
+
if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
|
1700
|
+
if (value[1]) return parseFloat(value[1]) / 100;
|
1701
|
+
return 1.0;
|
1702
|
+
}
|
1703
|
+
|
1704
|
+
if (value == 'auto') {
|
1705
|
+
if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
|
1706
|
+
return element['offset'+style.capitalize()] + 'px';
|
1707
|
+
return null;
|
1708
|
+
}
|
1709
|
+
return value;
|
1710
|
+
};
|
1711
|
+
|
1712
|
+
Element.Methods.setOpacity = function(element, value) {
|
1713
|
+
element = $(element);
|
1714
|
+
var filter = element.getStyle('filter'), style = element.style;
|
1715
|
+
if (value == 1 || value === '') {
|
1716
|
+
style.filter = filter.replace(/alpha\([^\)]*\)/gi,'');
|
1717
|
+
return element;
|
1718
|
+
} else if (value < 0.00001) value = 0;
|
1719
|
+
style.filter = filter.replace(/alpha\([^\)]*\)/gi, '') +
|
1720
|
+
'alpha(opacity=' + (value * 100) + ')';
|
1721
|
+
return element;
|
1722
|
+
};
|
1723
|
+
|
1724
|
+
// IE is missing .innerHTML support for TABLE-related elements
|
1725
|
+
Element.Methods.update = function(element, html) {
|
1726
|
+
element = $(element);
|
1727
|
+
html = typeof html == 'undefined' ? '' : html.toString();
|
1728
|
+
var tagName = element.tagName.toUpperCase();
|
1729
|
+
if (['THEAD','TBODY','TR','TD'].include(tagName)) {
|
1730
|
+
var div = document.createElement('div');
|
1731
|
+
switch (tagName) {
|
1732
|
+
case 'THEAD':
|
1733
|
+
case 'TBODY':
|
1734
|
+
div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>';
|
1735
|
+
depth = 2;
|
1736
|
+
break;
|
1737
|
+
case 'TR':
|
1738
|
+
div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>';
|
1739
|
+
depth = 3;
|
1740
|
+
break;
|
1741
|
+
case 'TD':
|
1742
|
+
div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>';
|
1743
|
+
depth = 4;
|
1744
|
+
}
|
1745
|
+
$A(element.childNodes).each(function(node) { element.removeChild(node) });
|
1746
|
+
depth.times(function() { div = div.firstChild });
|
1747
|
+
$A(div.childNodes).each(function(node) { element.appendChild(node) });
|
1748
|
+
} else {
|
1749
|
+
element.innerHTML = html.stripScripts();
|
1750
|
+
}
|
1751
|
+
setTimeout(function() { html.evalScripts() }, 10);
|
1752
|
+
return element;
|
1753
|
+
}
|
1754
|
+
}
|
1755
|
+
else if (Prototype.Browser.Gecko) {
|
1756
|
+
Element.Methods.setOpacity = function(element, value) {
|
1757
|
+
element = $(element);
|
1758
|
+
element.style.opacity = (value == 1) ? 0.999999 :
|
1759
|
+
(value === '') ? '' : (value < 0.00001) ? 0 : value;
|
1760
|
+
return element;
|
1761
|
+
};
|
1762
|
+
}
|
1763
|
+
|
1764
|
+
Element._attributeTranslations = {
|
1765
|
+
names: {
|
1766
|
+
colspan: "colSpan",
|
1767
|
+
rowspan: "rowSpan",
|
1768
|
+
valign: "vAlign",
|
1769
|
+
datetime: "dateTime",
|
1770
|
+
accesskey: "accessKey",
|
1771
|
+
tabindex: "tabIndex",
|
1772
|
+
enctype: "encType",
|
1773
|
+
maxlength: "maxLength",
|
1774
|
+
readonly: "readOnly",
|
1775
|
+
longdesc: "longDesc"
|
1776
|
+
},
|
1777
|
+
values: {
|
1778
|
+
_getAttr: function(element, attribute) {
|
1779
|
+
return element.getAttribute(attribute, 2);
|
1780
|
+
},
|
1781
|
+
_flag: function(element, attribute) {
|
1782
|
+
return $(element).hasAttribute(attribute) ? attribute : null;
|
1783
|
+
},
|
1784
|
+
style: function(element) {
|
1785
|
+
return element.style.cssText.toLowerCase();
|
1786
|
+
},
|
1787
|
+
title: function(element) {
|
1788
|
+
var node = element.getAttributeNode('title');
|
1789
|
+
return node.specified ? node.nodeValue : null;
|
1790
|
+
}
|
1791
|
+
}
|
1792
|
+
};
|
1793
|
+
|
1794
|
+
(function() {
|
1795
|
+
Object.extend(this, {
|
1796
|
+
href: this._getAttr,
|
1797
|
+
src: this._getAttr,
|
1798
|
+
type: this._getAttr,
|
1799
|
+
disabled: this._flag,
|
1800
|
+
checked: this._flag,
|
1801
|
+
readonly: this._flag,
|
1802
|
+
multiple: this._flag
|
1803
|
+
});
|
1804
|
+
}).call(Element._attributeTranslations.values);
|
1805
|
+
|
1806
|
+
Element.Methods.Simulated = {
|
1807
|
+
hasAttribute: function(element, attribute) {
|
1808
|
+
var t = Element._attributeTranslations, node;
|
1809
|
+
attribute = t.names[attribute] || attribute;
|
1810
|
+
node = $(element).getAttributeNode(attribute);
|
1811
|
+
return node && node.specified;
|
1812
|
+
}
|
1813
|
+
};
|
1814
|
+
|
1815
|
+
Element.Methods.ByTag = {};
|
1816
|
+
|
1817
|
+
Object.extend(Element, Element.Methods);
|
1818
|
+
|
1819
|
+
if (!Prototype.BrowserFeatures.ElementExtensions &&
|
1820
|
+
document.createElement('div').__proto__) {
|
1821
|
+
window.HTMLElement = {};
|
1822
|
+
window.HTMLElement.prototype = document.createElement('div').__proto__;
|
1823
|
+
Prototype.BrowserFeatures.ElementExtensions = true;
|
1824
|
+
}
|
1825
|
+
|
1826
|
+
Element.hasAttribute = function(element, attribute) {
|
1827
|
+
if (element.hasAttribute) return element.hasAttribute(attribute);
|
1828
|
+
return Element.Methods.Simulated.hasAttribute(element, attribute);
|
1829
|
+
};
|
1830
|
+
|
1831
|
+
Element.addMethods = function(methods) {
|
1832
|
+
var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
|
1833
|
+
|
1834
|
+
if (!methods) {
|
1835
|
+
Object.extend(Form, Form.Methods);
|
1836
|
+
Object.extend(Form.Element, Form.Element.Methods);
|
1837
|
+
Object.extend(Element.Methods.ByTag, {
|
1838
|
+
"FORM": Object.clone(Form.Methods),
|
1839
|
+
"INPUT": Object.clone(Form.Element.Methods),
|
1840
|
+
"SELECT": Object.clone(Form.Element.Methods),
|
1841
|
+
"TEXTAREA": Object.clone(Form.Element.Methods)
|
1842
|
+
});
|
1843
|
+
}
|
1844
|
+
|
1845
|
+
if (arguments.length == 2) {
|
1846
|
+
var tagName = methods;
|
1847
|
+
methods = arguments[1];
|
1848
|
+
}
|
1849
|
+
|
1850
|
+
if (!tagName) Object.extend(Element.Methods, methods || {});
|
1851
|
+
else {
|
1852
|
+
if (tagName.constructor == Array) tagName.each(extend);
|
1853
|
+
else extend(tagName);
|
1854
|
+
}
|
1855
|
+
|
1856
|
+
function extend(tagName) {
|
1857
|
+
tagName = tagName.toUpperCase();
|
1858
|
+
if (!Element.Methods.ByTag[tagName])
|
1859
|
+
Element.Methods.ByTag[tagName] = {};
|
1860
|
+
Object.extend(Element.Methods.ByTag[tagName], methods);
|
1861
|
+
}
|
1862
|
+
|
1863
|
+
function copy(methods, destination, onlyIfAbsent) {
|
1864
|
+
onlyIfAbsent = onlyIfAbsent || false;
|
1865
|
+
var cache = Element.extend.cache;
|
1866
|
+
for (var property in methods) {
|
1867
|
+
var value = methods[property];
|
1868
|
+
if (!onlyIfAbsent || !(property in destination))
|
1869
|
+
destination[property] = cache.findOrStore(value);
|
1870
|
+
}
|
1871
|
+
}
|
1872
|
+
|
1873
|
+
function findDOMClass(tagName) {
|
1874
|
+
var klass;
|
1875
|
+
var trans = {
|
1876
|
+
"OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
|
1877
|
+
"FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
|
1878
|
+
"DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
|
1879
|
+
"H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
|
1880
|
+
"INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
|
1881
|
+
"TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
|
1882
|
+
"TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
|
1883
|
+
"TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
|
1884
|
+
"FrameSet", "IFRAME": "IFrame"
|
1885
|
+
};
|
1886
|
+
if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
|
1887
|
+
if (window[klass]) return window[klass];
|
1888
|
+
klass = 'HTML' + tagName + 'Element';
|
1889
|
+
if (window[klass]) return window[klass];
|
1890
|
+
klass = 'HTML' + tagName.capitalize() + 'Element';
|
1891
|
+
if (window[klass]) return window[klass];
|
1892
|
+
|
1893
|
+
window[klass] = {};
|
1894
|
+
window[klass].prototype = document.createElement(tagName).__proto__;
|
1895
|
+
return window[klass];
|
1896
|
+
}
|
1897
|
+
|
1898
|
+
if (F.ElementExtensions) {
|
1899
|
+
copy(Element.Methods, HTMLElement.prototype);
|
1900
|
+
copy(Element.Methods.Simulated, HTMLElement.prototype, true);
|
1901
|
+
}
|
1902
|
+
|
1903
|
+
if (F.SpecificElementExtensions) {
|
1904
|
+
for (var tag in Element.Methods.ByTag) {
|
1905
|
+
var klass = findDOMClass(tag);
|
1906
|
+
if (typeof klass == "undefined") continue;
|
1907
|
+
copy(T[tag], klass.prototype);
|
1908
|
+
}
|
1909
|
+
}
|
1910
|
+
|
1911
|
+
Object.extend(Element, Element.Methods);
|
1912
|
+
delete Element.ByTag;
|
1913
|
+
};
|
1914
|
+
|
1915
|
+
var Toggle = { display: Element.toggle };
|
1916
|
+
|
1917
|
+
/*--------------------------------------------------------------------------*/
|
1918
|
+
|
1919
|
+
Abstract.Insertion = function(adjacency) {
|
1920
|
+
this.adjacency = adjacency;
|
1921
|
+
}
|
1922
|
+
|
1923
|
+
Abstract.Insertion.prototype = {
|
1924
|
+
initialize: function(element, content) {
|
1925
|
+
this.element = $(element);
|
1926
|
+
this.content = content.stripScripts();
|
1927
|
+
|
1928
|
+
if (this.adjacency && this.element.insertAdjacentHTML) {
|
1929
|
+
try {
|
1930
|
+
this.element.insertAdjacentHTML(this.adjacency, this.content);
|
1931
|
+
} catch (e) {
|
1932
|
+
var tagName = this.element.tagName.toUpperCase();
|
1933
|
+
if (['TBODY', 'TR'].include(tagName)) {
|
1934
|
+
this.insertContent(this.contentFromAnonymousTable());
|
1935
|
+
} else {
|
1936
|
+
throw e;
|
1937
|
+
}
|
1938
|
+
}
|
1939
|
+
} else {
|
1940
|
+
this.range = this.element.ownerDocument.createRange();
|
1941
|
+
if (this.initializeRange) this.initializeRange();
|
1942
|
+
this.insertContent([this.range.createContextualFragment(this.content)]);
|
1943
|
+
}
|
1944
|
+
|
1945
|
+
setTimeout(function() {content.evalScripts()}, 10);
|
1946
|
+
},
|
1947
|
+
|
1948
|
+
contentFromAnonymousTable: function() {
|
1949
|
+
var div = document.createElement('div');
|
1950
|
+
div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
|
1951
|
+
return $A(div.childNodes[0].childNodes[0].childNodes);
|
1952
|
+
}
|
1953
|
+
}
|
1954
|
+
|
1955
|
+
var Insertion = new Object();
|
1956
|
+
|
1957
|
+
Insertion.Before = Class.create();
|
1958
|
+
Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
|
1959
|
+
initializeRange: function() {
|
1960
|
+
this.range.setStartBefore(this.element);
|
1961
|
+
},
|
1962
|
+
|
1963
|
+
insertContent: function(fragments) {
|
1964
|
+
fragments.each((function(fragment) {
|
1965
|
+
this.element.parentNode.insertBefore(fragment, this.element);
|
1966
|
+
}).bind(this));
|
1967
|
+
}
|
1968
|
+
});
|
1969
|
+
|
1970
|
+
Insertion.Top = Class.create();
|
1971
|
+
Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
|
1972
|
+
initializeRange: function() {
|
1973
|
+
this.range.selectNodeContents(this.element);
|
1974
|
+
this.range.collapse(true);
|
1975
|
+
},
|
1976
|
+
|
1977
|
+
insertContent: function(fragments) {
|
1978
|
+
fragments.reverse(false).each((function(fragment) {
|
1979
|
+
this.element.insertBefore(fragment, this.element.firstChild);
|
1980
|
+
}).bind(this));
|
1981
|
+
}
|
1982
|
+
});
|
1983
|
+
|
1984
|
+
Insertion.Bottom = Class.create();
|
1985
|
+
Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
|
1986
|
+
initializeRange: function() {
|
1987
|
+
this.range.selectNodeContents(this.element);
|
1988
|
+
this.range.collapse(this.element);
|
1989
|
+
},
|
1990
|
+
|
1991
|
+
insertContent: function(fragments) {
|
1992
|
+
fragments.each((function(fragment) {
|
1993
|
+
this.element.appendChild(fragment);
|
1994
|
+
}).bind(this));
|
1995
|
+
}
|
1996
|
+
});
|
1997
|
+
|
1998
|
+
Insertion.After = Class.create();
|
1999
|
+
Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
|
2000
|
+
initializeRange: function() {
|
2001
|
+
this.range.setStartAfter(this.element);
|
2002
|
+
},
|
2003
|
+
|
2004
|
+
insertContent: function(fragments) {
|
2005
|
+
fragments.each((function(fragment) {
|
2006
|
+
this.element.parentNode.insertBefore(fragment,
|
2007
|
+
this.element.nextSibling);
|
2008
|
+
}).bind(this));
|
2009
|
+
}
|
2010
|
+
});
|
2011
|
+
|
2012
|
+
/*--------------------------------------------------------------------------*/
|
2013
|
+
|
2014
|
+
Element.ClassNames = Class.create();
|
2015
|
+
Element.ClassNames.prototype = {
|
2016
|
+
initialize: function(element) {
|
2017
|
+
this.element = $(element);
|
2018
|
+
},
|
2019
|
+
|
2020
|
+
_each: function(iterator) {
|
2021
|
+
this.element.className.split(/\s+/).select(function(name) {
|
2022
|
+
return name.length > 0;
|
2023
|
+
})._each(iterator);
|
2024
|
+
},
|
2025
|
+
|
2026
|
+
set: function(className) {
|
2027
|
+
this.element.className = className;
|
2028
|
+
},
|
2029
|
+
|
2030
|
+
add: function(classNameToAdd) {
|
2031
|
+
if (this.include(classNameToAdd)) return;
|
2032
|
+
this.set($A(this).concat(classNameToAdd).join(' '));
|
2033
|
+
},
|
2034
|
+
|
2035
|
+
remove: function(classNameToRemove) {
|
2036
|
+
if (!this.include(classNameToRemove)) return;
|
2037
|
+
this.set($A(this).without(classNameToRemove).join(' '));
|
2038
|
+
},
|
2039
|
+
|
2040
|
+
toString: function() {
|
2041
|
+
return $A(this).join(' ');
|
2042
|
+
}
|
2043
|
+
};
|
2044
|
+
|
2045
|
+
Object.extend(Element.ClassNames.prototype, Enumerable);
|
2046
|
+
/* Portions of the Selector class are derived from Jack Slocum’s DomQuery,
|
2047
|
+
* part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
|
2048
|
+
* license. Please see http://www.yui-ext.com/ for more information. */
|
2049
|
+
|
2050
|
+
var Selector = Class.create();
|
2051
|
+
|
2052
|
+
Selector.prototype = {
|
2053
|
+
initialize: function(expression) {
|
2054
|
+
this.expression = expression.strip();
|
2055
|
+
this.compileMatcher();
|
2056
|
+
},
|
2057
|
+
|
2058
|
+
compileMatcher: function() {
|
2059
|
+
// Selectors with namespaced attributes can't use the XPath version
|
2060
|
+
if (Prototype.BrowserFeatures.XPath && !(/\[[\w-]*?:/).test(this.expression))
|
2061
|
+
return this.compileXPathMatcher();
|
2062
|
+
|
2063
|
+
var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
|
2064
|
+
c = Selector.criteria, le, p, m;
|
2065
|
+
|
2066
|
+
if (Selector._cache[e]) {
|
2067
|
+
this.matcher = Selector._cache[e]; return;
|
2068
|
+
}
|
2069
|
+
this.matcher = ["this.matcher = function(root) {",
|
2070
|
+
"var r = root, h = Selector.handlers, c = false, n;"];
|
2071
|
+
|
2072
|
+
while (e && le != e && (/\S/).test(e)) {
|
2073
|
+
le = e;
|
2074
|
+
for (var i in ps) {
|
2075
|
+
p = ps[i];
|
2076
|
+
if (m = e.match(p)) {
|
2077
|
+
this.matcher.push(typeof c[i] == 'function' ? c[i](m) :
|
2078
|
+
new Template(c[i]).evaluate(m));
|
2079
|
+
e = e.replace(m[0], '');
|
2080
|
+
break;
|
2081
|
+
}
|
2082
|
+
}
|
2083
|
+
}
|
2084
|
+
|
2085
|
+
this.matcher.push("return h.unique(n);\n}");
|
2086
|
+
eval(this.matcher.join('\n'));
|
2087
|
+
Selector._cache[this.expression] = this.matcher;
|
2088
|
+
},
|
2089
|
+
|
2090
|
+
compileXPathMatcher: function() {
|
2091
|
+
var e = this.expression, ps = Selector.patterns,
|
2092
|
+
x = Selector.xpath, le, m;
|
2093
|
+
|
2094
|
+
if (Selector._cache[e]) {
|
2095
|
+
this.xpath = Selector._cache[e]; return;
|
2096
|
+
}
|
2097
|
+
|
2098
|
+
this.matcher = ['.//*'];
|
2099
|
+
while (e && le != e && (/\S/).test(e)) {
|
2100
|
+
le = e;
|
2101
|
+
for (var i in ps) {
|
2102
|
+
if (m = e.match(ps[i])) {
|
2103
|
+
this.matcher.push(typeof x[i] == 'function' ? x[i](m) :
|
2104
|
+
new Template(x[i]).evaluate(m));
|
2105
|
+
e = e.replace(m[0], '');
|
2106
|
+
break;
|
2107
|
+
}
|
2108
|
+
}
|
2109
|
+
}
|
2110
|
+
|
2111
|
+
this.xpath = this.matcher.join('');
|
2112
|
+
Selector._cache[this.expression] = this.xpath;
|
2113
|
+
},
|
2114
|
+
|
2115
|
+
findElements: function(root) {
|
2116
|
+
root = root || document;
|
2117
|
+
if (this.xpath) return document._getElementsByXPath(this.xpath, root);
|
2118
|
+
return this.matcher(root);
|
2119
|
+
},
|
2120
|
+
|
2121
|
+
match: function(element) {
|
2122
|
+
return this.findElements(document).include(element);
|
2123
|
+
},
|
2124
|
+
|
2125
|
+
toString: function() {
|
2126
|
+
return this.expression;
|
2127
|
+
},
|
2128
|
+
|
2129
|
+
inspect: function() {
|
2130
|
+
return "#<Selector:" + this.expression.inspect() + ">";
|
2131
|
+
}
|
2132
|
+
};
|
2133
|
+
|
2134
|
+
Object.extend(Selector, {
|
2135
|
+
_cache: {},
|
2136
|
+
|
2137
|
+
xpath: {
|
2138
|
+
descendant: "//*",
|
2139
|
+
child: "/*",
|
2140
|
+
adjacent: "/following-sibling::*[1]",
|
2141
|
+
laterSibling: '/following-sibling::*',
|
2142
|
+
tagName: function(m) {
|
2143
|
+
if (m[1] == '*') return '';
|
2144
|
+
return "[local-name()='" + m[1].toLowerCase() +
|
2145
|
+
"' or local-name()='" + m[1].toUpperCase() + "']";
|
2146
|
+
},
|
2147
|
+
className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
|
2148
|
+
id: "[@id='#{1}']",
|
2149
|
+
attrPresence: "[@#{1}]",
|
2150
|
+
attr: function(m) {
|
2151
|
+
m[3] = m[5] || m[6];
|
2152
|
+
return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
|
2153
|
+
},
|
2154
|
+
pseudo: function(m) {
|
2155
|
+
var h = Selector.xpath.pseudos[m[1]];
|
2156
|
+
if (!h) return '';
|
2157
|
+
if (typeof h === 'function') return h(m);
|
2158
|
+
return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
|
2159
|
+
},
|
2160
|
+
operators: {
|
2161
|
+
'=': "[@#{1}='#{3}']",
|
2162
|
+
'!=': "[@#{1}!='#{3}']",
|
2163
|
+
'^=': "[starts-with(@#{1}, '#{3}')]",
|
2164
|
+
'$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
|
2165
|
+
'*=': "[contains(@#{1}, '#{3}')]",
|
2166
|
+
'~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
|
2167
|
+
'|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
|
2168
|
+
},
|
2169
|
+
pseudos: {
|
2170
|
+
'first-child': '[not(preceding-sibling::*)]',
|
2171
|
+
'last-child': '[not(following-sibling::*)]',
|
2172
|
+
'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
|
2173
|
+
'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
|
2174
|
+
'checked': "[@checked]",
|
2175
|
+
'disabled': "[@disabled]",
|
2176
|
+
'enabled': "[not(@disabled)]",
|
2177
|
+
'not': function(m) {
|
2178
|
+
var e = m[6], p = Selector.patterns,
|
2179
|
+
x = Selector.xpath, le, m, v;
|
2180
|
+
|
2181
|
+
var exclusion = [];
|
2182
|
+
while (e && le != e && (/\S/).test(e)) {
|
2183
|
+
le = e;
|
2184
|
+
for (var i in p) {
|
2185
|
+
if (m = e.match(p[i])) {
|
2186
|
+
v = typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m);
|
2187
|
+
exclusion.push("(" + v.substring(1, v.length - 1) + ")");
|
2188
|
+
e = e.replace(m[0], '');
|
2189
|
+
break;
|
2190
|
+
}
|
2191
|
+
}
|
2192
|
+
}
|
2193
|
+
return "[not(" + exclusion.join(" and ") + ")]";
|
2194
|
+
},
|
2195
|
+
'nth-child': function(m) {
|
2196
|
+
return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
|
2197
|
+
},
|
2198
|
+
'nth-last-child': function(m) {
|
2199
|
+
return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
|
2200
|
+
},
|
2201
|
+
'nth-of-type': function(m) {
|
2202
|
+
return Selector.xpath.pseudos.nth("position() ", m);
|
2203
|
+
},
|
2204
|
+
'nth-last-of-type': function(m) {
|
2205
|
+
return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
|
2206
|
+
},
|
2207
|
+
'first-of-type': function(m) {
|
2208
|
+
m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
|
2209
|
+
},
|
2210
|
+
'last-of-type': function(m) {
|
2211
|
+
m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
|
2212
|
+
},
|
2213
|
+
'only-of-type': function(m) {
|
2214
|
+
var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
|
2215
|
+
},
|
2216
|
+
nth: function(fragment, m) {
|
2217
|
+
var mm, formula = m[6], predicate;
|
2218
|
+
if (formula == 'even') formula = '2n+0';
|
2219
|
+
if (formula == 'odd') formula = '2n+1';
|
2220
|
+
if (mm = formula.match(/^(\d+)$/)) // digit only
|
2221
|
+
return '[' + fragment + "= " + mm[1] + ']';
|
2222
|
+
if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
|
2223
|
+
if (mm[1] == "-") mm[1] = -1;
|
2224
|
+
var a = mm[1] ? Number(mm[1]) : 1;
|
2225
|
+
var b = mm[2] ? Number(mm[2]) : 0;
|
2226
|
+
predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
|
2227
|
+
"((#{fragment} - #{b}) div #{a} >= 0)]";
|
2228
|
+
return new Template(predicate).evaluate({
|
2229
|
+
fragment: fragment, a: a, b: b });
|
2230
|
+
}
|
2231
|
+
}
|
2232
|
+
}
|
2233
|
+
},
|
2234
|
+
|
2235
|
+
criteria: {
|
2236
|
+
tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
|
2237
|
+
className: 'n = h.className(n, r, "#{1}", c); c = false;',
|
2238
|
+
id: 'n = h.id(n, r, "#{1}", c); c = false;',
|
2239
|
+
attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
|
2240
|
+
attr: function(m) {
|
2241
|
+
m[3] = (m[5] || m[6]);
|
2242
|
+
return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
|
2243
|
+
},
|
2244
|
+
pseudo: function(m) {
|
2245
|
+
if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
|
2246
|
+
return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
|
2247
|
+
},
|
2248
|
+
descendant: 'c = "descendant";',
|
2249
|
+
child: 'c = "child";',
|
2250
|
+
adjacent: 'c = "adjacent";',
|
2251
|
+
laterSibling: 'c = "laterSibling";'
|
2252
|
+
},
|
2253
|
+
|
2254
|
+
patterns: {
|
2255
|
+
// combinators must be listed first
|
2256
|
+
// (and descendant needs to be last combinator)
|
2257
|
+
laterSibling: /^\s*~\s*/,
|
2258
|
+
child: /^\s*>\s*/,
|
2259
|
+
adjacent: /^\s*\+\s*/,
|
2260
|
+
descendant: /^\s/,
|
2261
|
+
|
2262
|
+
// selectors follow
|
2263
|
+
tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
|
2264
|
+
id: /^#([\w\-\*]+)(\b|$)/,
|
2265
|
+
className: /^\.([\w\-\*]+)(\b|$)/,
|
2266
|
+
pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s|(?=:))/,
|
2267
|
+
attrPresence: /^\[([\w]+)\]/,
|
2268
|
+
attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/
|
2269
|
+
},
|
2270
|
+
|
2271
|
+
handlers: {
|
2272
|
+
// UTILITY FUNCTIONS
|
2273
|
+
// joins two collections
|
2274
|
+
concat: function(a, b) {
|
2275
|
+
for (var i = 0, node; node = b[i]; i++)
|
2276
|
+
a.push(node);
|
2277
|
+
return a;
|
2278
|
+
},
|
2279
|
+
|
2280
|
+
// marks an array of nodes for counting
|
2281
|
+
mark: function(nodes) {
|
2282
|
+
for (var i = 0, node; node = nodes[i]; i++)
|
2283
|
+
node._counted = true;
|
2284
|
+
return nodes;
|
2285
|
+
},
|
2286
|
+
|
2287
|
+
unmark: function(nodes) {
|
2288
|
+
for (var i = 0, node; node = nodes[i]; i++)
|
2289
|
+
node._counted = undefined;
|
2290
|
+
return nodes;
|
2291
|
+
},
|
2292
|
+
|
2293
|
+
// mark each child node with its position (for nth calls)
|
2294
|
+
// "ofType" flag indicates whether we're indexing for nth-of-type
|
2295
|
+
// rather than nth-child
|
2296
|
+
index: function(parentNode, reverse, ofType) {
|
2297
|
+
parentNode._counted = true;
|
2298
|
+
if (reverse) {
|
2299
|
+
for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
|
2300
|
+
node = nodes[i];
|
2301
|
+
if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
|
2302
|
+
}
|
2303
|
+
} else {
|
2304
|
+
for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
|
2305
|
+
if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
|
2306
|
+
}
|
2307
|
+
},
|
2308
|
+
|
2309
|
+
// filters out duplicates and extends all nodes
|
2310
|
+
unique: function(nodes) {
|
2311
|
+
if (nodes.length == 0) return nodes;
|
2312
|
+
var results = [], n;
|
2313
|
+
for (var i = 0, l = nodes.length; i < l; i++)
|
2314
|
+
if (!(n = nodes[i])._counted) {
|
2315
|
+
n._counted = true;
|
2316
|
+
results.push(Element.extend(n));
|
2317
|
+
}
|
2318
|
+
return Selector.handlers.unmark(results);
|
2319
|
+
},
|
2320
|
+
|
2321
|
+
// COMBINATOR FUNCTIONS
|
2322
|
+
descendant: function(nodes) {
|
2323
|
+
var h = Selector.handlers;
|
2324
|
+
for (var i = 0, results = [], node; node = nodes[i]; i++)
|
2325
|
+
h.concat(results, node.getElementsByTagName('*'));
|
2326
|
+
return results;
|
2327
|
+
},
|
2328
|
+
|
2329
|
+
child: function(nodes) {
|
2330
|
+
var h = Selector.handlers;
|
2331
|
+
for (var i = 0, results = [], node; node = nodes[i]; i++) {
|
2332
|
+
for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
|
2333
|
+
if (child.nodeType == 1 && child.tagName != '!') results.push(child);
|
2334
|
+
}
|
2335
|
+
return results;
|
2336
|
+
},
|
2337
|
+
|
2338
|
+
adjacent: function(nodes) {
|
2339
|
+
for (var i = 0, results = [], node; node = nodes[i]; i++) {
|
2340
|
+
var next = this.nextElementSibling(node);
|
2341
|
+
if (next) results.push(next);
|
2342
|
+
}
|
2343
|
+
return results;
|
2344
|
+
},
|
2345
|
+
|
2346
|
+
laterSibling: function(nodes) {
|
2347
|
+
var h = Selector.handlers;
|
2348
|
+
for (var i = 0, results = [], node; node = nodes[i]; i++)
|
2349
|
+
h.concat(results, Element.nextSiblings(node));
|
2350
|
+
return results;
|
2351
|
+
},
|
2352
|
+
|
2353
|
+
nextElementSibling: function(node) {
|
2354
|
+
while (node = node.nextSibling)
|
2355
|
+
if (node.nodeType == 1) return node;
|
2356
|
+
return null;
|
2357
|
+
},
|
2358
|
+
|
2359
|
+
previousElementSibling: function(node) {
|
2360
|
+
while (node = node.previousSibling)
|
2361
|
+
if (node.nodeType == 1) return node;
|
2362
|
+
return null;
|
2363
|
+
},
|
2364
|
+
|
2365
|
+
// TOKEN FUNCTIONS
|
2366
|
+
tagName: function(nodes, root, tagName, combinator) {
|
2367
|
+
tagName = tagName.toUpperCase();
|
2368
|
+
var results = [], h = Selector.handlers;
|
2369
|
+
if (nodes) {
|
2370
|
+
if (combinator) {
|
2371
|
+
// fastlane for ordinary descendant combinators
|
2372
|
+
if (combinator == "descendant") {
|
2373
|
+
for (var i = 0, node; node = nodes[i]; i++)
|
2374
|
+
h.concat(results, node.getElementsByTagName(tagName));
|
2375
|
+
return results;
|
2376
|
+
} else nodes = this[combinator](nodes);
|
2377
|
+
if (tagName == "*") return nodes;
|
2378
|
+
}
|
2379
|
+
for (var i = 0, node; node = nodes[i]; i++)
|
2380
|
+
if (node.tagName.toUpperCase() == tagName) results.push(node);
|
2381
|
+
return results;
|
2382
|
+
} else return root.getElementsByTagName(tagName);
|
2383
|
+
},
|
2384
|
+
|
2385
|
+
id: function(nodes, root, id, combinator) {
|
2386
|
+
var targetNode = $(id), h = Selector.handlers;
|
2387
|
+
if (!nodes && root == document) return targetNode ? [targetNode] : [];
|
2388
|
+
if (nodes) {
|
2389
|
+
if (combinator) {
|
2390
|
+
if (combinator == 'child') {
|
2391
|
+
for (var i = 0, node; node = nodes[i]; i++)
|
2392
|
+
if (targetNode.parentNode == node) return [targetNode];
|
2393
|
+
} else if (combinator == 'descendant') {
|
2394
|
+
for (var i = 0, node; node = nodes[i]; i++)
|
2395
|
+
if (Element.descendantOf(targetNode, node)) return [targetNode];
|
2396
|
+
} else if (combinator == 'adjacent') {
|
2397
|
+
for (var i = 0, node; node = nodes[i]; i++)
|
2398
|
+
if (Selector.handlers.previousElementSibling(targetNode) == node)
|
2399
|
+
return [targetNode];
|
2400
|
+
} else nodes = h[combinator](nodes);
|
2401
|
+
}
|
2402
|
+
for (var i = 0, node; node = nodes[i]; i++)
|
2403
|
+
if (node == targetNode) return [targetNode];
|
2404
|
+
return [];
|
2405
|
+
}
|
2406
|
+
return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
|
2407
|
+
},
|
2408
|
+
|
2409
|
+
className: function(nodes, root, className, combinator) {
|
2410
|
+
if (nodes && combinator) nodes = this[combinator](nodes);
|
2411
|
+
return Selector.handlers.byClassName(nodes, root, className);
|
2412
|
+
},
|
2413
|
+
|
2414
|
+
byClassName: function(nodes, root, className) {
|
2415
|
+
if (!nodes) nodes = Selector.handlers.descendant([root]);
|
2416
|
+
var needle = ' ' + className + ' ';
|
2417
|
+
for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
|
2418
|
+
nodeClassName = node.className;
|
2419
|
+
if (nodeClassName.length == 0) continue;
|
2420
|
+
if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
|
2421
|
+
results.push(node);
|
2422
|
+
}
|
2423
|
+
return results;
|
2424
|
+
},
|
2425
|
+
|
2426
|
+
attrPresence: function(nodes, root, attr) {
|
2427
|
+
var results = [];
|
2428
|
+
for (var i = 0, node; node = nodes[i]; i++)
|
2429
|
+
if (Element.hasAttribute(node, attr)) results.push(node);
|
2430
|
+
return results;
|
2431
|
+
},
|
2432
|
+
|
2433
|
+
attr: function(nodes, root, attr, value, operator) {
|
2434
|
+
if (!nodes) nodes = root.getElementsByTagName("*");
|
2435
|
+
var handler = Selector.operators[operator], results = [];
|
2436
|
+
for (var i = 0, node; node = nodes[i]; i++) {
|
2437
|
+
var nodeValue = Element.readAttribute(node, attr);
|
2438
|
+
if (nodeValue === null) continue;
|
2439
|
+
if (handler(nodeValue, value)) results.push(node);
|
2440
|
+
}
|
2441
|
+
return results;
|
2442
|
+
},
|
2443
|
+
|
2444
|
+
pseudo: function(nodes, name, value, root, combinator) {
|
2445
|
+
if (nodes && combinator) nodes = this[combinator](nodes);
|
2446
|
+
if (!nodes) nodes = root.getElementsByTagName("*");
|
2447
|
+
return Selector.pseudos[name](nodes, value, root);
|
2448
|
+
}
|
2449
|
+
},
|
2450
|
+
|
2451
|
+
pseudos: {
|
2452
|
+
'first-child': function(nodes, value, root) {
|
2453
|
+
for (var i = 0, results = [], node; node = nodes[i]; i++) {
|
2454
|
+
if (Selector.handlers.previousElementSibling(node)) continue;
|
2455
|
+
results.push(node);
|
2456
|
+
}
|
2457
|
+
return results;
|
2458
|
+
},
|
2459
|
+
'last-child': function(nodes, value, root) {
|
2460
|
+
for (var i = 0, results = [], node; node = nodes[i]; i++) {
|
2461
|
+
if (Selector.handlers.nextElementSibling(node)) continue;
|
2462
|
+
results.push(node);
|
2463
|
+
}
|
2464
|
+
return results;
|
2465
|
+
},
|
2466
|
+
'only-child': function(nodes, value, root) {
|
2467
|
+
var h = Selector.handlers;
|
2468
|
+
for (var i = 0, results = [], node; node = nodes[i]; i++)
|
2469
|
+
if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
|
2470
|
+
results.push(node);
|
2471
|
+
return results;
|
2472
|
+
},
|
2473
|
+
'nth-child': function(nodes, formula, root) {
|
2474
|
+
return Selector.pseudos.nth(nodes, formula, root);
|
2475
|
+
},
|
2476
|
+
'nth-last-child': function(nodes, formula, root) {
|
2477
|
+
return Selector.pseudos.nth(nodes, formula, root, true);
|
2478
|
+
},
|
2479
|
+
'nth-of-type': function(nodes, formula, root) {
|
2480
|
+
return Selector.pseudos.nth(nodes, formula, root, false, true);
|
2481
|
+
},
|
2482
|
+
'nth-last-of-type': function(nodes, formula, root) {
|
2483
|
+
return Selector.pseudos.nth(nodes, formula, root, true, true);
|
2484
|
+
},
|
2485
|
+
'first-of-type': function(nodes, formula, root) {
|
2486
|
+
return Selector.pseudos.nth(nodes, "1", root, false, true);
|
2487
|
+
},
|
2488
|
+
'last-of-type': function(nodes, formula, root) {
|
2489
|
+
return Selector.pseudos.nth(nodes, "1", root, true, true);
|
2490
|
+
},
|
2491
|
+
'only-of-type': function(nodes, formula, root) {
|
2492
|
+
var p = Selector.pseudos;
|
2493
|
+
return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
|
2494
|
+
},
|
2495
|
+
|
2496
|
+
// handles the an+b logic
|
2497
|
+
getIndices: function(a, b, total) {
|
2498
|
+
if (a == 0) return b > 0 ? [b] : [];
|
2499
|
+
return $R(1, total).inject([], function(memo, i) {
|
2500
|
+
if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
|
2501
|
+
return memo;
|
2502
|
+
});
|
2503
|
+
},
|
2504
|
+
|
2505
|
+
// handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
|
2506
|
+
nth: function(nodes, formula, root, reverse, ofType) {
|
2507
|
+
if (nodes.length == 0) return [];
|
2508
|
+
if (formula == 'even') formula = '2n+0';
|
2509
|
+
if (formula == 'odd') formula = '2n+1';
|
2510
|
+
var h = Selector.handlers, results = [], indexed = [], m;
|
2511
|
+
h.mark(nodes);
|
2512
|
+
for (var i = 0, node; node = nodes[i]; i++) {
|
2513
|
+
if (!node.parentNode._counted) {
|
2514
|
+
h.index(node.parentNode, reverse, ofType);
|
2515
|
+
indexed.push(node.parentNode);
|
2516
|
+
}
|
2517
|
+
}
|
2518
|
+
if (formula.match(/^\d+$/)) { // just a number
|
2519
|
+
formula = Number(formula);
|
2520
|
+
for (var i = 0, node; node = nodes[i]; i++)
|
2521
|
+
if (node.nodeIndex == formula) results.push(node);
|
2522
|
+
} else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
|
2523
|
+
if (m[1] == "-") m[1] = -1;
|
2524
|
+
var a = m[1] ? Number(m[1]) : 1;
|
2525
|
+
var b = m[2] ? Number(m[2]) : 0;
|
2526
|
+
var indices = Selector.pseudos.getIndices(a, b, nodes.length);
|
2527
|
+
for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
|
2528
|
+
for (var j = 0; j < l; j++)
|
2529
|
+
if (node.nodeIndex == indices[j]) results.push(node);
|
2530
|
+
}
|
2531
|
+
}
|
2532
|
+
h.unmark(nodes);
|
2533
|
+
h.unmark(indexed);
|
2534
|
+
return results;
|
2535
|
+
},
|
2536
|
+
|
2537
|
+
'empty': function(nodes, value, root) {
|
2538
|
+
for (var i = 0, results = [], node; node = nodes[i]; i++) {
|
2539
|
+
// IE treats comments as element nodes
|
2540
|
+
if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
|
2541
|
+
results.push(node);
|
2542
|
+
}
|
2543
|
+
return results;
|
2544
|
+
},
|
2545
|
+
|
2546
|
+
'not': function(nodes, selector, root) {
|
2547
|
+
var h = Selector.handlers, selectorType, m;
|
2548
|
+
var exclusions = new Selector(selector).findElements(root);
|
2549
|
+
h.mark(exclusions);
|
2550
|
+
for (var i = 0, results = [], node; node = nodes[i]; i++)
|
2551
|
+
if (!node._counted) results.push(node);
|
2552
|
+
h.unmark(exclusions);
|
2553
|
+
return results;
|
2554
|
+
},
|
2555
|
+
|
2556
|
+
'enabled': function(nodes, value, root) {
|
2557
|
+
for (var i = 0, results = [], node; node = nodes[i]; i++)
|
2558
|
+
if (!node.disabled) results.push(node);
|
2559
|
+
return results;
|
2560
|
+
},
|
2561
|
+
|
2562
|
+
'disabled': function(nodes, value, root) {
|
2563
|
+
for (var i = 0, results = [], node; node = nodes[i]; i++)
|
2564
|
+
if (node.disabled) results.push(node);
|
2565
|
+
return results;
|
2566
|
+
},
|
2567
|
+
|
2568
|
+
'checked': function(nodes, value, root) {
|
2569
|
+
for (var i = 0, results = [], node; node = nodes[i]; i++)
|
2570
|
+
if (node.checked) results.push(node);
|
2571
|
+
return results;
|
2572
|
+
}
|
2573
|
+
},
|
2574
|
+
|
2575
|
+
operators: {
|
2576
|
+
'=': function(nv, v) { return nv == v; },
|
2577
|
+
'!=': function(nv, v) { return nv != v; },
|
2578
|
+
'^=': function(nv, v) { return nv.startsWith(v); },
|
2579
|
+
'$=': function(nv, v) { return nv.endsWith(v); },
|
2580
|
+
'*=': function(nv, v) { return nv.include(v); },
|
2581
|
+
'~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
|
2582
|
+
'|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
|
2583
|
+
},
|
2584
|
+
|
2585
|
+
matchElements: function(elements, expression) {
|
2586
|
+
var matches = new Selector(expression).findElements(), h = Selector.handlers;
|
2587
|
+
h.mark(matches);
|
2588
|
+
for (var i = 0, results = [], element; element = elements[i]; i++)
|
2589
|
+
if (element._counted) results.push(element);
|
2590
|
+
h.unmark(matches);
|
2591
|
+
return results;
|
2592
|
+
},
|
2593
|
+
|
2594
|
+
findElement: function(elements, expression, index) {
|
2595
|
+
if (typeof expression == 'number') {
|
2596
|
+
index = expression; expression = false;
|
2597
|
+
}
|
2598
|
+
return Selector.matchElements(elements, expression || '*')[index || 0];
|
2599
|
+
},
|
2600
|
+
|
2601
|
+
findChildElements: function(element, expressions) {
|
2602
|
+
var exprs = expressions.join(','), expressions = [];
|
2603
|
+
exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
|
2604
|
+
expressions.push(m[1].strip());
|
2605
|
+
});
|
2606
|
+
var results = [], h = Selector.handlers;
|
2607
|
+
for (var i = 0, l = expressions.length, selector; i < l; i++) {
|
2608
|
+
selector = new Selector(expressions[i].strip());
|
2609
|
+
h.concat(results, selector.findElements(element));
|
2610
|
+
}
|
2611
|
+
return (l > 1) ? h.unique(results) : results;
|
2612
|
+
}
|
2613
|
+
});
|
2614
|
+
|
2615
|
+
function $$() {
|
2616
|
+
return Selector.findChildElements(document, $A(arguments));
|
2617
|
+
}
|
2618
|
+
var Form = {
|
2619
|
+
reset: function(form) {
|
2620
|
+
$(form).reset();
|
2621
|
+
return form;
|
2622
|
+
},
|
2623
|
+
|
2624
|
+
serializeElements: function(elements, getHash) {
|
2625
|
+
var data = elements.inject({}, function(result, element) {
|
2626
|
+
if (!element.disabled && element.name) {
|
2627
|
+
var key = element.name, value = $(element).getValue();
|
2628
|
+
if (value != null) {
|
2629
|
+
if (key in result) {
|
2630
|
+
if (result[key].constructor != Array) result[key] = [result[key]];
|
2631
|
+
result[key].push(value);
|
2632
|
+
}
|
2633
|
+
else result[key] = value;
|
2634
|
+
}
|
2635
|
+
}
|
2636
|
+
return result;
|
2637
|
+
});
|
2638
|
+
|
2639
|
+
return getHash ? data : Hash.toQueryString(data);
|
2640
|
+
}
|
2641
|
+
};
|
2642
|
+
|
2643
|
+
Form.Methods = {
|
2644
|
+
serialize: function(form, getHash) {
|
2645
|
+
return Form.serializeElements(Form.getElements(form), getHash);
|
2646
|
+
},
|
2647
|
+
|
2648
|
+
getElements: function(form) {
|
2649
|
+
return $A($(form).getElementsByTagName('*')).inject([],
|
2650
|
+
function(elements, child) {
|
2651
|
+
if (Form.Element.Serializers[child.tagName.toLowerCase()])
|
2652
|
+
elements.push(Element.extend(child));
|
2653
|
+
return elements;
|
2654
|
+
}
|
2655
|
+
);
|
2656
|
+
},
|
2657
|
+
|
2658
|
+
getInputs: function(form, typeName, name) {
|
2659
|
+
form = $(form);
|
2660
|
+
var inputs = form.getElementsByTagName('input');
|
2661
|
+
|
2662
|
+
if (!typeName && !name) return $A(inputs).map(Element.extend);
|
2663
|
+
|
2664
|
+
for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
|
2665
|
+
var input = inputs[i];
|
2666
|
+
if ((typeName && input.type != typeName) || (name && input.name != name))
|
2667
|
+
continue;
|
2668
|
+
matchingInputs.push(Element.extend(input));
|
2669
|
+
}
|
2670
|
+
|
2671
|
+
return matchingInputs;
|
2672
|
+
},
|
2673
|
+
|
2674
|
+
disable: function(form) {
|
2675
|
+
form = $(form);
|
2676
|
+
Form.getElements(form).invoke('disable');
|
2677
|
+
return form;
|
2678
|
+
},
|
2679
|
+
|
2680
|
+
enable: function(form) {
|
2681
|
+
form = $(form);
|
2682
|
+
Form.getElements(form).invoke('enable');
|
2683
|
+
return form;
|
2684
|
+
},
|
2685
|
+
|
2686
|
+
findFirstElement: function(form) {
|
2687
|
+
return $(form).getElements().find(function(element) {
|
2688
|
+
return element.type != 'hidden' && !element.disabled &&
|
2689
|
+
['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
|
2690
|
+
});
|
2691
|
+
},
|
2692
|
+
|
2693
|
+
focusFirstElement: function(form) {
|
2694
|
+
form = $(form);
|
2695
|
+
form.findFirstElement().activate();
|
2696
|
+
return form;
|
2697
|
+
},
|
2698
|
+
|
2699
|
+
request: function(form, options) {
|
2700
|
+
form = $(form), options = Object.clone(options || {});
|
2701
|
+
|
2702
|
+
var params = options.parameters;
|
2703
|
+
options.parameters = form.serialize(true);
|
2704
|
+
|
2705
|
+
if (params) {
|
2706
|
+
if (typeof params == 'string') params = params.toQueryParams();
|
2707
|
+
Object.extend(options.parameters, params);
|
2708
|
+
}
|
2709
|
+
|
2710
|
+
if (form.hasAttribute('method') && !options.method)
|
2711
|
+
options.method = form.method;
|
2712
|
+
|
2713
|
+
return new Ajax.Request(form.readAttribute('action'), options);
|
2714
|
+
}
|
2715
|
+
}
|
2716
|
+
|
2717
|
+
/*--------------------------------------------------------------------------*/
|
2718
|
+
|
2719
|
+
Form.Element = {
|
2720
|
+
focus: function(element) {
|
2721
|
+
$(element).focus();
|
2722
|
+
return element;
|
2723
|
+
},
|
2724
|
+
|
2725
|
+
select: function(element) {
|
2726
|
+
$(element).select();
|
2727
|
+
return element;
|
2728
|
+
}
|
2729
|
+
}
|
2730
|
+
|
2731
|
+
Form.Element.Methods = {
|
2732
|
+
serialize: function(element) {
|
2733
|
+
element = $(element);
|
2734
|
+
if (!element.disabled && element.name) {
|
2735
|
+
var value = element.getValue();
|
2736
|
+
if (value != undefined) {
|
2737
|
+
var pair = {};
|
2738
|
+
pair[element.name] = value;
|
2739
|
+
return Hash.toQueryString(pair);
|
2740
|
+
}
|
2741
|
+
}
|
2742
|
+
return '';
|
2743
|
+
},
|
2744
|
+
|
2745
|
+
getValue: function(element) {
|
2746
|
+
element = $(element);
|
2747
|
+
var method = element.tagName.toLowerCase();
|
2748
|
+
return Form.Element.Serializers[method](element);
|
2749
|
+
},
|
2750
|
+
|
2751
|
+
clear: function(element) {
|
2752
|
+
$(element).value = '';
|
2753
|
+
return element;
|
2754
|
+
},
|
2755
|
+
|
2756
|
+
present: function(element) {
|
2757
|
+
return $(element).value != '';
|
2758
|
+
},
|
2759
|
+
|
2760
|
+
activate: function(element) {
|
2761
|
+
element = $(element);
|
2762
|
+
try {
|
2763
|
+
element.focus();
|
2764
|
+
if (element.select && (element.tagName.toLowerCase() != 'input' ||
|
2765
|
+
!['button', 'reset', 'submit'].include(element.type)))
|
2766
|
+
element.select();
|
2767
|
+
} catch (e) {}
|
2768
|
+
return element;
|
2769
|
+
},
|
2770
|
+
|
2771
|
+
disable: function(element) {
|
2772
|
+
element = $(element);
|
2773
|
+
element.blur();
|
2774
|
+
element.disabled = true;
|
2775
|
+
return element;
|
2776
|
+
},
|
2777
|
+
|
2778
|
+
enable: function(element) {
|
2779
|
+
element = $(element);
|
2780
|
+
element.disabled = false;
|
2781
|
+
return element;
|
2782
|
+
}
|
2783
|
+
}
|
2784
|
+
|
2785
|
+
/*--------------------------------------------------------------------------*/
|
2786
|
+
|
2787
|
+
var Field = Form.Element;
|
2788
|
+
var $F = Form.Element.Methods.getValue;
|
2789
|
+
|
2790
|
+
/*--------------------------------------------------------------------------*/
|
2791
|
+
|
2792
|
+
Form.Element.Serializers = {
|
2793
|
+
input: function(element) {
|
2794
|
+
switch (element.type.toLowerCase()) {
|
2795
|
+
case 'checkbox':
|
2796
|
+
case 'radio':
|
2797
|
+
return Form.Element.Serializers.inputSelector(element);
|
2798
|
+
default:
|
2799
|
+
return Form.Element.Serializers.textarea(element);
|
2800
|
+
}
|
2801
|
+
},
|
2802
|
+
|
2803
|
+
inputSelector: function(element) {
|
2804
|
+
return element.checked ? element.value : null;
|
2805
|
+
},
|
2806
|
+
|
2807
|
+
textarea: function(element) {
|
2808
|
+
return element.value;
|
2809
|
+
},
|
2810
|
+
|
2811
|
+
select: function(element) {
|
2812
|
+
return this[element.type == 'select-one' ?
|
2813
|
+
'selectOne' : 'selectMany'](element);
|
2814
|
+
},
|
2815
|
+
|
2816
|
+
selectOne: function(element) {
|
2817
|
+
var index = element.selectedIndex;
|
2818
|
+
return index >= 0 ? this.optionValue(element.options[index]) : null;
|
2819
|
+
},
|
2820
|
+
|
2821
|
+
selectMany: function(element) {
|
2822
|
+
var values, length = element.length;
|
2823
|
+
if (!length) return null;
|
2824
|
+
|
2825
|
+
for (var i = 0, values = []; i < length; i++) {
|
2826
|
+
var opt = element.options[i];
|
2827
|
+
if (opt.selected) values.push(this.optionValue(opt));
|
2828
|
+
}
|
2829
|
+
return values;
|
2830
|
+
},
|
2831
|
+
|
2832
|
+
optionValue: function(opt) {
|
2833
|
+
// extend element because hasAttribute may not be native
|
2834
|
+
return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
|
2835
|
+
}
|
2836
|
+
}
|
2837
|
+
|
2838
|
+
/*--------------------------------------------------------------------------*/
|
2839
|
+
|
2840
|
+
Abstract.TimedObserver = function() {}
|
2841
|
+
Abstract.TimedObserver.prototype = {
|
2842
|
+
initialize: function(element, frequency, callback) {
|
2843
|
+
this.frequency = frequency;
|
2844
|
+
this.element = $(element);
|
2845
|
+
this.callback = callback;
|
2846
|
+
|
2847
|
+
this.lastValue = this.getValue();
|
2848
|
+
this.registerCallback();
|
2849
|
+
},
|
2850
|
+
|
2851
|
+
registerCallback: function() {
|
2852
|
+
setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
|
2853
|
+
},
|
2854
|
+
|
2855
|
+
onTimerEvent: function() {
|
2856
|
+
var value = this.getValue();
|
2857
|
+
var changed = ('string' == typeof this.lastValue && 'string' == typeof value
|
2858
|
+
? this.lastValue != value : String(this.lastValue) != String(value));
|
2859
|
+
if (changed) {
|
2860
|
+
this.callback(this.element, value);
|
2861
|
+
this.lastValue = value;
|
2862
|
+
}
|
2863
|
+
}
|
2864
|
+
}
|
2865
|
+
|
2866
|
+
Form.Element.Observer = Class.create();
|
2867
|
+
Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
|
2868
|
+
getValue: function() {
|
2869
|
+
return Form.Element.getValue(this.element);
|
2870
|
+
}
|
2871
|
+
});
|
2872
|
+
|
2873
|
+
Form.Observer = Class.create();
|
2874
|
+
Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
|
2875
|
+
getValue: function() {
|
2876
|
+
return Form.serialize(this.element);
|
2877
|
+
}
|
2878
|
+
});
|
2879
|
+
|
2880
|
+
/*--------------------------------------------------------------------------*/
|
2881
|
+
|
2882
|
+
Abstract.EventObserver = function() {}
|
2883
|
+
Abstract.EventObserver.prototype = {
|
2884
|
+
initialize: function(element, callback) {
|
2885
|
+
this.element = $(element);
|
2886
|
+
this.callback = callback;
|
2887
|
+
|
2888
|
+
this.lastValue = this.getValue();
|
2889
|
+
if (this.element.tagName.toLowerCase() == 'form')
|
2890
|
+
this.registerFormCallbacks();
|
2891
|
+
else
|
2892
|
+
this.registerCallback(this.element);
|
2893
|
+
},
|
2894
|
+
|
2895
|
+
onElementEvent: function() {
|
2896
|
+
var value = this.getValue();
|
2897
|
+
if (this.lastValue != value) {
|
2898
|
+
this.callback(this.element, value);
|
2899
|
+
this.lastValue = value;
|
2900
|
+
}
|
2901
|
+
},
|
2902
|
+
|
2903
|
+
registerFormCallbacks: function() {
|
2904
|
+
Form.getElements(this.element).each(this.registerCallback.bind(this));
|
2905
|
+
},
|
2906
|
+
|
2907
|
+
registerCallback: function(element) {
|
2908
|
+
if (element.type) {
|
2909
|
+
switch (element.type.toLowerCase()) {
|
2910
|
+
case 'checkbox':
|
2911
|
+
case 'radio':
|
2912
|
+
Event.observe(element, 'click', this.onElementEvent.bind(this));
|
2913
|
+
break;
|
2914
|
+
default:
|
2915
|
+
Event.observe(element, 'change', this.onElementEvent.bind(this));
|
2916
|
+
break;
|
2917
|
+
}
|
2918
|
+
}
|
2919
|
+
}
|
2920
|
+
}
|
2921
|
+
|
2922
|
+
Form.Element.EventObserver = Class.create();
|
2923
|
+
Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
|
2924
|
+
getValue: function() {
|
2925
|
+
return Form.Element.getValue(this.element);
|
2926
|
+
}
|
2927
|
+
});
|
2928
|
+
|
2929
|
+
Form.EventObserver = Class.create();
|
2930
|
+
Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
|
2931
|
+
getValue: function() {
|
2932
|
+
return Form.serialize(this.element);
|
2933
|
+
}
|
2934
|
+
});
|
2935
|
+
if (!window.Event) {
|
2936
|
+
var Event = new Object();
|
2937
|
+
}
|
2938
|
+
|
2939
|
+
Object.extend(Event, {
|
2940
|
+
KEY_BACKSPACE: 8,
|
2941
|
+
KEY_TAB: 9,
|
2942
|
+
KEY_RETURN: 13,
|
2943
|
+
KEY_ESC: 27,
|
2944
|
+
KEY_LEFT: 37,
|
2945
|
+
KEY_UP: 38,
|
2946
|
+
KEY_RIGHT: 39,
|
2947
|
+
KEY_DOWN: 40,
|
2948
|
+
KEY_DELETE: 46,
|
2949
|
+
KEY_HOME: 36,
|
2950
|
+
KEY_END: 35,
|
2951
|
+
KEY_PAGEUP: 33,
|
2952
|
+
KEY_PAGEDOWN: 34,
|
2953
|
+
|
2954
|
+
element: function(event) {
|
2955
|
+
return $(event.target || event.srcElement);
|
2956
|
+
},
|
2957
|
+
|
2958
|
+
isLeftClick: function(event) {
|
2959
|
+
return (((event.which) && (event.which == 1)) ||
|
2960
|
+
((event.button) && (event.button == 1)));
|
2961
|
+
},
|
2962
|
+
|
2963
|
+
pointerX: function(event) {
|
2964
|
+
return event.pageX || (event.clientX +
|
2965
|
+
(document.documentElement.scrollLeft || document.body.scrollLeft));
|
2966
|
+
},
|
2967
|
+
|
2968
|
+
pointerY: function(event) {
|
2969
|
+
return event.pageY || (event.clientY +
|
2970
|
+
(document.documentElement.scrollTop || document.body.scrollTop));
|
2971
|
+
},
|
2972
|
+
|
2973
|
+
stop: function(event) {
|
2974
|
+
if (event.preventDefault) {
|
2975
|
+
event.preventDefault();
|
2976
|
+
event.stopPropagation();
|
2977
|
+
} else {
|
2978
|
+
event.returnValue = false;
|
2979
|
+
event.cancelBubble = true;
|
2980
|
+
}
|
2981
|
+
},
|
2982
|
+
|
2983
|
+
// find the first node with the given tagName, starting from the
|
2984
|
+
// node the event was triggered on; traverses the DOM upwards
|
2985
|
+
findElement: function(event, tagName) {
|
2986
|
+
var element = Event.element(event);
|
2987
|
+
while (element.parentNode && (!element.tagName ||
|
2988
|
+
(element.tagName.toUpperCase() != tagName.toUpperCase())))
|
2989
|
+
element = element.parentNode;
|
2990
|
+
return element;
|
2991
|
+
},
|
2992
|
+
|
2993
|
+
observers: false,
|
2994
|
+
|
2995
|
+
_observeAndCache: function(element, name, observer, useCapture) {
|
2996
|
+
if (!this.observers) this.observers = [];
|
2997
|
+
if (element.addEventListener) {
|
2998
|
+
this.observers.push([element, name, observer, useCapture]);
|
2999
|
+
element.addEventListener(name, observer, useCapture);
|
3000
|
+
} else if (element.attachEvent) {
|
3001
|
+
this.observers.push([element, name, observer, useCapture]);
|
3002
|
+
element.attachEvent('on' + name, observer);
|
3003
|
+
}
|
3004
|
+
},
|
3005
|
+
|
3006
|
+
unloadCache: function() {
|
3007
|
+
if (!Event.observers) return;
|
3008
|
+
for (var i = 0, length = Event.observers.length; i < length; i++) {
|
3009
|
+
Event.stopObserving.apply(this, Event.observers[i]);
|
3010
|
+
Event.observers[i][0] = null;
|
3011
|
+
}
|
3012
|
+
Event.observers = false;
|
3013
|
+
},
|
3014
|
+
|
3015
|
+
observe: function(element, name, observer, useCapture) {
|
3016
|
+
element = $(element);
|
3017
|
+
useCapture = useCapture || false;
|
3018
|
+
|
3019
|
+
if (name == 'keypress' &&
|
3020
|
+
(Prototype.Browser.WebKit || element.attachEvent))
|
3021
|
+
name = 'keydown';
|
3022
|
+
|
3023
|
+
Event._observeAndCache(element, name, observer, useCapture);
|
3024
|
+
},
|
3025
|
+
|
3026
|
+
stopObserving: function(element, name, observer, useCapture) {
|
3027
|
+
element = $(element);
|
3028
|
+
useCapture = useCapture || false;
|
3029
|
+
|
3030
|
+
if (name == 'keypress' &&
|
3031
|
+
(Prototype.Browser.WebKit || element.attachEvent))
|
3032
|
+
name = 'keydown';
|
3033
|
+
|
3034
|
+
if (element.removeEventListener) {
|
3035
|
+
element.removeEventListener(name, observer, useCapture);
|
3036
|
+
} else if (element.detachEvent) {
|
3037
|
+
try {
|
3038
|
+
element.detachEvent('on' + name, observer);
|
3039
|
+
} catch (e) {}
|
3040
|
+
}
|
3041
|
+
}
|
3042
|
+
});
|
3043
|
+
|
3044
|
+
/* prevent memory leaks in IE */
|
3045
|
+
if (Prototype.Browser.IE)
|
3046
|
+
Event.observe(window, 'unload', Event.unloadCache, false);
|
3047
|
+
var Position = {
|
3048
|
+
// set to true if needed, warning: firefox performance problems
|
3049
|
+
// NOT neeeded for page scrolling, only if draggable contained in
|
3050
|
+
// scrollable elements
|
3051
|
+
includeScrollOffsets: false,
|
3052
|
+
|
3053
|
+
// must be called before calling withinIncludingScrolloffset, every time the
|
3054
|
+
// page is scrolled
|
3055
|
+
prepare: function() {
|
3056
|
+
this.deltaX = window.pageXOffset
|
3057
|
+
|| document.documentElement.scrollLeft
|
3058
|
+
|| document.body.scrollLeft
|
3059
|
+
|| 0;
|
3060
|
+
this.deltaY = window.pageYOffset
|
3061
|
+
|| document.documentElement.scrollTop
|
3062
|
+
|| document.body.scrollTop
|
3063
|
+
|| 0;
|
3064
|
+
},
|
3065
|
+
|
3066
|
+
realOffset: function(element) {
|
3067
|
+
var valueT = 0, valueL = 0;
|
3068
|
+
do {
|
3069
|
+
valueT += element.scrollTop || 0;
|
3070
|
+
valueL += element.scrollLeft || 0;
|
3071
|
+
element = element.parentNode;
|
3072
|
+
} while (element);
|
3073
|
+
return [valueL, valueT];
|
3074
|
+
},
|
3075
|
+
|
3076
|
+
cumulativeOffset: function(element) {
|
3077
|
+
var valueT = 0, valueL = 0;
|
3078
|
+
do {
|
3079
|
+
valueT += element.offsetTop || 0;
|
3080
|
+
valueL += element.offsetLeft || 0;
|
3081
|
+
element = element.offsetParent;
|
3082
|
+
} while (element);
|
3083
|
+
return [valueL, valueT];
|
3084
|
+
},
|
3085
|
+
|
3086
|
+
positionedOffset: function(element) {
|
3087
|
+
var valueT = 0, valueL = 0;
|
3088
|
+
do {
|
3089
|
+
valueT += element.offsetTop || 0;
|
3090
|
+
valueL += element.offsetLeft || 0;
|
3091
|
+
element = element.offsetParent;
|
3092
|
+
if (element) {
|
3093
|
+
if(element.tagName=='BODY') break;
|
3094
|
+
var p = Element.getStyle(element, 'position');
|
3095
|
+
if (p == 'relative' || p == 'absolute') break;
|
3096
|
+
}
|
3097
|
+
} while (element);
|
3098
|
+
return [valueL, valueT];
|
3099
|
+
},
|
3100
|
+
|
3101
|
+
offsetParent: function(element) {
|
3102
|
+
if (element.offsetParent) return element.offsetParent;
|
3103
|
+
if (element == document.body) return element;
|
3104
|
+
|
3105
|
+
while ((element = element.parentNode) && element != document.body)
|
3106
|
+
if (Element.getStyle(element, 'position') != 'static')
|
3107
|
+
return element;
|
3108
|
+
|
3109
|
+
return document.body;
|
3110
|
+
},
|
3111
|
+
|
3112
|
+
// caches x/y coordinate pair to use with overlap
|
3113
|
+
within: function(element, x, y) {
|
3114
|
+
if (this.includeScrollOffsets)
|
3115
|
+
return this.withinIncludingScrolloffsets(element, x, y);
|
3116
|
+
this.xcomp = x;
|
3117
|
+
this.ycomp = y;
|
3118
|
+
this.offset = this.cumulativeOffset(element);
|
3119
|
+
|
3120
|
+
return (y >= this.offset[1] &&
|
3121
|
+
y < this.offset[1] + element.offsetHeight &&
|
3122
|
+
x >= this.offset[0] &&
|
3123
|
+
x < this.offset[0] + element.offsetWidth);
|
3124
|
+
},
|
3125
|
+
|
3126
|
+
withinIncludingScrolloffsets: function(element, x, y) {
|
3127
|
+
var offsetcache = this.realOffset(element);
|
3128
|
+
|
3129
|
+
this.xcomp = x + offsetcache[0] - this.deltaX;
|
3130
|
+
this.ycomp = y + offsetcache[1] - this.deltaY;
|
3131
|
+
this.offset = this.cumulativeOffset(element);
|
3132
|
+
|
3133
|
+
return (this.ycomp >= this.offset[1] &&
|
3134
|
+
this.ycomp < this.offset[1] + element.offsetHeight &&
|
3135
|
+
this.xcomp >= this.offset[0] &&
|
3136
|
+
this.xcomp < this.offset[0] + element.offsetWidth);
|
3137
|
+
},
|
3138
|
+
|
3139
|
+
// within must be called directly before
|
3140
|
+
overlap: function(mode, element) {
|
3141
|
+
if (!mode) return 0;
|
3142
|
+
if (mode == 'vertical')
|
3143
|
+
return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
|
3144
|
+
element.offsetHeight;
|
3145
|
+
if (mode == 'horizontal')
|
3146
|
+
return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
|
3147
|
+
element.offsetWidth;
|
3148
|
+
},
|
3149
|
+
|
3150
|
+
page: function(forElement) {
|
3151
|
+
var valueT = 0, valueL = 0;
|
3152
|
+
|
3153
|
+
var element = forElement;
|
3154
|
+
do {
|
3155
|
+
valueT += element.offsetTop || 0;
|
3156
|
+
valueL += element.offsetLeft || 0;
|
3157
|
+
|
3158
|
+
// Safari fix
|
3159
|
+
if (element.offsetParent == document.body)
|
3160
|
+
if (Element.getStyle(element,'position')=='absolute') break;
|
3161
|
+
|
3162
|
+
} while (element = element.offsetParent);
|
3163
|
+
|
3164
|
+
element = forElement;
|
3165
|
+
do {
|
3166
|
+
if (!window.opera || element.tagName=='BODY') {
|
3167
|
+
valueT -= element.scrollTop || 0;
|
3168
|
+
valueL -= element.scrollLeft || 0;
|
3169
|
+
}
|
3170
|
+
} while (element = element.parentNode);
|
3171
|
+
|
3172
|
+
return [valueL, valueT];
|
3173
|
+
},
|
3174
|
+
|
3175
|
+
clone: function(source, target) {
|
3176
|
+
var options = Object.extend({
|
3177
|
+
setLeft: true,
|
3178
|
+
setTop: true,
|
3179
|
+
setWidth: true,
|
3180
|
+
setHeight: true,
|
3181
|
+
offsetTop: 0,
|
3182
|
+
offsetLeft: 0
|
3183
|
+
}, arguments[2] || {})
|
3184
|
+
|
3185
|
+
// find page position of source
|
3186
|
+
source = $(source);
|
3187
|
+
var p = Position.page(source);
|
3188
|
+
|
3189
|
+
// find coordinate system to use
|
3190
|
+
target = $(target);
|
3191
|
+
var delta = [0, 0];
|
3192
|
+
var parent = null;
|
3193
|
+
// delta [0,0] will do fine with position: fixed elements,
|
3194
|
+
// position:absolute needs offsetParent deltas
|
3195
|
+
if (Element.getStyle(target,'position') == 'absolute') {
|
3196
|
+
parent = Position.offsetParent(target);
|
3197
|
+
delta = Position.page(parent);
|
3198
|
+
}
|
3199
|
+
|
3200
|
+
// correct by body offsets (fixes Safari)
|
3201
|
+
if (parent == document.body) {
|
3202
|
+
delta[0] -= document.body.offsetLeft;
|
3203
|
+
delta[1] -= document.body.offsetTop;
|
3204
|
+
}
|
3205
|
+
|
3206
|
+
// set position
|
3207
|
+
if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
|
3208
|
+
if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
|
3209
|
+
if(options.setWidth) target.style.width = source.offsetWidth + 'px';
|
3210
|
+
if(options.setHeight) target.style.height = source.offsetHeight + 'px';
|
3211
|
+
},
|
3212
|
+
|
3213
|
+
absolutize: function(element) {
|
3214
|
+
element = $(element);
|
3215
|
+
if (element.style.position == 'absolute') return;
|
3216
|
+
Position.prepare();
|
3217
|
+
|
3218
|
+
var offsets = Position.positionedOffset(element);
|
3219
|
+
var top = offsets[1];
|
3220
|
+
var left = offsets[0];
|
3221
|
+
var width = element.clientWidth;
|
3222
|
+
var height = element.clientHeight;
|
3223
|
+
|
3224
|
+
element._originalLeft = left - parseFloat(element.style.left || 0);
|
3225
|
+
element._originalTop = top - parseFloat(element.style.top || 0);
|
3226
|
+
element._originalWidth = element.style.width;
|
3227
|
+
element._originalHeight = element.style.height;
|
3228
|
+
|
3229
|
+
element.style.position = 'absolute';
|
3230
|
+
element.style.top = top + 'px';
|
3231
|
+
element.style.left = left + 'px';
|
3232
|
+
element.style.width = width + 'px';
|
3233
|
+
element.style.height = height + 'px';
|
3234
|
+
},
|
3235
|
+
|
3236
|
+
relativize: function(element) {
|
3237
|
+
element = $(element);
|
3238
|
+
if (element.style.position == 'relative') return;
|
3239
|
+
Position.prepare();
|
3240
|
+
|
3241
|
+
element.style.position = 'relative';
|
3242
|
+
var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
|
3243
|
+
var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
|
3244
|
+
|
3245
|
+
element.style.top = top + 'px';
|
3246
|
+
element.style.left = left + 'px';
|
3247
|
+
element.style.height = element._originalHeight;
|
3248
|
+
element.style.width = element._originalWidth;
|
3249
|
+
}
|
3250
|
+
}
|
3251
|
+
|
3252
|
+
// Safari returns margins on body which is incorrect if the child is absolutely
|
3253
|
+
// positioned. For performance reasons, redefine Position.cumulativeOffset for
|
3254
|
+
// KHTML/WebKit only.
|
3255
|
+
if (Prototype.Browser.WebKit) {
|
3256
|
+
Position.cumulativeOffset = function(element) {
|
3257
|
+
var valueT = 0, valueL = 0;
|
3258
|
+
do {
|
3259
|
+
valueT += element.offsetTop || 0;
|
3260
|
+
valueL += element.offsetLeft || 0;
|
3261
|
+
if (element.offsetParent == document.body)
|
3262
|
+
if (Element.getStyle(element, 'position') == 'absolute') break;
|
3263
|
+
|
3264
|
+
element = element.offsetParent;
|
3265
|
+
} while (element);
|
3266
|
+
|
3267
|
+
return [valueL, valueT];
|
3268
|
+
}
|
3269
|
+
}
|
3270
|
+
|
3271
|
+
Element.addMethods();
|