json_pure 1.0.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/CHANGES +25 -0
- data/GPL +340 -0
- data/README +77 -0
- data/Rakefile +250 -0
- data/TODO +1 -0
- data/VERSION +1 -0
- data/benchmarks/benchmark.txt +133 -0
- data/benchmarks/benchmark_generator.rb +44 -0
- data/benchmarks/benchmark_parser.rb +22 -0
- data/benchmarks/benchmark_rails.rb +26 -0
- data/bin/edit_json.rb +11 -0
- data/data/example.json +1 -0
- data/data/index.html +37 -0
- data/data/prototype.js +2515 -0
- data/ext/json/ext/generator/Makefile +149 -0
- data/ext/json/ext/generator/extconf.rb +9 -0
- data/ext/json/ext/generator/generator.c +729 -0
- data/ext/json/ext/generator/unicode.c +184 -0
- data/ext/json/ext/generator/unicode.h +40 -0
- data/ext/json/ext/parser/Makefile +149 -0
- data/ext/json/ext/parser/extconf.rb +9 -0
- data/ext/json/ext/parser/parser.c +1551 -0
- data/ext/json/ext/parser/parser.rl +515 -0
- data/ext/json/ext/parser/unicode.c +156 -0
- data/ext/json/ext/parser/unicode.h +44 -0
- data/install.rb +26 -0
- data/lib/json.rb +205 -0
- data/lib/json/Array.xpm +21 -0
- data/lib/json/FalseClass.xpm +21 -0
- data/lib/json/Hash.xpm +21 -0
- data/lib/json/Key.xpm +73 -0
- data/lib/json/NilClass.xpm +21 -0
- data/lib/json/Numeric.xpm +28 -0
- data/lib/json/String.xpm +96 -0
- data/lib/json/TrueClass.xpm +21 -0
- data/lib/json/common.rb +184 -0
- data/lib/json/editor.rb +1207 -0
- data/lib/json/ext.rb +13 -0
- data/lib/json/json.xpm +1499 -0
- data/lib/json/pure.rb +75 -0
- data/lib/json/pure/generator.rb +321 -0
- data/lib/json/pure/parser.rb +210 -0
- data/lib/json/version.rb +8 -0
- data/tests/fixtures/fail1.json +1 -0
- data/tests/fixtures/fail10.json +1 -0
- data/tests/fixtures/fail11.json +1 -0
- data/tests/fixtures/fail12.json +1 -0
- data/tests/fixtures/fail13.json +1 -0
- data/tests/fixtures/fail14.json +1 -0
- data/tests/fixtures/fail15.json +1 -0
- data/tests/fixtures/fail16.json +1 -0
- data/tests/fixtures/fail17.json +1 -0
- data/tests/fixtures/fail19.json +1 -0
- data/tests/fixtures/fail2.json +1 -0
- data/tests/fixtures/fail20.json +1 -0
- data/tests/fixtures/fail21.json +1 -0
- data/tests/fixtures/fail22.json +1 -0
- data/tests/fixtures/fail23.json +1 -0
- data/tests/fixtures/fail24.json +1 -0
- data/tests/fixtures/fail25.json +1 -0
- data/tests/fixtures/fail26.json +1 -0
- data/tests/fixtures/fail27.json +2 -0
- data/tests/fixtures/fail28.json +2 -0
- data/tests/fixtures/fail3.json +1 -0
- data/tests/fixtures/fail4.json +1 -0
- data/tests/fixtures/fail5.json +1 -0
- data/tests/fixtures/fail6.json +1 -0
- data/tests/fixtures/fail7.json +1 -0
- data/tests/fixtures/fail8.json +1 -0
- data/tests/fixtures/fail9.json +1 -0
- data/tests/fixtures/pass1.json +56 -0
- data/tests/fixtures/pass18.json +1 -0
- data/tests/fixtures/pass2.json +1 -0
- data/tests/fixtures/pass3.json +6 -0
- data/tests/runner.rb +24 -0
- data/tests/test_json.rb +235 -0
- data/tests/test_json_addition.rb +94 -0
- data/tests/test_json_fixtures.rb +30 -0
- data/tests/test_json_generate.rb +81 -0
- data/tests/test_json_unicode.rb +55 -0
- data/tools/fuzz.rb +133 -0
- data/tools/server.rb +62 -0
- metadata +146 -0
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
@@ -0,0 +1,133 @@
|
|
1
|
+
(in /home/flori/json)
|
2
|
+
Ragel Code Generator version 5.17 January 2007
|
3
|
+
Copyright (c) 2001-2006 by Adrian Thurston
|
4
|
+
Benchmarking extension variant
|
5
|
+
First run for warmup.
|
6
|
+
Running 'BC_Parser' for a duration of 10 secs per method:
|
7
|
+
real total utime stime cutime cstime
|
8
|
+
parser: 10.005944 10.010000 9.970000 0.040000 0.000000 0.000000
|
9
|
+
5091 508.591409 0.001966
|
10
|
+
calls calls/sec secs/call
|
11
|
+
--------------------------------------------------------------------------------
|
12
|
+
Running 'BC_Parser' for a duration of 10 secs per method:
|
13
|
+
real total utime stime cutime cstime
|
14
|
+
parser: 10.006881 10.000000 9.950000 0.050000 0.000000 0.000000
|
15
|
+
5055 505.500000 0.001978
|
16
|
+
calls calls/sec secs/call
|
17
|
+
--------------------------------------------------------------------------------
|
18
|
+
================================================================================
|
19
|
+
|
20
|
+
|
21
|
+
[null,false,true,"f\u00d6\u00df\u00c4r",["n\u20acst\u20acd",true],{"quux":true,"foo\u00df":"b\u00e4r"}]
|
22
|
+
First run for warmup.
|
23
|
+
Running 'BC_Generator' for a duration of 10 secs per method:
|
24
|
+
real total utime stime cutime cstime
|
25
|
+
generator_pretty: 10.001066 10.010000 9.990000 0.020000 0.000000 0.000000
|
26
|
+
3492 348.851149 0.002867
|
27
|
+
generator_fast : 10.002910 10.000000 9.980000 0.020000 0.000000 0.000000
|
28
|
+
5416 541.600000 0.001846
|
29
|
+
generator_safe : 10.003107 10.010000 10.000000 0.010000 0.000000 0.000000
|
30
|
+
4926 492.107892 0.002032
|
31
|
+
calls calls/sec secs/call
|
32
|
+
--------------------------------------------------------------------------------
|
33
|
+
Running 'BC_Generator' for a duration of 10 secs per method:
|
34
|
+
real total utime stime cutime cstime
|
35
|
+
generator_pretty: 10.009150 10.010000 10.010000 0.000000 0.000000 0.000000
|
36
|
+
3511 350.749251 0.002851
|
37
|
+
generator_fast : 10.014407 10.020000 10.020000 0.000000 0.000000 0.000000
|
38
|
+
5411 540.019960 0.001852
|
39
|
+
generator_safe : 10.010055 10.000000 10.000000 0.000000 0.000000 0.000000
|
40
|
+
4933 493.300000 0.002027
|
41
|
+
calls calls/sec secs/call
|
42
|
+
--------------------------------------------------------------------------------
|
43
|
+
================================================================================
|
44
|
+
|
45
|
+
Comparison in BC_Generator:
|
46
|
+
secs/call speed
|
47
|
+
generator_fast : 0.002 -> 1.540x
|
48
|
+
generator_safe : 0.002 -> 1.406x
|
49
|
+
generator_pretty: 0.003 -> 1.000x
|
50
|
+
--------------------------------------------------------------------------------
|
51
|
+
|
52
|
+
[null, false, true, "f\u00d6\u00df\u00c4r", ["n\u20acst\u20acd", true], {quux: true, "foo\u00df": "b\u00e4r"}]
|
53
|
+
First run for warmup.
|
54
|
+
Running 'BC_Rails' for a duration of 10 secs per method:
|
55
|
+
real total utime stime cutime cstime
|
56
|
+
generator: 10.026043 10.020000 10.020000 0.000000 0.000000 0.000000
|
57
|
+
239 23.852295 0.041925
|
58
|
+
calls calls/sec secs/call
|
59
|
+
--------------------------------------------------------------------------------
|
60
|
+
Running 'BC_Rails' for a duration of 10 secs per method:
|
61
|
+
real total utime stime cutime cstime
|
62
|
+
generator: 10.010931 10.020000 10.010000 0.010000 0.000000 0.000000
|
63
|
+
238 23.752495 0.042101
|
64
|
+
calls calls/sec secs/call
|
65
|
+
--------------------------------------------------------------------------------
|
66
|
+
================================================================================
|
67
|
+
|
68
|
+
|
69
|
+
Benchmarking pure variant
|
70
|
+
First run for warmup.
|
71
|
+
Running 'BC_Parser' for a duration of 10 secs per method:
|
72
|
+
real total utime stime cutime cstime
|
73
|
+
parser: 10.022352 10.030000 10.020000 0.010000 0.000000 0.000000
|
74
|
+
288 28.713858 0.034826
|
75
|
+
calls calls/sec secs/call
|
76
|
+
--------------------------------------------------------------------------------
|
77
|
+
Running 'BC_Parser' for a duration of 10 secs per method:
|
78
|
+
real total utime stime cutime cstime
|
79
|
+
parser: 10.006552 10.000000 10.000000 0.000000 0.000000 0.000000
|
80
|
+
289 28.900000 0.034602
|
81
|
+
calls calls/sec secs/call
|
82
|
+
--------------------------------------------------------------------------------
|
83
|
+
================================================================================
|
84
|
+
|
85
|
+
|
86
|
+
[null,false,true,"f\u00d6\u00df\u00c4r",["n\u20acst\u20acd",true],{"quux":true,"foo\u00df":"b\u00e4r"}]
|
87
|
+
First run for warmup.
|
88
|
+
Running 'BC_Generator' for a duration of 10 secs per method:
|
89
|
+
real total utime stime cutime cstime
|
90
|
+
generator_fast : 10.011644 10.010000 10.010000 0.000000 0.000000 0.000000
|
91
|
+
411 41.058941 0.024355
|
92
|
+
generator_safe : 10.007100 10.010000 10.010000 0.000000 0.000000 0.000000
|
93
|
+
352 35.164835 0.028438
|
94
|
+
generator_pretty: 10.008156 10.010000 10.010000 0.000000 0.000000 0.000000
|
95
|
+
341 34.065934 0.029355
|
96
|
+
calls calls/sec secs/call
|
97
|
+
--------------------------------------------------------------------------------
|
98
|
+
Running 'BC_Generator' for a duration of 10 secs per method:
|
99
|
+
real total utime stime cutime cstime
|
100
|
+
generator_fast : 10.005185 10.010000 10.010000 0.000000 0.000000 0.000000
|
101
|
+
411 41.058941 0.024355
|
102
|
+
generator_safe : 10.006932 10.010000 10.010000 0.000000 0.000000 0.000000
|
103
|
+
351 35.064935 0.028519
|
104
|
+
generator_pretty: 10.007414 10.000000 10.000000 0.000000 0.000000 0.000000
|
105
|
+
340 34.000000 0.029412
|
106
|
+
calls calls/sec secs/call
|
107
|
+
--------------------------------------------------------------------------------
|
108
|
+
================================================================================
|
109
|
+
|
110
|
+
Comparison in BC_Generator:
|
111
|
+
secs/call speed
|
112
|
+
generator_fast : 0.024 -> 1.208x
|
113
|
+
generator_safe : 0.029 -> 1.031x
|
114
|
+
generator_pretty: 0.029 -> 1.000x
|
115
|
+
--------------------------------------------------------------------------------
|
116
|
+
|
117
|
+
[null, false, true, "f\u00d6\u00df\u00c4r", ["n\u20acst\u20acd", true], {quux: true, "foo\u00df": "b\u00e4r"}]
|
118
|
+
First run for warmup.
|
119
|
+
Running 'BC_Rails' for a duration of 10 secs per method:
|
120
|
+
real total utime stime cutime cstime
|
121
|
+
generator: 10.005748 10.000000 10.000000 0.000000 0.000000 0.000000
|
122
|
+
240 24.000000 0.041667
|
123
|
+
calls calls/sec secs/call
|
124
|
+
--------------------------------------------------------------------------------
|
125
|
+
Running 'BC_Rails' for a duration of 10 secs per method:
|
126
|
+
real total utime stime cutime cstime
|
127
|
+
generator: 10.006764 10.010000 10.010000 0.000000 0.000000 0.000000
|
128
|
+
239 23.876124 0.041883
|
129
|
+
calls calls/sec secs/call
|
130
|
+
--------------------------------------------------------------------------------
|
131
|
+
================================================================================
|
132
|
+
|
133
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bullshit'
|
4
|
+
$KCODE='utf8'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
class BC_Generator < Bullshit::TimeCase
|
8
|
+
include JSON
|
9
|
+
|
10
|
+
warmup true
|
11
|
+
duration 10
|
12
|
+
|
13
|
+
def setup
|
14
|
+
a = [ nil, false, true, "fÖßÄr", [ "n€st€d", true ], { "fooß" => "bär", "quux" => true } ]
|
15
|
+
puts JSON[a]
|
16
|
+
@big = a * 100
|
17
|
+
end
|
18
|
+
|
19
|
+
def benchmark_generator_fast
|
20
|
+
@result = JSON.fast_generate(@big)
|
21
|
+
end
|
22
|
+
|
23
|
+
def reset_benchmark_generator_fast
|
24
|
+
@result and @result.size > 2 + 6 * @big.size or raise @result.to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
def benchmark_generator_safe
|
28
|
+
@result = JSON.generate(@big)
|
29
|
+
end
|
30
|
+
|
31
|
+
def reset_benchmark_generator_safe
|
32
|
+
@result and @result.size > 2 + 6 * @big.size or raise @result.to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
def benchmark_generator_pretty
|
36
|
+
@result = JSON.pretty_generate(@big)
|
37
|
+
end
|
38
|
+
|
39
|
+
def reset_benchmark_generator_pretty
|
40
|
+
@result and @result.size > 2 + 6 * @big.size or raise @result.to_s
|
41
|
+
end
|
42
|
+
|
43
|
+
compare :generator_fast, :generator_safe, :generator_pretty
|
44
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bullshit'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
class BC_Parser < Bullshit::TimeCase
|
7
|
+
include JSON
|
8
|
+
|
9
|
+
warmup true
|
10
|
+
duration 10
|
11
|
+
|
12
|
+
def setup
|
13
|
+
a = [ nil, false, true, "fÖßÄr", [ "n€st€d", true ], { "fooß" => "bär", "quux" => true } ]
|
14
|
+
@big = a * 100
|
15
|
+
@json = JSON.generate(@big)
|
16
|
+
end
|
17
|
+
|
18
|
+
def benchmark_parser
|
19
|
+
a = JSON.parse(@json)
|
20
|
+
a == @big or raise "not equal"
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bullshit'
|
4
|
+
require 'active_support'
|
5
|
+
|
6
|
+
class BC_Rails < Bullshit::TimeCase
|
7
|
+
warmup true
|
8
|
+
duration 10
|
9
|
+
|
10
|
+
def setup
|
11
|
+
a = [ nil, false, true, "fÖßÄr", [ "n€st€d", true ], { "fooß" => "bär", "quux" => true } ]
|
12
|
+
puts a.to_json
|
13
|
+
@big = a * 100
|
14
|
+
end
|
15
|
+
|
16
|
+
def benchmark_generator
|
17
|
+
@result = @big.to_json
|
18
|
+
end
|
19
|
+
|
20
|
+
def reset_benchmark_generator
|
21
|
+
@result and @result.size > 2 + 6 * @big.size or raise @result.to_s
|
22
|
+
if stack = Thread.current[:json_reference_stack]
|
23
|
+
stack.clear
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/bin/edit_json.rb
ADDED
data/data/example.json
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{"a":2,"b":3.141,"TIME":"2007-03-14T11:52:40","c":"c","d":[1,"b",3.14],"COUNT":666,"e":{"foo":"bar"},"foo":"B\u00e4r","g":"\u677e\u672c\u884c\u5f18","h":1000.0,"bar":"\u00a9 \u2260 \u20ac!","i":0.001,"j":"\ud840\udc01"}
|
data/data/index.html
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
3
|
+
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
|
4
|
+
<head>
|
5
|
+
<title>Javascript Example</title>
|
6
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
7
|
+
<script src="prototype.js" type="text/javascript"></script>
|
8
|
+
</head>
|
9
|
+
|
10
|
+
<body>
|
11
|
+
<h1>Fetching object from server</h1>
|
12
|
+
<div id="list">
|
13
|
+
Switch on Javascript!
|
14
|
+
</div>
|
15
|
+
<script type="text/javascript">
|
16
|
+
<!--
|
17
|
+
function pollJSON() {
|
18
|
+
new Ajax.Request('/json',
|
19
|
+
{
|
20
|
+
method:'get',
|
21
|
+
onSuccess: function(transport){
|
22
|
+
var response = transport.responseText || "no response text";
|
23
|
+
response = eval("(" + response + ")");
|
24
|
+
var text = "";
|
25
|
+
for (var k in response) {
|
26
|
+
text = text + "<b>" + k + "</b>: " + response[k] + "<br/>"
|
27
|
+
}
|
28
|
+
$("list").update(text);
|
29
|
+
},
|
30
|
+
onFailure: function(){ alert('Something went wrong...') }
|
31
|
+
});
|
32
|
+
}
|
33
|
+
new PeriodicalExecuter(pollJSON, 1);
|
34
|
+
-->
|
35
|
+
</script>
|
36
|
+
</body>
|
37
|
+
</html>
|
data/data/prototype.js
ADDED
@@ -0,0 +1,2515 @@
|
|
1
|
+
/* Prototype JavaScript framework, version 1.5.0
|
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://prototype.conio.net/
|
6
|
+
*
|
7
|
+
/*--------------------------------------------------------------------------*/
|
8
|
+
|
9
|
+
var Prototype = {
|
10
|
+
Version: '1.5.0',
|
11
|
+
BrowserFeatures: {
|
12
|
+
XPath: !!document.evaluate
|
13
|
+
},
|
14
|
+
|
15
|
+
ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
|
16
|
+
emptyFunction: function() {},
|
17
|
+
K: function(x) { return x }
|
18
|
+
}
|
19
|
+
|
20
|
+
var Class = {
|
21
|
+
create: function() {
|
22
|
+
return function() {
|
23
|
+
this.initialize.apply(this, arguments);
|
24
|
+
}
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
var Abstract = new Object();
|
29
|
+
|
30
|
+
Object.extend = function(destination, source) {
|
31
|
+
for (var property in source) {
|
32
|
+
destination[property] = source[property];
|
33
|
+
}
|
34
|
+
return destination;
|
35
|
+
}
|
36
|
+
|
37
|
+
Object.extend(Object, {
|
38
|
+
inspect: function(object) {
|
39
|
+
try {
|
40
|
+
if (object === undefined) return 'undefined';
|
41
|
+
if (object === null) return 'null';
|
42
|
+
return object.inspect ? object.inspect() : object.toString();
|
43
|
+
} catch (e) {
|
44
|
+
if (e instanceof RangeError) return '...';
|
45
|
+
throw e;
|
46
|
+
}
|
47
|
+
},
|
48
|
+
|
49
|
+
keys: function(object) {
|
50
|
+
var keys = [];
|
51
|
+
for (var property in object)
|
52
|
+
keys.push(property);
|
53
|
+
return keys;
|
54
|
+
},
|
55
|
+
|
56
|
+
values: function(object) {
|
57
|
+
var values = [];
|
58
|
+
for (var property in object)
|
59
|
+
values.push(object[property]);
|
60
|
+
return values;
|
61
|
+
},
|
62
|
+
|
63
|
+
clone: function(object) {
|
64
|
+
return Object.extend({}, object);
|
65
|
+
}
|
66
|
+
});
|
67
|
+
|
68
|
+
Function.prototype.bind = function() {
|
69
|
+
var __method = this, args = $A(arguments), object = args.shift();
|
70
|
+
return function() {
|
71
|
+
return __method.apply(object, args.concat($A(arguments)));
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
Function.prototype.bindAsEventListener = function(object) {
|
76
|
+
var __method = this, args = $A(arguments), object = args.shift();
|
77
|
+
return function(event) {
|
78
|
+
return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));
|
79
|
+
}
|
80
|
+
}
|
81
|
+
|
82
|
+
Object.extend(Number.prototype, {
|
83
|
+
toColorPart: function() {
|
84
|
+
var digits = this.toString(16);
|
85
|
+
if (this < 16) return '0' + digits;
|
86
|
+
return digits;
|
87
|
+
},
|
88
|
+
|
89
|
+
succ: function() {
|
90
|
+
return this + 1;
|
91
|
+
},
|
92
|
+
|
93
|
+
times: function(iterator) {
|
94
|
+
$R(0, this, true).each(iterator);
|
95
|
+
return this;
|
96
|
+
}
|
97
|
+
});
|
98
|
+
|
99
|
+
var Try = {
|
100
|
+
these: function() {
|
101
|
+
var returnValue;
|
102
|
+
|
103
|
+
for (var i = 0, length = arguments.length; i < length; i++) {
|
104
|
+
var lambda = arguments[i];
|
105
|
+
try {
|
106
|
+
returnValue = lambda();
|
107
|
+
break;
|
108
|
+
} catch (e) {}
|
109
|
+
}
|
110
|
+
|
111
|
+
return returnValue;
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
/*--------------------------------------------------------------------------*/
|
116
|
+
|
117
|
+
var PeriodicalExecuter = Class.create();
|
118
|
+
PeriodicalExecuter.prototype = {
|
119
|
+
initialize: function(callback, frequency) {
|
120
|
+
this.callback = callback;
|
121
|
+
this.frequency = frequency;
|
122
|
+
this.currentlyExecuting = false;
|
123
|
+
|
124
|
+
this.registerCallback();
|
125
|
+
},
|
126
|
+
|
127
|
+
registerCallback: function() {
|
128
|
+
this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
|
129
|
+
},
|
130
|
+
|
131
|
+
stop: function() {
|
132
|
+
if (!this.timer) return;
|
133
|
+
clearInterval(this.timer);
|
134
|
+
this.timer = null;
|
135
|
+
},
|
136
|
+
|
137
|
+
onTimerEvent: function() {
|
138
|
+
if (!this.currentlyExecuting) {
|
139
|
+
try {
|
140
|
+
this.currentlyExecuting = true;
|
141
|
+
this.callback(this);
|
142
|
+
} finally {
|
143
|
+
this.currentlyExecuting = false;
|
144
|
+
}
|
145
|
+
}
|
146
|
+
}
|
147
|
+
}
|
148
|
+
String.interpret = function(value){
|
149
|
+
return value == null ? '' : String(value);
|
150
|
+
}
|
151
|
+
|
152
|
+
Object.extend(String.prototype, {
|
153
|
+
gsub: function(pattern, replacement) {
|
154
|
+
var result = '', source = this, match;
|
155
|
+
replacement = arguments.callee.prepareReplacement(replacement);
|
156
|
+
|
157
|
+
while (source.length > 0) {
|
158
|
+
if (match = source.match(pattern)) {
|
159
|
+
result += source.slice(0, match.index);
|
160
|
+
result += String.interpret(replacement(match));
|
161
|
+
source = source.slice(match.index + match[0].length);
|
162
|
+
} else {
|
163
|
+
result += source, source = '';
|
164
|
+
}
|
165
|
+
}
|
166
|
+
return result;
|
167
|
+
},
|
168
|
+
|
169
|
+
sub: function(pattern, replacement, count) {
|
170
|
+
replacement = this.gsub.prepareReplacement(replacement);
|
171
|
+
count = count === undefined ? 1 : count;
|
172
|
+
|
173
|
+
return this.gsub(pattern, function(match) {
|
174
|
+
if (--count < 0) return match[0];
|
175
|
+
return replacement(match);
|
176
|
+
});
|
177
|
+
},
|
178
|
+
|
179
|
+
scan: function(pattern, iterator) {
|
180
|
+
this.gsub(pattern, iterator);
|
181
|
+
return this;
|
182
|
+
},
|
183
|
+
|
184
|
+
truncate: function(length, truncation) {
|
185
|
+
length = length || 30;
|
186
|
+
truncation = truncation === undefined ? '...' : truncation;
|
187
|
+
return this.length > length ?
|
188
|
+
this.slice(0, length - truncation.length) + truncation : this;
|
189
|
+
},
|
190
|
+
|
191
|
+
strip: function() {
|
192
|
+
return this.replace(/^\s+/, '').replace(/\s+$/, '');
|
193
|
+
},
|
194
|
+
|
195
|
+
stripTags: function() {
|
196
|
+
return this.replace(/<\/?[^>]+>/gi, '');
|
197
|
+
},
|
198
|
+
|
199
|
+
stripScripts: function() {
|
200
|
+
return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
|
201
|
+
},
|
202
|
+
|
203
|
+
extractScripts: function() {
|
204
|
+
var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
|
205
|
+
var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
|
206
|
+
return (this.match(matchAll) || []).map(function(scriptTag) {
|
207
|
+
return (scriptTag.match(matchOne) || ['', ''])[1];
|
208
|
+
});
|
209
|
+
},
|
210
|
+
|
211
|
+
evalScripts: function() {
|
212
|
+
return this.extractScripts().map(function(script) { return eval(script) });
|
213
|
+
},
|
214
|
+
|
215
|
+
escapeHTML: function() {
|
216
|
+
var div = document.createElement('div');
|
217
|
+
var text = document.createTextNode(this);
|
218
|
+
div.appendChild(text);
|
219
|
+
return div.innerHTML;
|
220
|
+
},
|
221
|
+
|
222
|
+
unescapeHTML: function() {
|
223
|
+
var div = document.createElement('div');
|
224
|
+
div.innerHTML = this.stripTags();
|
225
|
+
return div.childNodes[0] ? (div.childNodes.length > 1 ?
|
226
|
+
$A(div.childNodes).inject('',function(memo,node){ return memo+node.nodeValue }) :
|
227
|
+
div.childNodes[0].nodeValue) : '';
|
228
|
+
},
|
229
|
+
|
230
|
+
toQueryParams: function(separator) {
|
231
|
+
var match = this.strip().match(/([^?#]*)(#.*)?$/);
|
232
|
+
if (!match) return {};
|
233
|
+
|
234
|
+
return match[1].split(separator || '&').inject({}, function(hash, pair) {
|
235
|
+
if ((pair = pair.split('='))[0]) {
|
236
|
+
var name = decodeURIComponent(pair[0]);
|
237
|
+
var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
|
238
|
+
|
239
|
+
if (hash[name] !== undefined) {
|
240
|
+
if (hash[name].constructor != Array)
|
241
|
+
hash[name] = [hash[name]];
|
242
|
+
if (value) hash[name].push(value);
|
243
|
+
}
|
244
|
+
else hash[name] = value;
|
245
|
+
}
|
246
|
+
return hash;
|
247
|
+
});
|
248
|
+
},
|
249
|
+
|
250
|
+
toArray: function() {
|
251
|
+
return this.split('');
|
252
|
+
},
|
253
|
+
|
254
|
+
succ: function() {
|
255
|
+
return this.slice(0, this.length - 1) +
|
256
|
+
String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
|
257
|
+
},
|
258
|
+
|
259
|
+
camelize: function() {
|
260
|
+
var parts = this.split('-'), len = parts.length;
|
261
|
+
if (len == 1) return parts[0];
|
262
|
+
|
263
|
+
var camelized = this.charAt(0) == '-'
|
264
|
+
? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
|
265
|
+
: parts[0];
|
266
|
+
|
267
|
+
for (var i = 1; i < len; i++)
|
268
|
+
camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
|
269
|
+
|
270
|
+
return camelized;
|
271
|
+
},
|
272
|
+
|
273
|
+
capitalize: function(){
|
274
|
+
return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
|
275
|
+
},
|
276
|
+
|
277
|
+
underscore: function() {
|
278
|
+
return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
|
279
|
+
},
|
280
|
+
|
281
|
+
dasherize: function() {
|
282
|
+
return this.gsub(/_/,'-');
|
283
|
+
},
|
284
|
+
|
285
|
+
inspect: function(useDoubleQuotes) {
|
286
|
+
var escapedString = this.replace(/\\/g, '\\\\');
|
287
|
+
if (useDoubleQuotes)
|
288
|
+
return '"' + escapedString.replace(/"/g, '\\"') + '"';
|
289
|
+
else
|
290
|
+
return "'" + escapedString.replace(/'/g, '\\\'') + "'";
|
291
|
+
}
|
292
|
+
});
|
293
|
+
|
294
|
+
String.prototype.gsub.prepareReplacement = function(replacement) {
|
295
|
+
if (typeof replacement == 'function') return replacement;
|
296
|
+
var template = new Template(replacement);
|
297
|
+
return function(match) { return template.evaluate(match) };
|
298
|
+
}
|
299
|
+
|
300
|
+
String.prototype.parseQuery = String.prototype.toQueryParams;
|
301
|
+
|
302
|
+
var Template = Class.create();
|
303
|
+
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
|
304
|
+
Template.prototype = {
|
305
|
+
initialize: function(template, pattern) {
|
306
|
+
this.template = template.toString();
|
307
|
+
this.pattern = pattern || Template.Pattern;
|
308
|
+
},
|
309
|
+
|
310
|
+
evaluate: function(object) {
|
311
|
+
return this.template.gsub(this.pattern, function(match) {
|
312
|
+
var before = match[1];
|
313
|
+
if (before == '\\') return match[2];
|
314
|
+
return before + String.interpret(object[match[3]]);
|
315
|
+
});
|
316
|
+
}
|
317
|
+
}
|
318
|
+
|
319
|
+
var $break = new Object();
|
320
|
+
var $continue = new Object();
|
321
|
+
|
322
|
+
var Enumerable = {
|
323
|
+
each: function(iterator) {
|
324
|
+
var index = 0;
|
325
|
+
try {
|
326
|
+
this._each(function(value) {
|
327
|
+
try {
|
328
|
+
iterator(value, index++);
|
329
|
+
} catch (e) {
|
330
|
+
if (e != $continue) throw e;
|
331
|
+
}
|
332
|
+
});
|
333
|
+
} catch (e) {
|
334
|
+
if (e != $break) throw e;
|
335
|
+
}
|
336
|
+
return this;
|
337
|
+
},
|
338
|
+
|
339
|
+
eachSlice: function(number, iterator) {
|
340
|
+
var index = -number, slices = [], array = this.toArray();
|
341
|
+
while ((index += number) < array.length)
|
342
|
+
slices.push(array.slice(index, index+number));
|
343
|
+
return slices.map(iterator);
|
344
|
+
},
|
345
|
+
|
346
|
+
all: function(iterator) {
|
347
|
+
var result = true;
|
348
|
+
this.each(function(value, index) {
|
349
|
+
result = result && !!(iterator || Prototype.K)(value, index);
|
350
|
+
if (!result) throw $break;
|
351
|
+
});
|
352
|
+
return result;
|
353
|
+
},
|
354
|
+
|
355
|
+
any: function(iterator) {
|
356
|
+
var result = false;
|
357
|
+
this.each(function(value, index) {
|
358
|
+
if (result = !!(iterator || Prototype.K)(value, index))
|
359
|
+
throw $break;
|
360
|
+
});
|
361
|
+
return result;
|
362
|
+
},
|
363
|
+
|
364
|
+
collect: function(iterator) {
|
365
|
+
var results = [];
|
366
|
+
this.each(function(value, index) {
|
367
|
+
results.push((iterator || Prototype.K)(value, index));
|
368
|
+
});
|
369
|
+
return results;
|
370
|
+
},
|
371
|
+
|
372
|
+
detect: function(iterator) {
|
373
|
+
var result;
|
374
|
+
this.each(function(value, index) {
|
375
|
+
if (iterator(value, index)) {
|
376
|
+
result = value;
|
377
|
+
throw $break;
|
378
|
+
}
|
379
|
+
});
|
380
|
+
return result;
|
381
|
+
},
|
382
|
+
|
383
|
+
findAll: function(iterator) {
|
384
|
+
var results = [];
|
385
|
+
this.each(function(value, index) {
|
386
|
+
if (iterator(value, index))
|
387
|
+
results.push(value);
|
388
|
+
});
|
389
|
+
return results;
|
390
|
+
},
|
391
|
+
|
392
|
+
grep: function(pattern, iterator) {
|
393
|
+
var results = [];
|
394
|
+
this.each(function(value, index) {
|
395
|
+
var stringValue = value.toString();
|
396
|
+
if (stringValue.match(pattern))
|
397
|
+
results.push((iterator || Prototype.K)(value, index));
|
398
|
+
})
|
399
|
+
return results;
|
400
|
+
},
|
401
|
+
|
402
|
+
include: function(object) {
|
403
|
+
var found = false;
|
404
|
+
this.each(function(value) {
|
405
|
+
if (value == object) {
|
406
|
+
found = true;
|
407
|
+
throw $break;
|
408
|
+
}
|
409
|
+
});
|
410
|
+
return found;
|
411
|
+
},
|
412
|
+
|
413
|
+
inGroupsOf: function(number, fillWith) {
|
414
|
+
fillWith = fillWith === undefined ? null : fillWith;
|
415
|
+
return this.eachSlice(number, function(slice) {
|
416
|
+
while(slice.length < number) slice.push(fillWith);
|
417
|
+
return slice;
|
418
|
+
});
|
419
|
+
},
|
420
|
+
|
421
|
+
inject: function(memo, iterator) {
|
422
|
+
this.each(function(value, index) {
|
423
|
+
memo = iterator(memo, value, index);
|
424
|
+
});
|
425
|
+
return memo;
|
426
|
+
},
|
427
|
+
|
428
|
+
invoke: function(method) {
|
429
|
+
var args = $A(arguments).slice(1);
|
430
|
+
return this.map(function(value) {
|
431
|
+
return value[method].apply(value, args);
|
432
|
+
});
|
433
|
+
},
|
434
|
+
|
435
|
+
max: function(iterator) {
|
436
|
+
var result;
|
437
|
+
this.each(function(value, index) {
|
438
|
+
value = (iterator || Prototype.K)(value, index);
|
439
|
+
if (result == undefined || value >= result)
|
440
|
+
result = value;
|
441
|
+
});
|
442
|
+
return result;
|
443
|
+
},
|
444
|
+
|
445
|
+
min: function(iterator) {
|
446
|
+
var result;
|
447
|
+
this.each(function(value, index) {
|
448
|
+
value = (iterator || Prototype.K)(value, index);
|
449
|
+
if (result == undefined || value < result)
|
450
|
+
result = value;
|
451
|
+
});
|
452
|
+
return result;
|
453
|
+
},
|
454
|
+
|
455
|
+
partition: function(iterator) {
|
456
|
+
var trues = [], falses = [];
|
457
|
+
this.each(function(value, index) {
|
458
|
+
((iterator || Prototype.K)(value, index) ?
|
459
|
+
trues : falses).push(value);
|
460
|
+
});
|
461
|
+
return [trues, falses];
|
462
|
+
},
|
463
|
+
|
464
|
+
pluck: function(property) {
|
465
|
+
var results = [];
|
466
|
+
this.each(function(value, index) {
|
467
|
+
results.push(value[property]);
|
468
|
+
});
|
469
|
+
return results;
|
470
|
+
},
|
471
|
+
|
472
|
+
reject: function(iterator) {
|
473
|
+
var results = [];
|
474
|
+
this.each(function(value, index) {
|
475
|
+
if (!iterator(value, index))
|
476
|
+
results.push(value);
|
477
|
+
});
|
478
|
+
return results;
|
479
|
+
},
|
480
|
+
|
481
|
+
sortBy: function(iterator) {
|
482
|
+
return this.map(function(value, index) {
|
483
|
+
return {value: value, criteria: iterator(value, index)};
|
484
|
+
}).sort(function(left, right) {
|
485
|
+
var a = left.criteria, b = right.criteria;
|
486
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
487
|
+
}).pluck('value');
|
488
|
+
},
|
489
|
+
|
490
|
+
toArray: function() {
|
491
|
+
return this.map();
|
492
|
+
},
|
493
|
+
|
494
|
+
zip: function() {
|
495
|
+
var iterator = Prototype.K, args = $A(arguments);
|
496
|
+
if (typeof args.last() == 'function')
|
497
|
+
iterator = args.pop();
|
498
|
+
|
499
|
+
var collections = [this].concat(args).map($A);
|
500
|
+
return this.map(function(value, index) {
|
501
|
+
return iterator(collections.pluck(index));
|
502
|
+
});
|
503
|
+
},
|
504
|
+
|
505
|
+
size: function() {
|
506
|
+
return this.toArray().length;
|
507
|
+
},
|
508
|
+
|
509
|
+
inspect: function() {
|
510
|
+
return '#<Enumerable:' + this.toArray().inspect() + '>';
|
511
|
+
}
|
512
|
+
}
|
513
|
+
|
514
|
+
Object.extend(Enumerable, {
|
515
|
+
map: Enumerable.collect,
|
516
|
+
find: Enumerable.detect,
|
517
|
+
select: Enumerable.findAll,
|
518
|
+
member: Enumerable.include,
|
519
|
+
entries: Enumerable.toArray
|
520
|
+
});
|
521
|
+
var $A = Array.from = function(iterable) {
|
522
|
+
if (!iterable) return [];
|
523
|
+
if (iterable.toArray) {
|
524
|
+
return iterable.toArray();
|
525
|
+
} else {
|
526
|
+
var results = [];
|
527
|
+
for (var i = 0, length = iterable.length; i < length; i++)
|
528
|
+
results.push(iterable[i]);
|
529
|
+
return results;
|
530
|
+
}
|
531
|
+
}
|
532
|
+
|
533
|
+
Object.extend(Array.prototype, Enumerable);
|
534
|
+
|
535
|
+
if (!Array.prototype._reverse)
|
536
|
+
Array.prototype._reverse = Array.prototype.reverse;
|
537
|
+
|
538
|
+
Object.extend(Array.prototype, {
|
539
|
+
_each: function(iterator) {
|
540
|
+
for (var i = 0, length = this.length; i < length; i++)
|
541
|
+
iterator(this[i]);
|
542
|
+
},
|
543
|
+
|
544
|
+
clear: function() {
|
545
|
+
this.length = 0;
|
546
|
+
return this;
|
547
|
+
},
|
548
|
+
|
549
|
+
first: function() {
|
550
|
+
return this[0];
|
551
|
+
},
|
552
|
+
|
553
|
+
last: function() {
|
554
|
+
return this[this.length - 1];
|
555
|
+
},
|
556
|
+
|
557
|
+
compact: function() {
|
558
|
+
return this.select(function(value) {
|
559
|
+
return value != null;
|
560
|
+
});
|
561
|
+
},
|
562
|
+
|
563
|
+
flatten: function() {
|
564
|
+
return this.inject([], function(array, value) {
|
565
|
+
return array.concat(value && value.constructor == Array ?
|
566
|
+
value.flatten() : [value]);
|
567
|
+
});
|
568
|
+
},
|
569
|
+
|
570
|
+
without: function() {
|
571
|
+
var values = $A(arguments);
|
572
|
+
return this.select(function(value) {
|
573
|
+
return !values.include(value);
|
574
|
+
});
|
575
|
+
},
|
576
|
+
|
577
|
+
indexOf: function(object) {
|
578
|
+
for (var i = 0, length = this.length; i < length; i++)
|
579
|
+
if (this[i] == object) return i;
|
580
|
+
return -1;
|
581
|
+
},
|
582
|
+
|
583
|
+
reverse: function(inline) {
|
584
|
+
return (inline !== false ? this : this.toArray())._reverse();
|
585
|
+
},
|
586
|
+
|
587
|
+
reduce: function() {
|
588
|
+
return this.length > 1 ? this : this[0];
|
589
|
+
},
|
590
|
+
|
591
|
+
uniq: function() {
|
592
|
+
return this.inject([], function(array, value) {
|
593
|
+
return array.include(value) ? array : array.concat([value]);
|
594
|
+
});
|
595
|
+
},
|
596
|
+
|
597
|
+
clone: function() {
|
598
|
+
return [].concat(this);
|
599
|
+
},
|
600
|
+
|
601
|
+
size: function() {
|
602
|
+
return this.length;
|
603
|
+
},
|
604
|
+
|
605
|
+
inspect: function() {
|
606
|
+
return '[' + this.map(Object.inspect).join(', ') + ']';
|
607
|
+
}
|
608
|
+
});
|
609
|
+
|
610
|
+
Array.prototype.toArray = Array.prototype.clone;
|
611
|
+
|
612
|
+
function $w(string){
|
613
|
+
string = string.strip();
|
614
|
+
return string ? string.split(/\s+/) : [];
|
615
|
+
}
|
616
|
+
|
617
|
+
if(window.opera){
|
618
|
+
Array.prototype.concat = function(){
|
619
|
+
var array = [];
|
620
|
+
for(var i = 0, length = this.length; i < length; i++) array.push(this[i]);
|
621
|
+
for(var i = 0, length = arguments.length; i < length; i++) {
|
622
|
+
if(arguments[i].constructor == Array) {
|
623
|
+
for(var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
|
624
|
+
array.push(arguments[i][j]);
|
625
|
+
} else {
|
626
|
+
array.push(arguments[i]);
|
627
|
+
}
|
628
|
+
}
|
629
|
+
return array;
|
630
|
+
}
|
631
|
+
}
|
632
|
+
var Hash = function(obj) {
|
633
|
+
Object.extend(this, obj || {});
|
634
|
+
};
|
635
|
+
|
636
|
+
Object.extend(Hash, {
|
637
|
+
toQueryString: function(obj) {
|
638
|
+
var parts = [];
|
639
|
+
|
640
|
+
this.prototype._each.call(obj, function(pair) {
|
641
|
+
if (!pair.key) return;
|
642
|
+
|
643
|
+
if (pair.value && pair.value.constructor == Array) {
|
644
|
+
var values = pair.value.compact();
|
645
|
+
if (values.length < 2) pair.value = values.reduce();
|
646
|
+
else {
|
647
|
+
key = encodeURIComponent(pair.key);
|
648
|
+
values.each(function(value) {
|
649
|
+
value = value != undefined ? encodeURIComponent(value) : '';
|
650
|
+
parts.push(key + '=' + encodeURIComponent(value));
|
651
|
+
});
|
652
|
+
return;
|
653
|
+
}
|
654
|
+
}
|
655
|
+
if (pair.value == undefined) pair[1] = '';
|
656
|
+
parts.push(pair.map(encodeURIComponent).join('='));
|
657
|
+
});
|
658
|
+
|
659
|
+
return parts.join('&');
|
660
|
+
}
|
661
|
+
});
|
662
|
+
|
663
|
+
Object.extend(Hash.prototype, Enumerable);
|
664
|
+
Object.extend(Hash.prototype, {
|
665
|
+
_each: function(iterator) {
|
666
|
+
for (var key in this) {
|
667
|
+
var value = this[key];
|
668
|
+
if (value && value == Hash.prototype[key]) continue;
|
669
|
+
|
670
|
+
var pair = [key, value];
|
671
|
+
pair.key = key;
|
672
|
+
pair.value = value;
|
673
|
+
iterator(pair);
|
674
|
+
}
|
675
|
+
},
|
676
|
+
|
677
|
+
keys: function() {
|
678
|
+
return this.pluck('key');
|
679
|
+
},
|
680
|
+
|
681
|
+
values: function() {
|
682
|
+
return this.pluck('value');
|
683
|
+
},
|
684
|
+
|
685
|
+
merge: function(hash) {
|
686
|
+
return $H(hash).inject(this, function(mergedHash, pair) {
|
687
|
+
mergedHash[pair.key] = pair.value;
|
688
|
+
return mergedHash;
|
689
|
+
});
|
690
|
+
},
|
691
|
+
|
692
|
+
remove: function() {
|
693
|
+
var result;
|
694
|
+
for(var i = 0, length = arguments.length; i < length; i++) {
|
695
|
+
var value = this[arguments[i]];
|
696
|
+
if (value !== undefined){
|
697
|
+
if (result === undefined) result = value;
|
698
|
+
else {
|
699
|
+
if (result.constructor != Array) result = [result];
|
700
|
+
result.push(value)
|
701
|
+
}
|
702
|
+
}
|
703
|
+
delete this[arguments[i]];
|
704
|
+
}
|
705
|
+
return result;
|
706
|
+
},
|
707
|
+
|
708
|
+
toQueryString: function() {
|
709
|
+
return Hash.toQueryString(this);
|
710
|
+
},
|
711
|
+
|
712
|
+
inspect: function() {
|
713
|
+
return '#<Hash:{' + this.map(function(pair) {
|
714
|
+
return pair.map(Object.inspect).join(': ');
|
715
|
+
}).join(', ') + '}>';
|
716
|
+
}
|
717
|
+
});
|
718
|
+
|
719
|
+
function $H(object) {
|
720
|
+
if (object && object.constructor == Hash) return object;
|
721
|
+
return new Hash(object);
|
722
|
+
};
|
723
|
+
ObjectRange = Class.create();
|
724
|
+
Object.extend(ObjectRange.prototype, Enumerable);
|
725
|
+
Object.extend(ObjectRange.prototype, {
|
726
|
+
initialize: function(start, end, exclusive) {
|
727
|
+
this.start = start;
|
728
|
+
this.end = end;
|
729
|
+
this.exclusive = exclusive;
|
730
|
+
},
|
731
|
+
|
732
|
+
_each: function(iterator) {
|
733
|
+
var value = this.start;
|
734
|
+
while (this.include(value)) {
|
735
|
+
iterator(value);
|
736
|
+
value = value.succ();
|
737
|
+
}
|
738
|
+
},
|
739
|
+
|
740
|
+
include: function(value) {
|
741
|
+
if (value < this.start)
|
742
|
+
return false;
|
743
|
+
if (this.exclusive)
|
744
|
+
return value < this.end;
|
745
|
+
return value <= this.end;
|
746
|
+
}
|
747
|
+
});
|
748
|
+
|
749
|
+
var $R = function(start, end, exclusive) {
|
750
|
+
return new ObjectRange(start, end, exclusive);
|
751
|
+
}
|
752
|
+
|
753
|
+
var Ajax = {
|
754
|
+
getTransport: function() {
|
755
|
+
return Try.these(
|
756
|
+
function() {return new XMLHttpRequest()},
|
757
|
+
function() {return new ActiveXObject('Msxml2.XMLHTTP')},
|
758
|
+
function() {return new ActiveXObject('Microsoft.XMLHTTP')}
|
759
|
+
) || false;
|
760
|
+
},
|
761
|
+
|
762
|
+
activeRequestCount: 0
|
763
|
+
}
|
764
|
+
|
765
|
+
Ajax.Responders = {
|
766
|
+
responders: [],
|
767
|
+
|
768
|
+
_each: function(iterator) {
|
769
|
+
this.responders._each(iterator);
|
770
|
+
},
|
771
|
+
|
772
|
+
register: function(responder) {
|
773
|
+
if (!this.include(responder))
|
774
|
+
this.responders.push(responder);
|
775
|
+
},
|
776
|
+
|
777
|
+
unregister: function(responder) {
|
778
|
+
this.responders = this.responders.without(responder);
|
779
|
+
},
|
780
|
+
|
781
|
+
dispatch: function(callback, request, transport, json) {
|
782
|
+
this.each(function(responder) {
|
783
|
+
if (typeof responder[callback] == 'function') {
|
784
|
+
try {
|
785
|
+
responder[callback].apply(responder, [request, transport, json]);
|
786
|
+
} catch (e) {}
|
787
|
+
}
|
788
|
+
});
|
789
|
+
}
|
790
|
+
};
|
791
|
+
|
792
|
+
Object.extend(Ajax.Responders, Enumerable);
|
793
|
+
|
794
|
+
Ajax.Responders.register({
|
795
|
+
onCreate: function() {
|
796
|
+
Ajax.activeRequestCount++;
|
797
|
+
},
|
798
|
+
onComplete: function() {
|
799
|
+
Ajax.activeRequestCount--;
|
800
|
+
}
|
801
|
+
});
|
802
|
+
|
803
|
+
Ajax.Base = function() {};
|
804
|
+
Ajax.Base.prototype = {
|
805
|
+
setOptions: function(options) {
|
806
|
+
this.options = {
|
807
|
+
method: 'post',
|
808
|
+
asynchronous: true,
|
809
|
+
contentType: 'application/x-www-form-urlencoded',
|
810
|
+
encoding: 'UTF-8',
|
811
|
+
parameters: ''
|
812
|
+
}
|
813
|
+
Object.extend(this.options, options || {});
|
814
|
+
|
815
|
+
this.options.method = this.options.method.toLowerCase();
|
816
|
+
if (typeof this.options.parameters == 'string')
|
817
|
+
this.options.parameters = this.options.parameters.toQueryParams();
|
818
|
+
}
|
819
|
+
}
|
820
|
+
|
821
|
+
Ajax.Request = Class.create();
|
822
|
+
Ajax.Request.Events =
|
823
|
+
['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
|
824
|
+
|
825
|
+
Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
|
826
|
+
_complete: false,
|
827
|
+
|
828
|
+
initialize: function(url, options) {
|
829
|
+
this.transport = Ajax.getTransport();
|
830
|
+
this.setOptions(options);
|
831
|
+
this.request(url);
|
832
|
+
},
|
833
|
+
|
834
|
+
request: function(url) {
|
835
|
+
this.url = url;
|
836
|
+
this.method = this.options.method;
|
837
|
+
var params = this.options.parameters;
|
838
|
+
|
839
|
+
if (!['get', 'post'].include(this.method)) {
|
840
|
+
// simulate other verbs over post
|
841
|
+
params['_method'] = this.method;
|
842
|
+
this.method = 'post';
|
843
|
+
}
|
844
|
+
|
845
|
+
params = Hash.toQueryString(params);
|
846
|
+
if (params && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_='
|
847
|
+
|
848
|
+
// when GET, append parameters to URL
|
849
|
+
if (this.method == 'get' && params)
|
850
|
+
this.url += (this.url.indexOf('?') > -1 ? '&' : '?') + params;
|
851
|
+
|
852
|
+
try {
|
853
|
+
Ajax.Responders.dispatch('onCreate', this, this.transport);
|
854
|
+
|
855
|
+
this.transport.open(this.method.toUpperCase(), this.url,
|
856
|
+
this.options.asynchronous);
|
857
|
+
|
858
|
+
if (this.options.asynchronous)
|
859
|
+
setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
|
860
|
+
|
861
|
+
this.transport.onreadystatechange = this.onStateChange.bind(this);
|
862
|
+
this.setRequestHeaders();
|
863
|
+
|
864
|
+
var body = this.method == 'post' ? (this.options.postBody || params) : null;
|
865
|
+
|
866
|
+
this.transport.send(body);
|
867
|
+
|
868
|
+
/* Force Firefox to handle ready state 4 for synchronous requests */
|
869
|
+
if (!this.options.asynchronous && this.transport.overrideMimeType)
|
870
|
+
this.onStateChange();
|
871
|
+
|
872
|
+
}
|
873
|
+
catch (e) {
|
874
|
+
this.dispatchException(e);
|
875
|
+
}
|
876
|
+
},
|
877
|
+
|
878
|
+
onStateChange: function() {
|
879
|
+
var readyState = this.transport.readyState;
|
880
|
+
if (readyState > 1 && !((readyState == 4) && this._complete))
|
881
|
+
this.respondToReadyState(this.transport.readyState);
|
882
|
+
},
|
883
|
+
|
884
|
+
setRequestHeaders: function() {
|
885
|
+
var headers = {
|
886
|
+
'X-Requested-With': 'XMLHttpRequest',
|
887
|
+
'X-Prototype-Version': Prototype.Version,
|
888
|
+
'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
|
889
|
+
};
|
890
|
+
|
891
|
+
if (this.method == 'post') {
|
892
|
+
headers['Content-type'] = this.options.contentType +
|
893
|
+
(this.options.encoding ? '; charset=' + this.options.encoding : '');
|
894
|
+
|
895
|
+
/* Force "Connection: close" for older Mozilla browsers to work
|
896
|
+
* around a bug where XMLHttpRequest sends an incorrect
|
897
|
+
* Content-length header. See Mozilla Bugzilla #246651.
|
898
|
+
*/
|
899
|
+
if (this.transport.overrideMimeType &&
|
900
|
+
(navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
|
901
|
+
headers['Connection'] = 'close';
|
902
|
+
}
|
903
|
+
|
904
|
+
// user-defined headers
|
905
|
+
if (typeof this.options.requestHeaders == 'object') {
|
906
|
+
var extras = this.options.requestHeaders;
|
907
|
+
|
908
|
+
if (typeof extras.push == 'function')
|
909
|
+
for (var i = 0, length = extras.length; i < length; i += 2)
|
910
|
+
headers[extras[i]] = extras[i+1];
|
911
|
+
else
|
912
|
+
$H(extras).each(function(pair) { headers[pair.key] = pair.value });
|
913
|
+
}
|
914
|
+
|
915
|
+
for (var name in headers)
|
916
|
+
this.transport.setRequestHeader(name, headers[name]);
|
917
|
+
},
|
918
|
+
|
919
|
+
success: function() {
|
920
|
+
return !this.transport.status
|
921
|
+
|| (this.transport.status >= 200 && this.transport.status < 300);
|
922
|
+
},
|
923
|
+
|
924
|
+
respondToReadyState: function(readyState) {
|
925
|
+
var state = Ajax.Request.Events[readyState];
|
926
|
+
var transport = this.transport, json = this.evalJSON();
|
927
|
+
|
928
|
+
if (state == 'Complete') {
|
929
|
+
try {
|
930
|
+
this._complete = true;
|
931
|
+
(this.options['on' + this.transport.status]
|
932
|
+
|| this.options['on' + (this.success() ? 'Success' : 'Failure')]
|
933
|
+
|| Prototype.emptyFunction)(transport, json);
|
934
|
+
} catch (e) {
|
935
|
+
this.dispatchException(e);
|
936
|
+
}
|
937
|
+
|
938
|
+
if ((this.getHeader('Content-type') || 'text/javascript').strip().
|
939
|
+
match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
|
940
|
+
this.evalResponse();
|
941
|
+
}
|
942
|
+
|
943
|
+
try {
|
944
|
+
(this.options['on' + state] || Prototype.emptyFunction)(transport, json);
|
945
|
+
Ajax.Responders.dispatch('on' + state, this, transport, json);
|
946
|
+
} catch (e) {
|
947
|
+
this.dispatchException(e);
|
948
|
+
}
|
949
|
+
|
950
|
+
if (state == 'Complete') {
|
951
|
+
// avoid memory leak in MSIE: clean up
|
952
|
+
this.transport.onreadystatechange = Prototype.emptyFunction;
|
953
|
+
}
|
954
|
+
},
|
955
|
+
|
956
|
+
getHeader: function(name) {
|
957
|
+
try {
|
958
|
+
return this.transport.getResponseHeader(name);
|
959
|
+
} catch (e) { return null }
|
960
|
+
},
|
961
|
+
|
962
|
+
evalJSON: function() {
|
963
|
+
try {
|
964
|
+
var json = this.getHeader('X-JSON');
|
965
|
+
return json ? eval('(' + json + ')') : null;
|
966
|
+
} catch (e) { return null }
|
967
|
+
},
|
968
|
+
|
969
|
+
evalResponse: function() {
|
970
|
+
try {
|
971
|
+
return eval(this.transport.responseText);
|
972
|
+
} catch (e) {
|
973
|
+
this.dispatchException(e);
|
974
|
+
}
|
975
|
+
},
|
976
|
+
|
977
|
+
dispatchException: function(exception) {
|
978
|
+
(this.options.onException || Prototype.emptyFunction)(this, exception);
|
979
|
+
Ajax.Responders.dispatch('onException', this, exception);
|
980
|
+
}
|
981
|
+
});
|
982
|
+
|
983
|
+
Ajax.Updater = Class.create();
|
984
|
+
|
985
|
+
Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
|
986
|
+
initialize: function(container, url, options) {
|
987
|
+
this.container = {
|
988
|
+
success: (container.success || container),
|
989
|
+
failure: (container.failure || (container.success ? null : container))
|
990
|
+
}
|
991
|
+
|
992
|
+
this.transport = Ajax.getTransport();
|
993
|
+
this.setOptions(options);
|
994
|
+
|
995
|
+
var onComplete = this.options.onComplete || Prototype.emptyFunction;
|
996
|
+
this.options.onComplete = (function(transport, param) {
|
997
|
+
this.updateContent();
|
998
|
+
onComplete(transport, param);
|
999
|
+
}).bind(this);
|
1000
|
+
|
1001
|
+
this.request(url);
|
1002
|
+
},
|
1003
|
+
|
1004
|
+
updateContent: function() {
|
1005
|
+
var receiver = this.container[this.success() ? 'success' : 'failure'];
|
1006
|
+
var response = this.transport.responseText;
|
1007
|
+
|
1008
|
+
if (!this.options.evalScripts) response = response.stripScripts();
|
1009
|
+
|
1010
|
+
if (receiver = $(receiver)) {
|
1011
|
+
if (this.options.insertion)
|
1012
|
+
new this.options.insertion(receiver, response);
|
1013
|
+
else
|
1014
|
+
receiver.update(response);
|
1015
|
+
}
|
1016
|
+
|
1017
|
+
if (this.success()) {
|
1018
|
+
if (this.onComplete)
|
1019
|
+
setTimeout(this.onComplete.bind(this), 10);
|
1020
|
+
}
|
1021
|
+
}
|
1022
|
+
});
|
1023
|
+
|
1024
|
+
Ajax.PeriodicalUpdater = Class.create();
|
1025
|
+
Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
|
1026
|
+
initialize: function(container, url, options) {
|
1027
|
+
this.setOptions(options);
|
1028
|
+
this.onComplete = this.options.onComplete;
|
1029
|
+
|
1030
|
+
this.frequency = (this.options.frequency || 2);
|
1031
|
+
this.decay = (this.options.decay || 1);
|
1032
|
+
|
1033
|
+
this.updater = {};
|
1034
|
+
this.container = container;
|
1035
|
+
this.url = url;
|
1036
|
+
|
1037
|
+
this.start();
|
1038
|
+
},
|
1039
|
+
|
1040
|
+
start: function() {
|
1041
|
+
this.options.onComplete = this.updateComplete.bind(this);
|
1042
|
+
this.onTimerEvent();
|
1043
|
+
},
|
1044
|
+
|
1045
|
+
stop: function() {
|
1046
|
+
this.updater.options.onComplete = undefined;
|
1047
|
+
clearTimeout(this.timer);
|
1048
|
+
(this.onComplete || Prototype.emptyFunction).apply(this, arguments);
|
1049
|
+
},
|
1050
|
+
|
1051
|
+
updateComplete: function(request) {
|
1052
|
+
if (this.options.decay) {
|
1053
|
+
this.decay = (request.responseText == this.lastText ?
|
1054
|
+
this.decay * this.options.decay : 1);
|
1055
|
+
|
1056
|
+
this.lastText = request.responseText;
|
1057
|
+
}
|
1058
|
+
this.timer = setTimeout(this.onTimerEvent.bind(this),
|
1059
|
+
this.decay * this.frequency * 1000);
|
1060
|
+
},
|
1061
|
+
|
1062
|
+
onTimerEvent: function() {
|
1063
|
+
this.updater = new Ajax.Updater(this.container, this.url, this.options);
|
1064
|
+
}
|
1065
|
+
});
|
1066
|
+
function $(element) {
|
1067
|
+
if (arguments.length > 1) {
|
1068
|
+
for (var i = 0, elements = [], length = arguments.length; i < length; i++)
|
1069
|
+
elements.push($(arguments[i]));
|
1070
|
+
return elements;
|
1071
|
+
}
|
1072
|
+
if (typeof element == 'string')
|
1073
|
+
element = document.getElementById(element);
|
1074
|
+
return Element.extend(element);
|
1075
|
+
}
|
1076
|
+
|
1077
|
+
if (Prototype.BrowserFeatures.XPath) {
|
1078
|
+
document._getElementsByXPath = function(expression, parentElement) {
|
1079
|
+
var results = [];
|
1080
|
+
var query = document.evaluate(expression, $(parentElement) || document,
|
1081
|
+
null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
1082
|
+
for (var i = 0, length = query.snapshotLength; i < length; i++)
|
1083
|
+
results.push(query.snapshotItem(i));
|
1084
|
+
return results;
|
1085
|
+
};
|
1086
|
+
}
|
1087
|
+
|
1088
|
+
document.getElementsByClassName = function(className, parentElement) {
|
1089
|
+
if (Prototype.BrowserFeatures.XPath) {
|
1090
|
+
var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
|
1091
|
+
return document._getElementsByXPath(q, parentElement);
|
1092
|
+
} else {
|
1093
|
+
var children = ($(parentElement) || document.body).getElementsByTagName('*');
|
1094
|
+
var elements = [], child;
|
1095
|
+
for (var i = 0, length = children.length; i < length; i++) {
|
1096
|
+
child = children[i];
|
1097
|
+
if (Element.hasClassName(child, className))
|
1098
|
+
elements.push(Element.extend(child));
|
1099
|
+
}
|
1100
|
+
return elements;
|
1101
|
+
}
|
1102
|
+
};
|
1103
|
+
|
1104
|
+
/*--------------------------------------------------------------------------*/
|
1105
|
+
|
1106
|
+
if (!window.Element)
|
1107
|
+
var Element = new Object();
|
1108
|
+
|
1109
|
+
Element.extend = function(element) {
|
1110
|
+
if (!element || _nativeExtensions || element.nodeType == 3) return element;
|
1111
|
+
|
1112
|
+
if (!element._extended && element.tagName && element != window) {
|
1113
|
+
var methods = Object.clone(Element.Methods), cache = Element.extend.cache;
|
1114
|
+
|
1115
|
+
if (element.tagName == 'FORM')
|
1116
|
+
Object.extend(methods, Form.Methods);
|
1117
|
+
if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
|
1118
|
+
Object.extend(methods, Form.Element.Methods);
|
1119
|
+
|
1120
|
+
Object.extend(methods, Element.Methods.Simulated);
|
1121
|
+
|
1122
|
+
for (var property in methods) {
|
1123
|
+
var value = methods[property];
|
1124
|
+
if (typeof value == 'function' && !(property in element))
|
1125
|
+
element[property] = cache.findOrStore(value);
|
1126
|
+
}
|
1127
|
+
}
|
1128
|
+
|
1129
|
+
element._extended = true;
|
1130
|
+
return element;
|
1131
|
+
};
|
1132
|
+
|
1133
|
+
Element.extend.cache = {
|
1134
|
+
findOrStore: function(value) {
|
1135
|
+
return this[value] = this[value] || function() {
|
1136
|
+
return value.apply(null, [this].concat($A(arguments)));
|
1137
|
+
}
|
1138
|
+
}
|
1139
|
+
};
|
1140
|
+
|
1141
|
+
Element.Methods = {
|
1142
|
+
visible: function(element) {
|
1143
|
+
return $(element).style.display != 'none';
|
1144
|
+
},
|
1145
|
+
|
1146
|
+
toggle: function(element) {
|
1147
|
+
element = $(element);
|
1148
|
+
Element[Element.visible(element) ? 'hide' : 'show'](element);
|
1149
|
+
return element;
|
1150
|
+
},
|
1151
|
+
|
1152
|
+
hide: function(element) {
|
1153
|
+
$(element).style.display = 'none';
|
1154
|
+
return element;
|
1155
|
+
},
|
1156
|
+
|
1157
|
+
show: function(element) {
|
1158
|
+
$(element).style.display = '';
|
1159
|
+
return element;
|
1160
|
+
},
|
1161
|
+
|
1162
|
+
remove: function(element) {
|
1163
|
+
element = $(element);
|
1164
|
+
element.parentNode.removeChild(element);
|
1165
|
+
return element;
|
1166
|
+
},
|
1167
|
+
|
1168
|
+
update: function(element, html) {
|
1169
|
+
html = typeof html == 'undefined' ? '' : html.toString();
|
1170
|
+
$(element).innerHTML = html.stripScripts();
|
1171
|
+
setTimeout(function() {html.evalScripts()}, 10);
|
1172
|
+
return element;
|
1173
|
+
},
|
1174
|
+
|
1175
|
+
replace: function(element, html) {
|
1176
|
+
element = $(element);
|
1177
|
+
html = typeof html == 'undefined' ? '' : html.toString();
|
1178
|
+
if (element.outerHTML) {
|
1179
|
+
element.outerHTML = html.stripScripts();
|
1180
|
+
} else {
|
1181
|
+
var range = element.ownerDocument.createRange();
|
1182
|
+
range.selectNodeContents(element);
|
1183
|
+
element.parentNode.replaceChild(
|
1184
|
+
range.createContextualFragment(html.stripScripts()), element);
|
1185
|
+
}
|
1186
|
+
setTimeout(function() {html.evalScripts()}, 10);
|
1187
|
+
return element;
|
1188
|
+
},
|
1189
|
+
|
1190
|
+
inspect: function(element) {
|
1191
|
+
element = $(element);
|
1192
|
+
var result = '<' + element.tagName.toLowerCase();
|
1193
|
+
$H({'id': 'id', 'className': 'class'}).each(function(pair) {
|
1194
|
+
var property = pair.first(), attribute = pair.last();
|
1195
|
+
var value = (element[property] || '').toString();
|
1196
|
+
if (value) result += ' ' + attribute + '=' + value.inspect(true);
|
1197
|
+
});
|
1198
|
+
return result + '>';
|
1199
|
+
},
|
1200
|
+
|
1201
|
+
recursivelyCollect: function(element, property) {
|
1202
|
+
element = $(element);
|
1203
|
+
var elements = [];
|
1204
|
+
while (element = element[property])
|
1205
|
+
if (element.nodeType == 1)
|
1206
|
+
elements.push(Element.extend(element));
|
1207
|
+
return elements;
|
1208
|
+
},
|
1209
|
+
|
1210
|
+
ancestors: function(element) {
|
1211
|
+
return $(element).recursivelyCollect('parentNode');
|
1212
|
+
},
|
1213
|
+
|
1214
|
+
descendants: function(element) {
|
1215
|
+
return $A($(element).getElementsByTagName('*'));
|
1216
|
+
},
|
1217
|
+
|
1218
|
+
immediateDescendants: function(element) {
|
1219
|
+
if (!(element = $(element).firstChild)) return [];
|
1220
|
+
while (element && element.nodeType != 1) element = element.nextSibling;
|
1221
|
+
if (element) return [element].concat($(element).nextSiblings());
|
1222
|
+
return [];
|
1223
|
+
},
|
1224
|
+
|
1225
|
+
previousSiblings: function(element) {
|
1226
|
+
return $(element).recursivelyCollect('previousSibling');
|
1227
|
+
},
|
1228
|
+
|
1229
|
+
nextSiblings: function(element) {
|
1230
|
+
return $(element).recursivelyCollect('nextSibling');
|
1231
|
+
},
|
1232
|
+
|
1233
|
+
siblings: function(element) {
|
1234
|
+
element = $(element);
|
1235
|
+
return element.previousSiblings().reverse().concat(element.nextSiblings());
|
1236
|
+
},
|
1237
|
+
|
1238
|
+
match: function(element, selector) {
|
1239
|
+
if (typeof selector == 'string')
|
1240
|
+
selector = new Selector(selector);
|
1241
|
+
return selector.match($(element));
|
1242
|
+
},
|
1243
|
+
|
1244
|
+
up: function(element, expression, index) {
|
1245
|
+
return Selector.findElement($(element).ancestors(), expression, index);
|
1246
|
+
},
|
1247
|
+
|
1248
|
+
down: function(element, expression, index) {
|
1249
|
+
return Selector.findElement($(element).descendants(), expression, index);
|
1250
|
+
},
|
1251
|
+
|
1252
|
+
previous: function(element, expression, index) {
|
1253
|
+
return Selector.findElement($(element).previousSiblings(), expression, index);
|
1254
|
+
},
|
1255
|
+
|
1256
|
+
next: function(element, expression, index) {
|
1257
|
+
return Selector.findElement($(element).nextSiblings(), expression, index);
|
1258
|
+
},
|
1259
|
+
|
1260
|
+
getElementsBySelector: function() {
|
1261
|
+
var args = $A(arguments), element = $(args.shift());
|
1262
|
+
return Selector.findChildElements(element, args);
|
1263
|
+
},
|
1264
|
+
|
1265
|
+
getElementsByClassName: function(element, className) {
|
1266
|
+
return document.getElementsByClassName(className, element);
|
1267
|
+
},
|
1268
|
+
|
1269
|
+
readAttribute: function(element, name) {
|
1270
|
+
element = $(element);
|
1271
|
+
if (document.all && !window.opera) {
|
1272
|
+
var t = Element._attributeTranslations;
|
1273
|
+
if (t.values[name]) return t.values[name](element, name);
|
1274
|
+
if (t.names[name]) name = t.names[name];
|
1275
|
+
var attribute = element.attributes[name];
|
1276
|
+
if(attribute) return attribute.nodeValue;
|
1277
|
+
}
|
1278
|
+
return element.getAttribute(name);
|
1279
|
+
},
|
1280
|
+
|
1281
|
+
getHeight: function(element) {
|
1282
|
+
return $(element).getDimensions().height;
|
1283
|
+
},
|
1284
|
+
|
1285
|
+
getWidth: function(element) {
|
1286
|
+
return $(element).getDimensions().width;
|
1287
|
+
},
|
1288
|
+
|
1289
|
+
classNames: function(element) {
|
1290
|
+
return new Element.ClassNames(element);
|
1291
|
+
},
|
1292
|
+
|
1293
|
+
hasClassName: function(element, className) {
|
1294
|
+
if (!(element = $(element))) return;
|
1295
|
+
var elementClassName = element.className;
|
1296
|
+
if (elementClassName.length == 0) return false;
|
1297
|
+
if (elementClassName == className ||
|
1298
|
+
elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
|
1299
|
+
return true;
|
1300
|
+
return false;
|
1301
|
+
},
|
1302
|
+
|
1303
|
+
addClassName: function(element, className) {
|
1304
|
+
if (!(element = $(element))) return;
|
1305
|
+
Element.classNames(element).add(className);
|
1306
|
+
return element;
|
1307
|
+
},
|
1308
|
+
|
1309
|
+
removeClassName: function(element, className) {
|
1310
|
+
if (!(element = $(element))) return;
|
1311
|
+
Element.classNames(element).remove(className);
|
1312
|
+
return element;
|
1313
|
+
},
|
1314
|
+
|
1315
|
+
toggleClassName: function(element, className) {
|
1316
|
+
if (!(element = $(element))) return;
|
1317
|
+
Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
|
1318
|
+
return element;
|
1319
|
+
},
|
1320
|
+
|
1321
|
+
observe: function() {
|
1322
|
+
Event.observe.apply(Event, arguments);
|
1323
|
+
return $A(arguments).first();
|
1324
|
+
},
|
1325
|
+
|
1326
|
+
stopObserving: function() {
|
1327
|
+
Event.stopObserving.apply(Event, arguments);
|
1328
|
+
return $A(arguments).first();
|
1329
|
+
},
|
1330
|
+
|
1331
|
+
// removes whitespace-only text node children
|
1332
|
+
cleanWhitespace: function(element) {
|
1333
|
+
element = $(element);
|
1334
|
+
var node = element.firstChild;
|
1335
|
+
while (node) {
|
1336
|
+
var nextNode = node.nextSibling;
|
1337
|
+
if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
|
1338
|
+
element.removeChild(node);
|
1339
|
+
node = nextNode;
|
1340
|
+
}
|
1341
|
+
return element;
|
1342
|
+
},
|
1343
|
+
|
1344
|
+
empty: function(element) {
|
1345
|
+
return $(element).innerHTML.match(/^\s*$/);
|
1346
|
+
},
|
1347
|
+
|
1348
|
+
descendantOf: function(element, ancestor) {
|
1349
|
+
element = $(element), ancestor = $(ancestor);
|
1350
|
+
while (element = element.parentNode)
|
1351
|
+
if (element == ancestor) return true;
|
1352
|
+
return false;
|
1353
|
+
},
|
1354
|
+
|
1355
|
+
scrollTo: function(element) {
|
1356
|
+
element = $(element);
|
1357
|
+
var pos = Position.cumulativeOffset(element);
|
1358
|
+
window.scrollTo(pos[0], pos[1]);
|
1359
|
+
return element;
|
1360
|
+
},
|
1361
|
+
|
1362
|
+
getStyle: function(element, style) {
|
1363
|
+
element = $(element);
|
1364
|
+
if (['float','cssFloat'].include(style))
|
1365
|
+
style = (typeof element.style.styleFloat != 'undefined' ? 'styleFloat' : 'cssFloat');
|
1366
|
+
style = style.camelize();
|
1367
|
+
var value = element.style[style];
|
1368
|
+
if (!value) {
|
1369
|
+
if (document.defaultView && document.defaultView.getComputedStyle) {
|
1370
|
+
var css = document.defaultView.getComputedStyle(element, null);
|
1371
|
+
value = css ? css[style] : null;
|
1372
|
+
} else if (element.currentStyle) {
|
1373
|
+
value = element.currentStyle[style];
|
1374
|
+
}
|
1375
|
+
}
|
1376
|
+
|
1377
|
+
if((value == 'auto') && ['width','height'].include(style) && (element.getStyle('display') != 'none'))
|
1378
|
+
value = element['offset'+style.capitalize()] + 'px';
|
1379
|
+
|
1380
|
+
if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
|
1381
|
+
if (Element.getStyle(element, 'position') == 'static') value = 'auto';
|
1382
|
+
if(style == 'opacity') {
|
1383
|
+
if(value) return parseFloat(value);
|
1384
|
+
if(value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
|
1385
|
+
if(value[1]) return parseFloat(value[1]) / 100;
|
1386
|
+
return 1.0;
|
1387
|
+
}
|
1388
|
+
return value == 'auto' ? null : value;
|
1389
|
+
},
|
1390
|
+
|
1391
|
+
setStyle: function(element, style) {
|
1392
|
+
element = $(element);
|
1393
|
+
for (var name in style) {
|
1394
|
+
var value = style[name];
|
1395
|
+
if(name == 'opacity') {
|
1396
|
+
if (value == 1) {
|
1397
|
+
value = (/Gecko/.test(navigator.userAgent) &&
|
1398
|
+
!/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : 1.0;
|
1399
|
+
if(/MSIE/.test(navigator.userAgent) && !window.opera)
|
1400
|
+
element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
|
1401
|
+
} else if(value == '') {
|
1402
|
+
if(/MSIE/.test(navigator.userAgent) && !window.opera)
|
1403
|
+
element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
|
1404
|
+
} else {
|
1405
|
+
if(value < 0.00001) value = 0;
|
1406
|
+
if(/MSIE/.test(navigator.userAgent) && !window.opera)
|
1407
|
+
element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') +
|
1408
|
+
'alpha(opacity='+value*100+')';
|
1409
|
+
}
|
1410
|
+
} else if(['float','cssFloat'].include(name)) name = (typeof element.style.styleFloat != 'undefined') ? 'styleFloat' : 'cssFloat';
|
1411
|
+
element.style[name.camelize()] = value;
|
1412
|
+
}
|
1413
|
+
return element;
|
1414
|
+
},
|
1415
|
+
|
1416
|
+
getDimensions: function(element) {
|
1417
|
+
element = $(element);
|
1418
|
+
var display = $(element).getStyle('display');
|
1419
|
+
if (display != 'none' && display != null) // Safari bug
|
1420
|
+
return {width: element.offsetWidth, height: element.offsetHeight};
|
1421
|
+
|
1422
|
+
// All *Width and *Height properties give 0 on elements with display none,
|
1423
|
+
// so enable the element temporarily
|
1424
|
+
var els = element.style;
|
1425
|
+
var originalVisibility = els.visibility;
|
1426
|
+
var originalPosition = els.position;
|
1427
|
+
var originalDisplay = els.display;
|
1428
|
+
els.visibility = 'hidden';
|
1429
|
+
els.position = 'absolute';
|
1430
|
+
els.display = 'block';
|
1431
|
+
var originalWidth = element.clientWidth;
|
1432
|
+
var originalHeight = element.clientHeight;
|
1433
|
+
els.display = originalDisplay;
|
1434
|
+
els.position = originalPosition;
|
1435
|
+
els.visibility = originalVisibility;
|
1436
|
+
return {width: originalWidth, height: originalHeight};
|
1437
|
+
},
|
1438
|
+
|
1439
|
+
makePositioned: function(element) {
|
1440
|
+
element = $(element);
|
1441
|
+
var pos = Element.getStyle(element, 'position');
|
1442
|
+
if (pos == 'static' || !pos) {
|
1443
|
+
element._madePositioned = true;
|
1444
|
+
element.style.position = 'relative';
|
1445
|
+
// Opera returns the offset relative to the positioning context, when an
|
1446
|
+
// element is position relative but top and left have not been defined
|
1447
|
+
if (window.opera) {
|
1448
|
+
element.style.top = 0;
|
1449
|
+
element.style.left = 0;
|
1450
|
+
}
|
1451
|
+
}
|
1452
|
+
return element;
|
1453
|
+
},
|
1454
|
+
|
1455
|
+
undoPositioned: function(element) {
|
1456
|
+
element = $(element);
|
1457
|
+
if (element._madePositioned) {
|
1458
|
+
element._madePositioned = undefined;
|
1459
|
+
element.style.position =
|
1460
|
+
element.style.top =
|
1461
|
+
element.style.left =
|
1462
|
+
element.style.bottom =
|
1463
|
+
element.style.right = '';
|
1464
|
+
}
|
1465
|
+
return element;
|
1466
|
+
},
|
1467
|
+
|
1468
|
+
makeClipping: function(element) {
|
1469
|
+
element = $(element);
|
1470
|
+
if (element._overflow) return element;
|
1471
|
+
element._overflow = element.style.overflow || 'auto';
|
1472
|
+
if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
|
1473
|
+
element.style.overflow = 'hidden';
|
1474
|
+
return element;
|
1475
|
+
},
|
1476
|
+
|
1477
|
+
undoClipping: function(element) {
|
1478
|
+
element = $(element);
|
1479
|
+
if (!element._overflow) return element;
|
1480
|
+
element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
|
1481
|
+
element._overflow = null;
|
1482
|
+
return element;
|
1483
|
+
}
|
1484
|
+
};
|
1485
|
+
|
1486
|
+
Object.extend(Element.Methods, {childOf: Element.Methods.descendantOf});
|
1487
|
+
|
1488
|
+
Element._attributeTranslations = {};
|
1489
|
+
|
1490
|
+
Element._attributeTranslations.names = {
|
1491
|
+
colspan: "colSpan",
|
1492
|
+
rowspan: "rowSpan",
|
1493
|
+
valign: "vAlign",
|
1494
|
+
datetime: "dateTime",
|
1495
|
+
accesskey: "accessKey",
|
1496
|
+
tabindex: "tabIndex",
|
1497
|
+
enctype: "encType",
|
1498
|
+
maxlength: "maxLength",
|
1499
|
+
readonly: "readOnly",
|
1500
|
+
longdesc: "longDesc"
|
1501
|
+
};
|
1502
|
+
|
1503
|
+
Element._attributeTranslations.values = {
|
1504
|
+
_getAttr: function(element, attribute) {
|
1505
|
+
return element.getAttribute(attribute, 2);
|
1506
|
+
},
|
1507
|
+
|
1508
|
+
_flag: function(element, attribute) {
|
1509
|
+
return $(element).hasAttribute(attribute) ? attribute : null;
|
1510
|
+
},
|
1511
|
+
|
1512
|
+
style: function(element) {
|
1513
|
+
return element.style.cssText.toLowerCase();
|
1514
|
+
},
|
1515
|
+
|
1516
|
+
title: function(element) {
|
1517
|
+
var node = element.getAttributeNode('title');
|
1518
|
+
return node.specified ? node.nodeValue : null;
|
1519
|
+
}
|
1520
|
+
};
|
1521
|
+
|
1522
|
+
Object.extend(Element._attributeTranslations.values, {
|
1523
|
+
href: Element._attributeTranslations.values._getAttr,
|
1524
|
+
src: Element._attributeTranslations.values._getAttr,
|
1525
|
+
disabled: Element._attributeTranslations.values._flag,
|
1526
|
+
checked: Element._attributeTranslations.values._flag,
|
1527
|
+
readonly: Element._attributeTranslations.values._flag,
|
1528
|
+
multiple: Element._attributeTranslations.values._flag
|
1529
|
+
});
|
1530
|
+
|
1531
|
+
Element.Methods.Simulated = {
|
1532
|
+
hasAttribute: function(element, attribute) {
|
1533
|
+
var t = Element._attributeTranslations;
|
1534
|
+
attribute = t.names[attribute] || attribute;
|
1535
|
+
return $(element).getAttributeNode(attribute).specified;
|
1536
|
+
}
|
1537
|
+
};
|
1538
|
+
|
1539
|
+
// IE is missing .innerHTML support for TABLE-related elements
|
1540
|
+
if (document.all && !window.opera){
|
1541
|
+
Element.Methods.update = function(element, html) {
|
1542
|
+
element = $(element);
|
1543
|
+
html = typeof html == 'undefined' ? '' : html.toString();
|
1544
|
+
var tagName = element.tagName.toUpperCase();
|
1545
|
+
if (['THEAD','TBODY','TR','TD'].include(tagName)) {
|
1546
|
+
var div = document.createElement('div');
|
1547
|
+
switch (tagName) {
|
1548
|
+
case 'THEAD':
|
1549
|
+
case 'TBODY':
|
1550
|
+
div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>';
|
1551
|
+
depth = 2;
|
1552
|
+
break;
|
1553
|
+
case 'TR':
|
1554
|
+
div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>';
|
1555
|
+
depth = 3;
|
1556
|
+
break;
|
1557
|
+
case 'TD':
|
1558
|
+
div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>';
|
1559
|
+
depth = 4;
|
1560
|
+
}
|
1561
|
+
$A(element.childNodes).each(function(node){
|
1562
|
+
element.removeChild(node)
|
1563
|
+
});
|
1564
|
+
depth.times(function(){ div = div.firstChild });
|
1565
|
+
|
1566
|
+
$A(div.childNodes).each(
|
1567
|
+
function(node){ element.appendChild(node) });
|
1568
|
+
} else {
|
1569
|
+
element.innerHTML = html.stripScripts();
|
1570
|
+
}
|
1571
|
+
setTimeout(function() {html.evalScripts()}, 10);
|
1572
|
+
return element;
|
1573
|
+
}
|
1574
|
+
};
|
1575
|
+
|
1576
|
+
Object.extend(Element, Element.Methods);
|
1577
|
+
|
1578
|
+
var _nativeExtensions = false;
|
1579
|
+
|
1580
|
+
if(/Konqueror|Safari|KHTML/.test(navigator.userAgent))
|
1581
|
+
['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) {
|
1582
|
+
var className = 'HTML' + tag + 'Element';
|
1583
|
+
if(window[className]) return;
|
1584
|
+
var klass = window[className] = {};
|
1585
|
+
klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__;
|
1586
|
+
});
|
1587
|
+
|
1588
|
+
Element.addMethods = function(methods) {
|
1589
|
+
Object.extend(Element.Methods, methods || {});
|
1590
|
+
|
1591
|
+
function copy(methods, destination, onlyIfAbsent) {
|
1592
|
+
onlyIfAbsent = onlyIfAbsent || false;
|
1593
|
+
var cache = Element.extend.cache;
|
1594
|
+
for (var property in methods) {
|
1595
|
+
var value = methods[property];
|
1596
|
+
if (!onlyIfAbsent || !(property in destination))
|
1597
|
+
destination[property] = cache.findOrStore(value);
|
1598
|
+
}
|
1599
|
+
}
|
1600
|
+
|
1601
|
+
if (typeof HTMLElement != 'undefined') {
|
1602
|
+
copy(Element.Methods, HTMLElement.prototype);
|
1603
|
+
copy(Element.Methods.Simulated, HTMLElement.prototype, true);
|
1604
|
+
copy(Form.Methods, HTMLFormElement.prototype);
|
1605
|
+
[HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
|
1606
|
+
copy(Form.Element.Methods, klass.prototype);
|
1607
|
+
});
|
1608
|
+
_nativeExtensions = true;
|
1609
|
+
}
|
1610
|
+
}
|
1611
|
+
|
1612
|
+
var Toggle = new Object();
|
1613
|
+
Toggle.display = Element.toggle;
|
1614
|
+
|
1615
|
+
/*--------------------------------------------------------------------------*/
|
1616
|
+
|
1617
|
+
Abstract.Insertion = function(adjacency) {
|
1618
|
+
this.adjacency = adjacency;
|
1619
|
+
}
|
1620
|
+
|
1621
|
+
Abstract.Insertion.prototype = {
|
1622
|
+
initialize: function(element, content) {
|
1623
|
+
this.element = $(element);
|
1624
|
+
this.content = content.stripScripts();
|
1625
|
+
|
1626
|
+
if (this.adjacency && this.element.insertAdjacentHTML) {
|
1627
|
+
try {
|
1628
|
+
this.element.insertAdjacentHTML(this.adjacency, this.content);
|
1629
|
+
} catch (e) {
|
1630
|
+
var tagName = this.element.tagName.toUpperCase();
|
1631
|
+
if (['TBODY', 'TR'].include(tagName)) {
|
1632
|
+
this.insertContent(this.contentFromAnonymousTable());
|
1633
|
+
} else {
|
1634
|
+
throw e;
|
1635
|
+
}
|
1636
|
+
}
|
1637
|
+
} else {
|
1638
|
+
this.range = this.element.ownerDocument.createRange();
|
1639
|
+
if (this.initializeRange) this.initializeRange();
|
1640
|
+
this.insertContent([this.range.createContextualFragment(this.content)]);
|
1641
|
+
}
|
1642
|
+
|
1643
|
+
setTimeout(function() {content.evalScripts()}, 10);
|
1644
|
+
},
|
1645
|
+
|
1646
|
+
contentFromAnonymousTable: function() {
|
1647
|
+
var div = document.createElement('div');
|
1648
|
+
div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
|
1649
|
+
return $A(div.childNodes[0].childNodes[0].childNodes);
|
1650
|
+
}
|
1651
|
+
}
|
1652
|
+
|
1653
|
+
var Insertion = new Object();
|
1654
|
+
|
1655
|
+
Insertion.Before = Class.create();
|
1656
|
+
Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
|
1657
|
+
initializeRange: function() {
|
1658
|
+
this.range.setStartBefore(this.element);
|
1659
|
+
},
|
1660
|
+
|
1661
|
+
insertContent: function(fragments) {
|
1662
|
+
fragments.each((function(fragment) {
|
1663
|
+
this.element.parentNode.insertBefore(fragment, this.element);
|
1664
|
+
}).bind(this));
|
1665
|
+
}
|
1666
|
+
});
|
1667
|
+
|
1668
|
+
Insertion.Top = Class.create();
|
1669
|
+
Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
|
1670
|
+
initializeRange: function() {
|
1671
|
+
this.range.selectNodeContents(this.element);
|
1672
|
+
this.range.collapse(true);
|
1673
|
+
},
|
1674
|
+
|
1675
|
+
insertContent: function(fragments) {
|
1676
|
+
fragments.reverse(false).each((function(fragment) {
|
1677
|
+
this.element.insertBefore(fragment, this.element.firstChild);
|
1678
|
+
}).bind(this));
|
1679
|
+
}
|
1680
|
+
});
|
1681
|
+
|
1682
|
+
Insertion.Bottom = Class.create();
|
1683
|
+
Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
|
1684
|
+
initializeRange: function() {
|
1685
|
+
this.range.selectNodeContents(this.element);
|
1686
|
+
this.range.collapse(this.element);
|
1687
|
+
},
|
1688
|
+
|
1689
|
+
insertContent: function(fragments) {
|
1690
|
+
fragments.each((function(fragment) {
|
1691
|
+
this.element.appendChild(fragment);
|
1692
|
+
}).bind(this));
|
1693
|
+
}
|
1694
|
+
});
|
1695
|
+
|
1696
|
+
Insertion.After = Class.create();
|
1697
|
+
Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
|
1698
|
+
initializeRange: function() {
|
1699
|
+
this.range.setStartAfter(this.element);
|
1700
|
+
},
|
1701
|
+
|
1702
|
+
insertContent: function(fragments) {
|
1703
|
+
fragments.each((function(fragment) {
|
1704
|
+
this.element.parentNode.insertBefore(fragment,
|
1705
|
+
this.element.nextSibling);
|
1706
|
+
}).bind(this));
|
1707
|
+
}
|
1708
|
+
});
|
1709
|
+
|
1710
|
+
/*--------------------------------------------------------------------------*/
|
1711
|
+
|
1712
|
+
Element.ClassNames = Class.create();
|
1713
|
+
Element.ClassNames.prototype = {
|
1714
|
+
initialize: function(element) {
|
1715
|
+
this.element = $(element);
|
1716
|
+
},
|
1717
|
+
|
1718
|
+
_each: function(iterator) {
|
1719
|
+
this.element.className.split(/\s+/).select(function(name) {
|
1720
|
+
return name.length > 0;
|
1721
|
+
})._each(iterator);
|
1722
|
+
},
|
1723
|
+
|
1724
|
+
set: function(className) {
|
1725
|
+
this.element.className = className;
|
1726
|
+
},
|
1727
|
+
|
1728
|
+
add: function(classNameToAdd) {
|
1729
|
+
if (this.include(classNameToAdd)) return;
|
1730
|
+
this.set($A(this).concat(classNameToAdd).join(' '));
|
1731
|
+
},
|
1732
|
+
|
1733
|
+
remove: function(classNameToRemove) {
|
1734
|
+
if (!this.include(classNameToRemove)) return;
|
1735
|
+
this.set($A(this).without(classNameToRemove).join(' '));
|
1736
|
+
},
|
1737
|
+
|
1738
|
+
toString: function() {
|
1739
|
+
return $A(this).join(' ');
|
1740
|
+
}
|
1741
|
+
};
|
1742
|
+
|
1743
|
+
Object.extend(Element.ClassNames.prototype, Enumerable);
|
1744
|
+
var Selector = Class.create();
|
1745
|
+
Selector.prototype = {
|
1746
|
+
initialize: function(expression) {
|
1747
|
+
this.params = {classNames: []};
|
1748
|
+
this.expression = expression.toString().strip();
|
1749
|
+
this.parseExpression();
|
1750
|
+
this.compileMatcher();
|
1751
|
+
},
|
1752
|
+
|
1753
|
+
parseExpression: function() {
|
1754
|
+
function abort(message) { throw 'Parse error in selector: ' + message; }
|
1755
|
+
|
1756
|
+
if (this.expression == '') abort('empty expression');
|
1757
|
+
|
1758
|
+
var params = this.params, expr = this.expression, match, modifier, clause, rest;
|
1759
|
+
while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
|
1760
|
+
params.attributes = params.attributes || [];
|
1761
|
+
params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
|
1762
|
+
expr = match[1];
|
1763
|
+
}
|
1764
|
+
|
1765
|
+
if (expr == '*') return this.params.wildcard = true;
|
1766
|
+
|
1767
|
+
while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
|
1768
|
+
modifier = match[1], clause = match[2], rest = match[3];
|
1769
|
+
switch (modifier) {
|
1770
|
+
case '#': params.id = clause; break;
|
1771
|
+
case '.': params.classNames.push(clause); break;
|
1772
|
+
case '':
|
1773
|
+
case undefined: params.tagName = clause.toUpperCase(); break;
|
1774
|
+
default: abort(expr.inspect());
|
1775
|
+
}
|
1776
|
+
expr = rest;
|
1777
|
+
}
|
1778
|
+
|
1779
|
+
if (expr.length > 0) abort(expr.inspect());
|
1780
|
+
},
|
1781
|
+
|
1782
|
+
buildMatchExpression: function() {
|
1783
|
+
var params = this.params, conditions = [], clause;
|
1784
|
+
|
1785
|
+
if (params.wildcard)
|
1786
|
+
conditions.push('true');
|
1787
|
+
if (clause = params.id)
|
1788
|
+
conditions.push('element.readAttribute("id") == ' + clause.inspect());
|
1789
|
+
if (clause = params.tagName)
|
1790
|
+
conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
|
1791
|
+
if ((clause = params.classNames).length > 0)
|
1792
|
+
for (var i = 0, length = clause.length; i < length; i++)
|
1793
|
+
conditions.push('element.hasClassName(' + clause[i].inspect() + ')');
|
1794
|
+
if (clause = params.attributes) {
|
1795
|
+
clause.each(function(attribute) {
|
1796
|
+
var value = 'element.readAttribute(' + attribute.name.inspect() + ')';
|
1797
|
+
var splitValueBy = function(delimiter) {
|
1798
|
+
return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
|
1799
|
+
}
|
1800
|
+
|
1801
|
+
switch (attribute.operator) {
|
1802
|
+
case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break;
|
1803
|
+
case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
|
1804
|
+
case '|=': conditions.push(
|
1805
|
+
splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
|
1806
|
+
); break;
|
1807
|
+
case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break;
|
1808
|
+
case '':
|
1809
|
+
case undefined: conditions.push('element.hasAttribute(' + attribute.name.inspect() + ')'); break;
|
1810
|
+
default: throw 'Unknown operator ' + attribute.operator + ' in selector';
|
1811
|
+
}
|
1812
|
+
});
|
1813
|
+
}
|
1814
|
+
|
1815
|
+
return conditions.join(' && ');
|
1816
|
+
},
|
1817
|
+
|
1818
|
+
compileMatcher: function() {
|
1819
|
+
this.match = new Function('element', 'if (!element.tagName) return false; \
|
1820
|
+
element = $(element); \
|
1821
|
+
return ' + this.buildMatchExpression());
|
1822
|
+
},
|
1823
|
+
|
1824
|
+
findElements: function(scope) {
|
1825
|
+
var element;
|
1826
|
+
|
1827
|
+
if (element = $(this.params.id))
|
1828
|
+
if (this.match(element))
|
1829
|
+
if (!scope || Element.childOf(element, scope))
|
1830
|
+
return [element];
|
1831
|
+
|
1832
|
+
scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
|
1833
|
+
|
1834
|
+
var results = [];
|
1835
|
+
for (var i = 0, length = scope.length; i < length; i++)
|
1836
|
+
if (this.match(element = scope[i]))
|
1837
|
+
results.push(Element.extend(element));
|
1838
|
+
|
1839
|
+
return results;
|
1840
|
+
},
|
1841
|
+
|
1842
|
+
toString: function() {
|
1843
|
+
return this.expression;
|
1844
|
+
}
|
1845
|
+
}
|
1846
|
+
|
1847
|
+
Object.extend(Selector, {
|
1848
|
+
matchElements: function(elements, expression) {
|
1849
|
+
var selector = new Selector(expression);
|
1850
|
+
return elements.select(selector.match.bind(selector)).map(Element.extend);
|
1851
|
+
},
|
1852
|
+
|
1853
|
+
findElement: function(elements, expression, index) {
|
1854
|
+
if (typeof expression == 'number') index = expression, expression = false;
|
1855
|
+
return Selector.matchElements(elements, expression || '*')[index || 0];
|
1856
|
+
},
|
1857
|
+
|
1858
|
+
findChildElements: function(element, expressions) {
|
1859
|
+
return expressions.map(function(expression) {
|
1860
|
+
return expression.match(/[^\s"]+(?:"[^"]*"[^\s"]+)*/g).inject([null], function(results, expr) {
|
1861
|
+
var selector = new Selector(expr);
|
1862
|
+
return results.inject([], function(elements, result) {
|
1863
|
+
return elements.concat(selector.findElements(result || element));
|
1864
|
+
});
|
1865
|
+
});
|
1866
|
+
}).flatten();
|
1867
|
+
}
|
1868
|
+
});
|
1869
|
+
|
1870
|
+
function $$() {
|
1871
|
+
return Selector.findChildElements(document, $A(arguments));
|
1872
|
+
}
|
1873
|
+
var Form = {
|
1874
|
+
reset: function(form) {
|
1875
|
+
$(form).reset();
|
1876
|
+
return form;
|
1877
|
+
},
|
1878
|
+
|
1879
|
+
serializeElements: function(elements, getHash) {
|
1880
|
+
var data = elements.inject({}, function(result, element) {
|
1881
|
+
if (!element.disabled && element.name) {
|
1882
|
+
var key = element.name, value = $(element).getValue();
|
1883
|
+
if (value != undefined) {
|
1884
|
+
if (result[key]) {
|
1885
|
+
if (result[key].constructor != Array) result[key] = [result[key]];
|
1886
|
+
result[key].push(value);
|
1887
|
+
}
|
1888
|
+
else result[key] = value;
|
1889
|
+
}
|
1890
|
+
}
|
1891
|
+
return result;
|
1892
|
+
});
|
1893
|
+
|
1894
|
+
return getHash ? data : Hash.toQueryString(data);
|
1895
|
+
}
|
1896
|
+
};
|
1897
|
+
|
1898
|
+
Form.Methods = {
|
1899
|
+
serialize: function(form, getHash) {
|
1900
|
+
return Form.serializeElements(Form.getElements(form), getHash);
|
1901
|
+
},
|
1902
|
+
|
1903
|
+
getElements: function(form) {
|
1904
|
+
return $A($(form).getElementsByTagName('*')).inject([],
|
1905
|
+
function(elements, child) {
|
1906
|
+
if (Form.Element.Serializers[child.tagName.toLowerCase()])
|
1907
|
+
elements.push(Element.extend(child));
|
1908
|
+
return elements;
|
1909
|
+
}
|
1910
|
+
);
|
1911
|
+
},
|
1912
|
+
|
1913
|
+
getInputs: function(form, typeName, name) {
|
1914
|
+
form = $(form);
|
1915
|
+
var inputs = form.getElementsByTagName('input');
|
1916
|
+
|
1917
|
+
if (!typeName && !name) return $A(inputs).map(Element.extend);
|
1918
|
+
|
1919
|
+
for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
|
1920
|
+
var input = inputs[i];
|
1921
|
+
if ((typeName && input.type != typeName) || (name && input.name != name))
|
1922
|
+
continue;
|
1923
|
+
matchingInputs.push(Element.extend(input));
|
1924
|
+
}
|
1925
|
+
|
1926
|
+
return matchingInputs;
|
1927
|
+
},
|
1928
|
+
|
1929
|
+
disable: function(form) {
|
1930
|
+
form = $(form);
|
1931
|
+
form.getElements().each(function(element) {
|
1932
|
+
element.blur();
|
1933
|
+
element.disabled = 'true';
|
1934
|
+
});
|
1935
|
+
return form;
|
1936
|
+
},
|
1937
|
+
|
1938
|
+
enable: function(form) {
|
1939
|
+
form = $(form);
|
1940
|
+
form.getElements().each(function(element) {
|
1941
|
+
element.disabled = '';
|
1942
|
+
});
|
1943
|
+
return form;
|
1944
|
+
},
|
1945
|
+
|
1946
|
+
findFirstElement: function(form) {
|
1947
|
+
return $(form).getElements().find(function(element) {
|
1948
|
+
return element.type != 'hidden' && !element.disabled &&
|
1949
|
+
['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
|
1950
|
+
});
|
1951
|
+
},
|
1952
|
+
|
1953
|
+
focusFirstElement: function(form) {
|
1954
|
+
form = $(form);
|
1955
|
+
form.findFirstElement().activate();
|
1956
|
+
return form;
|
1957
|
+
}
|
1958
|
+
}
|
1959
|
+
|
1960
|
+
Object.extend(Form, Form.Methods);
|
1961
|
+
|
1962
|
+
/*--------------------------------------------------------------------------*/
|
1963
|
+
|
1964
|
+
Form.Element = {
|
1965
|
+
focus: function(element) {
|
1966
|
+
$(element).focus();
|
1967
|
+
return element;
|
1968
|
+
},
|
1969
|
+
|
1970
|
+
select: function(element) {
|
1971
|
+
$(element).select();
|
1972
|
+
return element;
|
1973
|
+
}
|
1974
|
+
}
|
1975
|
+
|
1976
|
+
Form.Element.Methods = {
|
1977
|
+
serialize: function(element) {
|
1978
|
+
element = $(element);
|
1979
|
+
if (!element.disabled && element.name) {
|
1980
|
+
var value = element.getValue();
|
1981
|
+
if (value != undefined) {
|
1982
|
+
var pair = {};
|
1983
|
+
pair[element.name] = value;
|
1984
|
+
return Hash.toQueryString(pair);
|
1985
|
+
}
|
1986
|
+
}
|
1987
|
+
return '';
|
1988
|
+
},
|
1989
|
+
|
1990
|
+
getValue: function(element) {
|
1991
|
+
element = $(element);
|
1992
|
+
var method = element.tagName.toLowerCase();
|
1993
|
+
return Form.Element.Serializers[method](element);
|
1994
|
+
},
|
1995
|
+
|
1996
|
+
clear: function(element) {
|
1997
|
+
$(element).value = '';
|
1998
|
+
return element;
|
1999
|
+
},
|
2000
|
+
|
2001
|
+
present: function(element) {
|
2002
|
+
return $(element).value != '';
|
2003
|
+
},
|
2004
|
+
|
2005
|
+
activate: function(element) {
|
2006
|
+
element = $(element);
|
2007
|
+
element.focus();
|
2008
|
+
if (element.select && ( element.tagName.toLowerCase() != 'input' ||
|
2009
|
+
!['button', 'reset', 'submit'].include(element.type) ) )
|
2010
|
+
element.select();
|
2011
|
+
return element;
|
2012
|
+
},
|
2013
|
+
|
2014
|
+
disable: function(element) {
|
2015
|
+
element = $(element);
|
2016
|
+
element.disabled = true;
|
2017
|
+
return element;
|
2018
|
+
},
|
2019
|
+
|
2020
|
+
enable: function(element) {
|
2021
|
+
element = $(element);
|
2022
|
+
element.blur();
|
2023
|
+
element.disabled = false;
|
2024
|
+
return element;
|
2025
|
+
}
|
2026
|
+
}
|
2027
|
+
|
2028
|
+
Object.extend(Form.Element, Form.Element.Methods);
|
2029
|
+
var Field = Form.Element;
|
2030
|
+
var $F = Form.Element.getValue;
|
2031
|
+
|
2032
|
+
/*--------------------------------------------------------------------------*/
|
2033
|
+
|
2034
|
+
Form.Element.Serializers = {
|
2035
|
+
input: function(element) {
|
2036
|
+
switch (element.type.toLowerCase()) {
|
2037
|
+
case 'checkbox':
|
2038
|
+
case 'radio':
|
2039
|
+
return Form.Element.Serializers.inputSelector(element);
|
2040
|
+
default:
|
2041
|
+
return Form.Element.Serializers.textarea(element);
|
2042
|
+
}
|
2043
|
+
},
|
2044
|
+
|
2045
|
+
inputSelector: function(element) {
|
2046
|
+
return element.checked ? element.value : null;
|
2047
|
+
},
|
2048
|
+
|
2049
|
+
textarea: function(element) {
|
2050
|
+
return element.value;
|
2051
|
+
},
|
2052
|
+
|
2053
|
+
select: function(element) {
|
2054
|
+
return this[element.type == 'select-one' ?
|
2055
|
+
'selectOne' : 'selectMany'](element);
|
2056
|
+
},
|
2057
|
+
|
2058
|
+
selectOne: function(element) {
|
2059
|
+
var index = element.selectedIndex;
|
2060
|
+
return index >= 0 ? this.optionValue(element.options[index]) : null;
|
2061
|
+
},
|
2062
|
+
|
2063
|
+
selectMany: function(element) {
|
2064
|
+
var values, length = element.length;
|
2065
|
+
if (!length) return null;
|
2066
|
+
|
2067
|
+
for (var i = 0, values = []; i < length; i++) {
|
2068
|
+
var opt = element.options[i];
|
2069
|
+
if (opt.selected) values.push(this.optionValue(opt));
|
2070
|
+
}
|
2071
|
+
return values;
|
2072
|
+
},
|
2073
|
+
|
2074
|
+
optionValue: function(opt) {
|
2075
|
+
// extend element because hasAttribute may not be native
|
2076
|
+
return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
|
2077
|
+
}
|
2078
|
+
}
|
2079
|
+
|
2080
|
+
/*--------------------------------------------------------------------------*/
|
2081
|
+
|
2082
|
+
Abstract.TimedObserver = function() {}
|
2083
|
+
Abstract.TimedObserver.prototype = {
|
2084
|
+
initialize: function(element, frequency, callback) {
|
2085
|
+
this.frequency = frequency;
|
2086
|
+
this.element = $(element);
|
2087
|
+
this.callback = callback;
|
2088
|
+
|
2089
|
+
this.lastValue = this.getValue();
|
2090
|
+
this.registerCallback();
|
2091
|
+
},
|
2092
|
+
|
2093
|
+
registerCallback: function() {
|
2094
|
+
setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
|
2095
|
+
},
|
2096
|
+
|
2097
|
+
onTimerEvent: function() {
|
2098
|
+
var value = this.getValue();
|
2099
|
+
var changed = ('string' == typeof this.lastValue && 'string' == typeof value
|
2100
|
+
? this.lastValue != value : String(this.lastValue) != String(value));
|
2101
|
+
if (changed) {
|
2102
|
+
this.callback(this.element, value);
|
2103
|
+
this.lastValue = value;
|
2104
|
+
}
|
2105
|
+
}
|
2106
|
+
}
|
2107
|
+
|
2108
|
+
Form.Element.Observer = Class.create();
|
2109
|
+
Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
|
2110
|
+
getValue: function() {
|
2111
|
+
return Form.Element.getValue(this.element);
|
2112
|
+
}
|
2113
|
+
});
|
2114
|
+
|
2115
|
+
Form.Observer = Class.create();
|
2116
|
+
Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
|
2117
|
+
getValue: function() {
|
2118
|
+
return Form.serialize(this.element);
|
2119
|
+
}
|
2120
|
+
});
|
2121
|
+
|
2122
|
+
/*--------------------------------------------------------------------------*/
|
2123
|
+
|
2124
|
+
Abstract.EventObserver = function() {}
|
2125
|
+
Abstract.EventObserver.prototype = {
|
2126
|
+
initialize: function(element, callback) {
|
2127
|
+
this.element = $(element);
|
2128
|
+
this.callback = callback;
|
2129
|
+
|
2130
|
+
this.lastValue = this.getValue();
|
2131
|
+
if (this.element.tagName.toLowerCase() == 'form')
|
2132
|
+
this.registerFormCallbacks();
|
2133
|
+
else
|
2134
|
+
this.registerCallback(this.element);
|
2135
|
+
},
|
2136
|
+
|
2137
|
+
onElementEvent: function() {
|
2138
|
+
var value = this.getValue();
|
2139
|
+
if (this.lastValue != value) {
|
2140
|
+
this.callback(this.element, value);
|
2141
|
+
this.lastValue = value;
|
2142
|
+
}
|
2143
|
+
},
|
2144
|
+
|
2145
|
+
registerFormCallbacks: function() {
|
2146
|
+
Form.getElements(this.element).each(this.registerCallback.bind(this));
|
2147
|
+
},
|
2148
|
+
|
2149
|
+
registerCallback: function(element) {
|
2150
|
+
if (element.type) {
|
2151
|
+
switch (element.type.toLowerCase()) {
|
2152
|
+
case 'checkbox':
|
2153
|
+
case 'radio':
|
2154
|
+
Event.observe(element, 'click', this.onElementEvent.bind(this));
|
2155
|
+
break;
|
2156
|
+
default:
|
2157
|
+
Event.observe(element, 'change', this.onElementEvent.bind(this));
|
2158
|
+
break;
|
2159
|
+
}
|
2160
|
+
}
|
2161
|
+
}
|
2162
|
+
}
|
2163
|
+
|
2164
|
+
Form.Element.EventObserver = Class.create();
|
2165
|
+
Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
|
2166
|
+
getValue: function() {
|
2167
|
+
return Form.Element.getValue(this.element);
|
2168
|
+
}
|
2169
|
+
});
|
2170
|
+
|
2171
|
+
Form.EventObserver = Class.create();
|
2172
|
+
Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
|
2173
|
+
getValue: function() {
|
2174
|
+
return Form.serialize(this.element);
|
2175
|
+
}
|
2176
|
+
});
|
2177
|
+
if (!window.Event) {
|
2178
|
+
var Event = new Object();
|
2179
|
+
}
|
2180
|
+
|
2181
|
+
Object.extend(Event, {
|
2182
|
+
KEY_BACKSPACE: 8,
|
2183
|
+
KEY_TAB: 9,
|
2184
|
+
KEY_RETURN: 13,
|
2185
|
+
KEY_ESC: 27,
|
2186
|
+
KEY_LEFT: 37,
|
2187
|
+
KEY_UP: 38,
|
2188
|
+
KEY_RIGHT: 39,
|
2189
|
+
KEY_DOWN: 40,
|
2190
|
+
KEY_DELETE: 46,
|
2191
|
+
KEY_HOME: 36,
|
2192
|
+
KEY_END: 35,
|
2193
|
+
KEY_PAGEUP: 33,
|
2194
|
+
KEY_PAGEDOWN: 34,
|
2195
|
+
|
2196
|
+
element: function(event) {
|
2197
|
+
return event.target || event.srcElement;
|
2198
|
+
},
|
2199
|
+
|
2200
|
+
isLeftClick: function(event) {
|
2201
|
+
return (((event.which) && (event.which == 1)) ||
|
2202
|
+
((event.button) && (event.button == 1)));
|
2203
|
+
},
|
2204
|
+
|
2205
|
+
pointerX: function(event) {
|
2206
|
+
return event.pageX || (event.clientX +
|
2207
|
+
(document.documentElement.scrollLeft || document.body.scrollLeft));
|
2208
|
+
},
|
2209
|
+
|
2210
|
+
pointerY: function(event) {
|
2211
|
+
return event.pageY || (event.clientY +
|
2212
|
+
(document.documentElement.scrollTop || document.body.scrollTop));
|
2213
|
+
},
|
2214
|
+
|
2215
|
+
stop: function(event) {
|
2216
|
+
if (event.preventDefault) {
|
2217
|
+
event.preventDefault();
|
2218
|
+
event.stopPropagation();
|
2219
|
+
} else {
|
2220
|
+
event.returnValue = false;
|
2221
|
+
event.cancelBubble = true;
|
2222
|
+
}
|
2223
|
+
},
|
2224
|
+
|
2225
|
+
// find the first node with the given tagName, starting from the
|
2226
|
+
// node the event was triggered on; traverses the DOM upwards
|
2227
|
+
findElement: function(event, tagName) {
|
2228
|
+
var element = Event.element(event);
|
2229
|
+
while (element.parentNode && (!element.tagName ||
|
2230
|
+
(element.tagName.toUpperCase() != tagName.toUpperCase())))
|
2231
|
+
element = element.parentNode;
|
2232
|
+
return element;
|
2233
|
+
},
|
2234
|
+
|
2235
|
+
observers: false,
|
2236
|
+
|
2237
|
+
_observeAndCache: function(element, name, observer, useCapture) {
|
2238
|
+
if (!this.observers) this.observers = [];
|
2239
|
+
if (element.addEventListener) {
|
2240
|
+
this.observers.push([element, name, observer, useCapture]);
|
2241
|
+
element.addEventListener(name, observer, useCapture);
|
2242
|
+
} else if (element.attachEvent) {
|
2243
|
+
this.observers.push([element, name, observer, useCapture]);
|
2244
|
+
element.attachEvent('on' + name, observer);
|
2245
|
+
}
|
2246
|
+
},
|
2247
|
+
|
2248
|
+
unloadCache: function() {
|
2249
|
+
if (!Event.observers) return;
|
2250
|
+
for (var i = 0, length = Event.observers.length; i < length; i++) {
|
2251
|
+
Event.stopObserving.apply(this, Event.observers[i]);
|
2252
|
+
Event.observers[i][0] = null;
|
2253
|
+
}
|
2254
|
+
Event.observers = false;
|
2255
|
+
},
|
2256
|
+
|
2257
|
+
observe: function(element, name, observer, useCapture) {
|
2258
|
+
element = $(element);
|
2259
|
+
useCapture = useCapture || false;
|
2260
|
+
|
2261
|
+
if (name == 'keypress' &&
|
2262
|
+
(navigator.appVersion.match(/Konqueror|Safari|KHTML/)
|
2263
|
+
|| element.attachEvent))
|
2264
|
+
name = 'keydown';
|
2265
|
+
|
2266
|
+
Event._observeAndCache(element, name, observer, useCapture);
|
2267
|
+
},
|
2268
|
+
|
2269
|
+
stopObserving: function(element, name, observer, useCapture) {
|
2270
|
+
element = $(element);
|
2271
|
+
useCapture = useCapture || false;
|
2272
|
+
|
2273
|
+
if (name == 'keypress' &&
|
2274
|
+
(navigator.appVersion.match(/Konqueror|Safari|KHTML/)
|
2275
|
+
|| element.detachEvent))
|
2276
|
+
name = 'keydown';
|
2277
|
+
|
2278
|
+
if (element.removeEventListener) {
|
2279
|
+
element.removeEventListener(name, observer, useCapture);
|
2280
|
+
} else if (element.detachEvent) {
|
2281
|
+
try {
|
2282
|
+
element.detachEvent('on' + name, observer);
|
2283
|
+
} catch (e) {}
|
2284
|
+
}
|
2285
|
+
}
|
2286
|
+
});
|
2287
|
+
|
2288
|
+
/* prevent memory leaks in IE */
|
2289
|
+
if (navigator.appVersion.match(/\bMSIE\b/))
|
2290
|
+
Event.observe(window, 'unload', Event.unloadCache, false);
|
2291
|
+
var Position = {
|
2292
|
+
// set to true if needed, warning: firefox performance problems
|
2293
|
+
// NOT neeeded for page scrolling, only if draggable contained in
|
2294
|
+
// scrollable elements
|
2295
|
+
includeScrollOffsets: false,
|
2296
|
+
|
2297
|
+
// must be called before calling withinIncludingScrolloffset, every time the
|
2298
|
+
// page is scrolled
|
2299
|
+
prepare: function() {
|
2300
|
+
this.deltaX = window.pageXOffset
|
2301
|
+
|| document.documentElement.scrollLeft
|
2302
|
+
|| document.body.scrollLeft
|
2303
|
+
|| 0;
|
2304
|
+
this.deltaY = window.pageYOffset
|
2305
|
+
|| document.documentElement.scrollTop
|
2306
|
+
|| document.body.scrollTop
|
2307
|
+
|| 0;
|
2308
|
+
},
|
2309
|
+
|
2310
|
+
realOffset: function(element) {
|
2311
|
+
var valueT = 0, valueL = 0;
|
2312
|
+
do {
|
2313
|
+
valueT += element.scrollTop || 0;
|
2314
|
+
valueL += element.scrollLeft || 0;
|
2315
|
+
element = element.parentNode;
|
2316
|
+
} while (element);
|
2317
|
+
return [valueL, valueT];
|
2318
|
+
},
|
2319
|
+
|
2320
|
+
cumulativeOffset: function(element) {
|
2321
|
+
var valueT = 0, valueL = 0;
|
2322
|
+
do {
|
2323
|
+
valueT += element.offsetTop || 0;
|
2324
|
+
valueL += element.offsetLeft || 0;
|
2325
|
+
element = element.offsetParent;
|
2326
|
+
} while (element);
|
2327
|
+
return [valueL, valueT];
|
2328
|
+
},
|
2329
|
+
|
2330
|
+
positionedOffset: function(element) {
|
2331
|
+
var valueT = 0, valueL = 0;
|
2332
|
+
do {
|
2333
|
+
valueT += element.offsetTop || 0;
|
2334
|
+
valueL += element.offsetLeft || 0;
|
2335
|
+
element = element.offsetParent;
|
2336
|
+
if (element) {
|
2337
|
+
if(element.tagName=='BODY') break;
|
2338
|
+
var p = Element.getStyle(element, 'position');
|
2339
|
+
if (p == 'relative' || p == 'absolute') break;
|
2340
|
+
}
|
2341
|
+
} while (element);
|
2342
|
+
return [valueL, valueT];
|
2343
|
+
},
|
2344
|
+
|
2345
|
+
offsetParent: function(element) {
|
2346
|
+
if (element.offsetParent) return element.offsetParent;
|
2347
|
+
if (element == document.body) return element;
|
2348
|
+
|
2349
|
+
while ((element = element.parentNode) && element != document.body)
|
2350
|
+
if (Element.getStyle(element, 'position') != 'static')
|
2351
|
+
return element;
|
2352
|
+
|
2353
|
+
return document.body;
|
2354
|
+
},
|
2355
|
+
|
2356
|
+
// caches x/y coordinate pair to use with overlap
|
2357
|
+
within: function(element, x, y) {
|
2358
|
+
if (this.includeScrollOffsets)
|
2359
|
+
return this.withinIncludingScrolloffsets(element, x, y);
|
2360
|
+
this.xcomp = x;
|
2361
|
+
this.ycomp = y;
|
2362
|
+
this.offset = this.cumulativeOffset(element);
|
2363
|
+
|
2364
|
+
return (y >= this.offset[1] &&
|
2365
|
+
y < this.offset[1] + element.offsetHeight &&
|
2366
|
+
x >= this.offset[0] &&
|
2367
|
+
x < this.offset[0] + element.offsetWidth);
|
2368
|
+
},
|
2369
|
+
|
2370
|
+
withinIncludingScrolloffsets: function(element, x, y) {
|
2371
|
+
var offsetcache = this.realOffset(element);
|
2372
|
+
|
2373
|
+
this.xcomp = x + offsetcache[0] - this.deltaX;
|
2374
|
+
this.ycomp = y + offsetcache[1] - this.deltaY;
|
2375
|
+
this.offset = this.cumulativeOffset(element);
|
2376
|
+
|
2377
|
+
return (this.ycomp >= this.offset[1] &&
|
2378
|
+
this.ycomp < this.offset[1] + element.offsetHeight &&
|
2379
|
+
this.xcomp >= this.offset[0] &&
|
2380
|
+
this.xcomp < this.offset[0] + element.offsetWidth);
|
2381
|
+
},
|
2382
|
+
|
2383
|
+
// within must be called directly before
|
2384
|
+
overlap: function(mode, element) {
|
2385
|
+
if (!mode) return 0;
|
2386
|
+
if (mode == 'vertical')
|
2387
|
+
return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
|
2388
|
+
element.offsetHeight;
|
2389
|
+
if (mode == 'horizontal')
|
2390
|
+
return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
|
2391
|
+
element.offsetWidth;
|
2392
|
+
},
|
2393
|
+
|
2394
|
+
page: function(forElement) {
|
2395
|
+
var valueT = 0, valueL = 0;
|
2396
|
+
|
2397
|
+
var element = forElement;
|
2398
|
+
do {
|
2399
|
+
valueT += element.offsetTop || 0;
|
2400
|
+
valueL += element.offsetLeft || 0;
|
2401
|
+
|
2402
|
+
// Safari fix
|
2403
|
+
if (element.offsetParent==document.body)
|
2404
|
+
if (Element.getStyle(element,'position')=='absolute') break;
|
2405
|
+
|
2406
|
+
} while (element = element.offsetParent);
|
2407
|
+
|
2408
|
+
element = forElement;
|
2409
|
+
do {
|
2410
|
+
if (!window.opera || element.tagName=='BODY') {
|
2411
|
+
valueT -= element.scrollTop || 0;
|
2412
|
+
valueL -= element.scrollLeft || 0;
|
2413
|
+
}
|
2414
|
+
} while (element = element.parentNode);
|
2415
|
+
|
2416
|
+
return [valueL, valueT];
|
2417
|
+
},
|
2418
|
+
|
2419
|
+
clone: function(source, target) {
|
2420
|
+
var options = Object.extend({
|
2421
|
+
setLeft: true,
|
2422
|
+
setTop: true,
|
2423
|
+
setWidth: true,
|
2424
|
+
setHeight: true,
|
2425
|
+
offsetTop: 0,
|
2426
|
+
offsetLeft: 0
|
2427
|
+
}, arguments[2] || {})
|
2428
|
+
|
2429
|
+
// find page position of source
|
2430
|
+
source = $(source);
|
2431
|
+
var p = Position.page(source);
|
2432
|
+
|
2433
|
+
// find coordinate system to use
|
2434
|
+
target = $(target);
|
2435
|
+
var delta = [0, 0];
|
2436
|
+
var parent = null;
|
2437
|
+
// delta [0,0] will do fine with position: fixed elements,
|
2438
|
+
// position:absolute needs offsetParent deltas
|
2439
|
+
if (Element.getStyle(target,'position') == 'absolute') {
|
2440
|
+
parent = Position.offsetParent(target);
|
2441
|
+
delta = Position.page(parent);
|
2442
|
+
}
|
2443
|
+
|
2444
|
+
// correct by body offsets (fixes Safari)
|
2445
|
+
if (parent == document.body) {
|
2446
|
+
delta[0] -= document.body.offsetLeft;
|
2447
|
+
delta[1] -= document.body.offsetTop;
|
2448
|
+
}
|
2449
|
+
|
2450
|
+
// set position
|
2451
|
+
if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
|
2452
|
+
if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
|
2453
|
+
if(options.setWidth) target.style.width = source.offsetWidth + 'px';
|
2454
|
+
if(options.setHeight) target.style.height = source.offsetHeight + 'px';
|
2455
|
+
},
|
2456
|
+
|
2457
|
+
absolutize: function(element) {
|
2458
|
+
element = $(element);
|
2459
|
+
if (element.style.position == 'absolute') return;
|
2460
|
+
Position.prepare();
|
2461
|
+
|
2462
|
+
var offsets = Position.positionedOffset(element);
|
2463
|
+
var top = offsets[1];
|
2464
|
+
var left = offsets[0];
|
2465
|
+
var width = element.clientWidth;
|
2466
|
+
var height = element.clientHeight;
|
2467
|
+
|
2468
|
+
element._originalLeft = left - parseFloat(element.style.left || 0);
|
2469
|
+
element._originalTop = top - parseFloat(element.style.top || 0);
|
2470
|
+
element._originalWidth = element.style.width;
|
2471
|
+
element._originalHeight = element.style.height;
|
2472
|
+
|
2473
|
+
element.style.position = 'absolute';
|
2474
|
+
element.style.top = top + 'px';
|
2475
|
+
element.style.left = left + 'px';
|
2476
|
+
element.style.width = width + 'px';
|
2477
|
+
element.style.height = height + 'px';
|
2478
|
+
},
|
2479
|
+
|
2480
|
+
relativize: function(element) {
|
2481
|
+
element = $(element);
|
2482
|
+
if (element.style.position == 'relative') return;
|
2483
|
+
Position.prepare();
|
2484
|
+
|
2485
|
+
element.style.position = 'relative';
|
2486
|
+
var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
|
2487
|
+
var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
|
2488
|
+
|
2489
|
+
element.style.top = top + 'px';
|
2490
|
+
element.style.left = left + 'px';
|
2491
|
+
element.style.height = element._originalHeight;
|
2492
|
+
element.style.width = element._originalWidth;
|
2493
|
+
}
|
2494
|
+
}
|
2495
|
+
|
2496
|
+
// Safari returns margins on body which is incorrect if the child is absolutely
|
2497
|
+
// positioned. For performance reasons, redefine Position.cumulativeOffset for
|
2498
|
+
// KHTML/WebKit only.
|
2499
|
+
if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
|
2500
|
+
Position.cumulativeOffset = function(element) {
|
2501
|
+
var valueT = 0, valueL = 0;
|
2502
|
+
do {
|
2503
|
+
valueT += element.offsetTop || 0;
|
2504
|
+
valueL += element.offsetLeft || 0;
|
2505
|
+
if (element.offsetParent == document.body)
|
2506
|
+
if (Element.getStyle(element, 'position') == 'absolute') break;
|
2507
|
+
|
2508
|
+
element = element.offsetParent;
|
2509
|
+
} while (element);
|
2510
|
+
|
2511
|
+
return [valueL, valueT];
|
2512
|
+
}
|
2513
|
+
}
|
2514
|
+
|
2515
|
+
Element.addMethods();
|