ruby-openid 2.2.3 → 2.3.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +11 -0
- data/README.md +1 -2
- data/examples/rails_openid/Gemfile +41 -0
- data/examples/rails_openid/README.rdoc +261 -0
- data/examples/rails_openid/Rakefile +4 -7
- data/examples/rails_openid/app/assets/images/rails.png +0 -0
- data/examples/rails_openid/app/assets/javascripts/application.js +15 -0
- data/examples/rails_openid/app/assets/stylesheets/application.css +13 -0
- data/examples/rails_openid/app/controllers/application_controller.rb +3 -0
- data/examples/rails_openid/app/controllers/consumer_controller.rb +1 -0
- data/examples/rails_openid/app/helpers/application_helper.rb +0 -1
- data/examples/rails_openid/app/views/consumer/{index.rhtml → index.html.erb} +0 -0
- data/examples/rails_openid/app/views/layouts/{server.rhtml → server.html.erb} +4 -2
- data/examples/rails_openid/app/views/login/{index.rhtml → index.html.erb} +0 -0
- data/examples/rails_openid/app/views/server/{decide.rhtml → decide.html.erb} +1 -0
- data/examples/rails_openid/config.ru +4 -0
- data/examples/rails_openid/config/application.rb +62 -0
- data/examples/rails_openid/config/boot.rb +4 -17
- data/examples/rails_openid/config/database.yml +15 -64
- data/examples/rails_openid/config/environment.rb +4 -53
- data/examples/rails_openid/config/environments/development.rb +32 -14
- data/examples/rails_openid/config/environments/production.rb +61 -13
- data/examples/rails_openid/config/environments/test.rb +33 -15
- data/examples/rails_openid/config/initializers/backtrace_silencers.rb +7 -0
- data/examples/rails_openid/config/initializers/inflections.rb +15 -0
- data/examples/rails_openid/config/initializers/mime_types.rb +5 -0
- data/examples/rails_openid/config/initializers/rails_root.rb +1 -0
- data/examples/rails_openid/config/initializers/secret_token.rb +7 -0
- data/examples/rails_openid/config/initializers/session_store.rb +8 -0
- data/examples/rails_openid/config/initializers/wrap_parameters.rb +14 -0
- data/examples/rails_openid/config/locales/en.yml +5 -0
- data/examples/rails_openid/config/routes.rb +65 -18
- data/examples/rails_openid/db/development.sqlite3 +0 -0
- data/examples/rails_openid/db/seeds.rb +7 -0
- data/examples/rails_openid/doc/README_FOR_APP +1 -1
- data/examples/rails_openid/log/development.log +2052 -0
- data/examples/rails_openid/public/404.html +23 -5
- data/examples/rails_openid/public/422.html +26 -0
- data/examples/rails_openid/public/500.html +22 -5
- data/examples/rails_openid/public/javascripts/application.js +2 -0
- data/examples/rails_openid/public/javascripts/controls.js +586 -373
- data/examples/rails_openid/public/javascripts/dragdrop.js +575 -186
- data/examples/rails_openid/public/javascripts/effects.js +763 -489
- data/examples/rails_openid/public/javascripts/prototype.js +3420 -885
- data/examples/rails_openid/public/robots.txt +5 -1
- data/examples/rails_openid/script/rails +6 -0
- data/examples/rails_openid/test/performance/browsing_test.rb +12 -0
- data/examples/rails_openid/test/test_helper.rb +7 -22
- data/lib/openid/association.rb +1 -1
- data/lib/openid/consumer/checkid_request.rb +1 -1
- data/lib/openid/consumer/discovery.rb +1 -1
- data/lib/openid/consumer/html_parse.rb +3 -1
- data/lib/openid/consumer/idres.rb +1 -1
- data/lib/openid/extensions/ax.rb +2 -3
- data/lib/openid/extensions/ui.rb +3 -3
- data/lib/openid/extras.rb +2 -2
- data/lib/openid/server.rb +2 -2
- data/lib/openid/store/memory.rb +1 -2
- data/lib/openid/store/nonce.rb +1 -1
- data/lib/openid/trustroot.rb +1 -1
- data/lib/openid/util.rb +2 -2
- data/lib/openid/version.rb +1 -1
- data/lib/openid/yadis/xrds.rb +1 -1
- data/test/test_accept.rb +20 -21
- data/test/test_association.rb +4 -8
- data/test/test_associationmanager.rb +1 -1
- data/test/test_ax.rb +0 -1
- data/test/test_checkid_request.rb +7 -8
- data/test/test_dh.rb +1 -1
- data/test/test_discover.rb +7 -8
- data/test/test_extension.rb +1 -1
- data/test/test_fetchers.rb +7 -11
- data/test/test_filters.rb +0 -4
- data/test/test_idres.rb +5 -5
- data/test/test_kvpost.rb +0 -1
- data/test/test_message.rb +10 -11
- data/test/test_parsehtml.rb +0 -1
- data/test/test_server.rb +11 -30
- data/test/test_stores.rb +2 -2
- data/test/test_trustroot.rb +1 -1
- data/test/test_urinorm.rb +1 -1
- data/test/test_xrds.rb +1 -1
- data/test/test_yadis_discovery.rb +0 -2
- metadata +34 -33
- data/examples/rails_openid/app/controllers/application.rb +0 -4
- data/examples/rails_openid/script/about +0 -3
- data/examples/rails_openid/script/breakpointer +0 -3
- data/examples/rails_openid/script/console +0 -3
- data/examples/rails_openid/script/destroy +0 -3
- data/examples/rails_openid/script/generate +0 -3
- data/examples/rails_openid/script/performance/benchmarker +0 -3
- data/examples/rails_openid/script/performance/profiler +0 -3
- data/examples/rails_openid/script/plugin +0 -3
- data/examples/rails_openid/script/process/reaper +0 -3
- data/examples/rails_openid/script/process/spawner +0 -3
- data/examples/rails_openid/script/process/spinner +0 -3
- data/examples/rails_openid/script/runner +0 -3
- data/examples/rails_openid/script/server +0 -3
|
@@ -1,8 +1,26 @@
|
|
|
1
|
-
<!DOCTYPE
|
|
2
|
-
"http://www.w3.org/TR/html4/loose.dtd">
|
|
1
|
+
<!DOCTYPE html>
|
|
3
2
|
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>The page you were looking for doesn't exist (404)</title>
|
|
5
|
+
<style type="text/css">
|
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
|
7
|
+
div.dialog {
|
|
8
|
+
width: 25em;
|
|
9
|
+
padding: 0 4em;
|
|
10
|
+
margin: 4em auto 0 auto;
|
|
11
|
+
border: 1px solid #ccc;
|
|
12
|
+
border-right-color: #999;
|
|
13
|
+
border-bottom-color: #999;
|
|
14
|
+
}
|
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
|
16
|
+
</style>
|
|
17
|
+
</head>
|
|
18
|
+
|
|
4
19
|
<body>
|
|
5
|
-
|
|
6
|
-
<
|
|
20
|
+
<!-- This file lives in public/404.html -->
|
|
21
|
+
<div class="dialog">
|
|
22
|
+
<h1>The page you were looking for doesn't exist.</h1>
|
|
23
|
+
<p>You may have mistyped the address or the page may have moved.</p>
|
|
24
|
+
</div>
|
|
7
25
|
</body>
|
|
8
|
-
</html>
|
|
26
|
+
</html>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>The change you wanted was rejected (422)</title>
|
|
5
|
+
<style type="text/css">
|
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
|
7
|
+
div.dialog {
|
|
8
|
+
width: 25em;
|
|
9
|
+
padding: 0 4em;
|
|
10
|
+
margin: 4em auto 0 auto;
|
|
11
|
+
border: 1px solid #ccc;
|
|
12
|
+
border-right-color: #999;
|
|
13
|
+
border-bottom-color: #999;
|
|
14
|
+
}
|
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
|
16
|
+
</style>
|
|
17
|
+
</head>
|
|
18
|
+
|
|
19
|
+
<body>
|
|
20
|
+
<!-- This file lives in public/422.html -->
|
|
21
|
+
<div class="dialog">
|
|
22
|
+
<h1>The change you wanted was rejected.</h1>
|
|
23
|
+
<p>Maybe you tried to change something you didn't have access to.</p>
|
|
24
|
+
</div>
|
|
25
|
+
</body>
|
|
26
|
+
</html>
|
|
@@ -1,8 +1,25 @@
|
|
|
1
|
-
<!DOCTYPE
|
|
2
|
-
"http://www.w3.org/TR/html4/loose.dtd">
|
|
1
|
+
<!DOCTYPE html>
|
|
3
2
|
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>We're sorry, but something went wrong (500)</title>
|
|
5
|
+
<style type="text/css">
|
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
|
7
|
+
div.dialog {
|
|
8
|
+
width: 25em;
|
|
9
|
+
padding: 0 4em;
|
|
10
|
+
margin: 4em auto 0 auto;
|
|
11
|
+
border: 1px solid #ccc;
|
|
12
|
+
border-right-color: #999;
|
|
13
|
+
border-bottom-color: #999;
|
|
14
|
+
}
|
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
|
16
|
+
</style>
|
|
17
|
+
</head>
|
|
18
|
+
|
|
4
19
|
<body>
|
|
5
|
-
|
|
6
|
-
<
|
|
20
|
+
<!-- This file lives in public/500.html -->
|
|
21
|
+
<div class="dialog">
|
|
22
|
+
<h1>We're sorry, but something went wrong.</h1>
|
|
23
|
+
</div>
|
|
7
24
|
</body>
|
|
8
|
-
</html>
|
|
25
|
+
</html>
|
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
|
2
|
-
// (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
|
|
3
|
-
// (c) 2005 Jon Tirsen (http://www.tirsen.com)
|
|
1
|
+
// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
|
2
|
+
// (c) 2005-2008 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
|
|
3
|
+
// (c) 2005-2008 Jon Tirsen (http://www.tirsen.com)
|
|
4
4
|
// Contributors:
|
|
5
5
|
// Richard Livsey
|
|
6
6
|
// Rahul Bhargava
|
|
7
7
|
// Rob Wills
|
|
8
|
-
//
|
|
9
|
-
//
|
|
8
|
+
//
|
|
9
|
+
// script.aculo.us is freely distributable under the terms of an MIT-style license.
|
|
10
|
+
// For details, see the script.aculo.us web site: http://script.aculo.us/
|
|
10
11
|
|
|
11
|
-
// Autocompleter.Base handles all the autocompletion functionality
|
|
12
|
+
// Autocompleter.Base handles all the autocompletion functionality
|
|
12
13
|
// that's independent of the data source for autocompletion. This
|
|
13
14
|
// includes drawing the autocompletion menu, observing keyboard
|
|
14
15
|
// and mouse events, and similar.
|
|
15
16
|
//
|
|
16
|
-
// Specific autocompleters need to provide, at the very least,
|
|
17
|
+
// Specific autocompleters need to provide, at the very least,
|
|
17
18
|
// a getUpdatedChoices function that will be invoked every time
|
|
18
|
-
// the text inside the monitored textbox changes. This method
|
|
19
|
+
// the text inside the monitored textbox changes. This method
|
|
19
20
|
// should get the text for which to provide autocompletion by
|
|
20
21
|
// invoking this.getToken(), NOT by directly accessing
|
|
21
22
|
// this.element.value. This is to allow incremental tokenized
|
|
@@ -29,62 +30,71 @@
|
|
|
29
30
|
// will incrementally autocomplete with a comma as the token.
|
|
30
31
|
// Additionally, ',' in the above example can be replaced with
|
|
31
32
|
// a token array, e.g. { tokens: [',', '\n'] } which
|
|
32
|
-
// enables autocompletion on multiple tokens. This is most
|
|
33
|
-
// useful when one of the tokens is \n (a newline), as it
|
|
33
|
+
// enables autocompletion on multiple tokens. This is most
|
|
34
|
+
// useful when one of the tokens is \n (a newline), as it
|
|
34
35
|
// allows smart autocompletion after linebreaks.
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
if(typeof Effect == 'undefined')
|
|
38
|
+
throw("controls.js requires including script.aculo.us' effects.js library");
|
|
39
|
+
|
|
40
|
+
var Autocompleter = { };
|
|
41
|
+
Autocompleter.Base = Class.create({
|
|
39
42
|
baseInitialize: function(element, update, options) {
|
|
40
|
-
|
|
41
|
-
this.
|
|
42
|
-
this.
|
|
43
|
-
this.
|
|
44
|
-
this.
|
|
45
|
-
this.
|
|
43
|
+
element = $(element);
|
|
44
|
+
this.element = element;
|
|
45
|
+
this.update = $(update);
|
|
46
|
+
this.hasFocus = false;
|
|
47
|
+
this.changed = false;
|
|
48
|
+
this.active = false;
|
|
49
|
+
this.index = 0;
|
|
46
50
|
this.entryCount = 0;
|
|
51
|
+
this.oldElementValue = this.element.value;
|
|
47
52
|
|
|
48
|
-
if
|
|
53
|
+
if(this.setOptions)
|
|
49
54
|
this.setOptions(options);
|
|
50
55
|
else
|
|
51
|
-
this.options = options || {};
|
|
56
|
+
this.options = options || { };
|
|
52
57
|
|
|
53
58
|
this.options.paramName = this.options.paramName || this.element.name;
|
|
54
59
|
this.options.tokens = this.options.tokens || [];
|
|
55
60
|
this.options.frequency = this.options.frequency || 0.4;
|
|
56
61
|
this.options.minChars = this.options.minChars || 1;
|
|
57
|
-
this.options.onShow = this.options.onShow ||
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
this.options.onShow = this.options.onShow ||
|
|
63
|
+
function(element, update){
|
|
64
|
+
if(!update.style.position || update.style.position=='absolute') {
|
|
65
|
+
update.style.position = 'absolute';
|
|
66
|
+
Position.clone(element, update, {
|
|
67
|
+
setHeight: false,
|
|
68
|
+
offsetTop: element.offsetHeight
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
Effect.Appear(update,{duration:0.15});
|
|
72
|
+
};
|
|
73
|
+
this.options.onHide = this.options.onHide ||
|
|
74
|
+
function(element, update){ new Effect.Fade(update,{duration:0.15}) };
|
|
67
75
|
|
|
68
|
-
if
|
|
76
|
+
if(typeof(this.options.tokens) == 'string')
|
|
69
77
|
this.options.tokens = new Array(this.options.tokens);
|
|
78
|
+
// Force carriage returns as token delimiters anyway
|
|
79
|
+
if (!this.options.tokens.include('\n'))
|
|
80
|
+
this.options.tokens.push('\n');
|
|
70
81
|
|
|
71
82
|
this.observer = null;
|
|
72
|
-
|
|
83
|
+
|
|
73
84
|
this.element.setAttribute('autocomplete','off');
|
|
74
85
|
|
|
75
86
|
Element.hide(this.update);
|
|
76
87
|
|
|
77
|
-
Event.observe(this.element,
|
|
78
|
-
Event.observe(this.element,
|
|
88
|
+
Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
|
|
89
|
+
Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));
|
|
79
90
|
},
|
|
80
91
|
|
|
81
92
|
show: function() {
|
|
82
93
|
if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
|
|
83
|
-
if(!this.iefix &&
|
|
84
|
-
(
|
|
85
|
-
(navigator.userAgent.indexOf('Opera')<0) &&
|
|
94
|
+
if(!this.iefix &&
|
|
95
|
+
(Prototype.Browser.IE) &&
|
|
86
96
|
(Element.getStyle(this.update, 'position')=='absolute')) {
|
|
87
|
-
new Insertion.After(this.update,
|
|
97
|
+
new Insertion.After(this.update,
|
|
88
98
|
'<iframe id="' + this.update.id + '_iefix" '+
|
|
89
99
|
'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
|
|
90
100
|
'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
|
|
@@ -92,9 +102,9 @@ Autocompleter.Base.prototype = {
|
|
|
92
102
|
}
|
|
93
103
|
if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
|
|
94
104
|
},
|
|
95
|
-
|
|
105
|
+
|
|
96
106
|
fixIEOverlapping: function() {
|
|
97
|
-
Position.clone(this.update, this.iefix);
|
|
107
|
+
Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
|
|
98
108
|
this.iefix.style.zIndex = 1;
|
|
99
109
|
this.update.style.zIndex = 2;
|
|
100
110
|
Element.show(this.iefix);
|
|
@@ -132,58 +142,63 @@ Autocompleter.Base.prototype = {
|
|
|
132
142
|
case Event.KEY_UP:
|
|
133
143
|
this.markPrevious();
|
|
134
144
|
this.render();
|
|
135
|
-
|
|
145
|
+
Event.stop(event);
|
|
136
146
|
return;
|
|
137
147
|
case Event.KEY_DOWN:
|
|
138
148
|
this.markNext();
|
|
139
149
|
this.render();
|
|
140
|
-
|
|
150
|
+
Event.stop(event);
|
|
141
151
|
return;
|
|
142
152
|
}
|
|
143
|
-
else
|
|
144
|
-
|
|
145
|
-
|
|
153
|
+
else
|
|
154
|
+
if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
|
|
155
|
+
(Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;
|
|
146
156
|
|
|
147
157
|
this.changed = true;
|
|
148
158
|
this.hasFocus = true;
|
|
149
159
|
|
|
150
160
|
if(this.observer) clearTimeout(this.observer);
|
|
151
|
-
this.observer =
|
|
161
|
+
this.observer =
|
|
152
162
|
setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
|
|
153
163
|
},
|
|
154
164
|
|
|
165
|
+
activate: function() {
|
|
166
|
+
this.changed = false;
|
|
167
|
+
this.hasFocus = true;
|
|
168
|
+
this.getUpdatedChoices();
|
|
169
|
+
},
|
|
170
|
+
|
|
155
171
|
onHover: function(event) {
|
|
156
172
|
var element = Event.findElement(event, 'LI');
|
|
157
|
-
if(this.index != element.autocompleteIndex)
|
|
173
|
+
if(this.index != element.autocompleteIndex)
|
|
158
174
|
{
|
|
159
175
|
this.index = element.autocompleteIndex;
|
|
160
176
|
this.render();
|
|
161
177
|
}
|
|
162
178
|
Event.stop(event);
|
|
163
179
|
},
|
|
164
|
-
|
|
180
|
+
|
|
165
181
|
onClick: function(event) {
|
|
166
182
|
var element = Event.findElement(event, 'LI');
|
|
167
183
|
this.index = element.autocompleteIndex;
|
|
168
184
|
this.selectEntry();
|
|
169
185
|
this.hide();
|
|
170
186
|
},
|
|
171
|
-
|
|
187
|
+
|
|
172
188
|
onBlur: function(event) {
|
|
173
189
|
// needed to make click events working
|
|
174
190
|
setTimeout(this.hide.bind(this), 250);
|
|
175
191
|
this.hasFocus = false;
|
|
176
|
-
this.active = false;
|
|
177
|
-
},
|
|
178
|
-
|
|
192
|
+
this.active = false;
|
|
193
|
+
},
|
|
194
|
+
|
|
179
195
|
render: function() {
|
|
180
196
|
if(this.entryCount > 0) {
|
|
181
197
|
for (var i = 0; i < this.entryCount; i++)
|
|
182
|
-
this.index==i ?
|
|
183
|
-
Element.addClassName(this.getEntry(i),"selected") :
|
|
198
|
+
this.index==i ?
|
|
199
|
+
Element.addClassName(this.getEntry(i),"selected") :
|
|
184
200
|
Element.removeClassName(this.getEntry(i),"selected");
|
|
185
|
-
|
|
186
|
-
if(this.hasFocus) {
|
|
201
|
+
if(this.hasFocus) {
|
|
187
202
|
this.show();
|
|
188
203
|
this.active = true;
|
|
189
204
|
}
|
|
@@ -192,25 +207,27 @@ Autocompleter.Base.prototype = {
|
|
|
192
207
|
this.hide();
|
|
193
208
|
}
|
|
194
209
|
},
|
|
195
|
-
|
|
210
|
+
|
|
196
211
|
markPrevious: function() {
|
|
197
|
-
if(this.index > 0) this.index
|
|
212
|
+
if(this.index > 0) this.index--;
|
|
198
213
|
else this.index = this.entryCount-1;
|
|
214
|
+
this.getEntry(this.index).scrollIntoView(true);
|
|
199
215
|
},
|
|
200
|
-
|
|
216
|
+
|
|
201
217
|
markNext: function() {
|
|
202
|
-
if(this.index < this.entryCount-1) this.index
|
|
218
|
+
if(this.index < this.entryCount-1) this.index++;
|
|
203
219
|
else this.index = 0;
|
|
220
|
+
this.getEntry(this.index).scrollIntoView(false);
|
|
204
221
|
},
|
|
205
|
-
|
|
222
|
+
|
|
206
223
|
getEntry: function(index) {
|
|
207
224
|
return this.update.firstChild.childNodes[index];
|
|
208
225
|
},
|
|
209
|
-
|
|
226
|
+
|
|
210
227
|
getCurrentEntry: function() {
|
|
211
228
|
return this.getEntry(this.index);
|
|
212
229
|
},
|
|
213
|
-
|
|
230
|
+
|
|
214
231
|
selectEntry: function() {
|
|
215
232
|
this.active = false;
|
|
216
233
|
this.updateElement(this.getCurrentEntry());
|
|
@@ -221,20 +238,26 @@ Autocompleter.Base.prototype = {
|
|
|
221
238
|
this.options.updateElement(selectedElement);
|
|
222
239
|
return;
|
|
223
240
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
241
|
+
var value = '';
|
|
242
|
+
if (this.options.select) {
|
|
243
|
+
var nodes = $(selectedElement).select('.' + this.options.select) || [];
|
|
244
|
+
if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
|
|
245
|
+
} else
|
|
246
|
+
value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
|
|
247
|
+
|
|
248
|
+
var bounds = this.getTokenBounds();
|
|
249
|
+
if (bounds[0] != -1) {
|
|
250
|
+
var newValue = this.element.value.substr(0, bounds[0]);
|
|
251
|
+
var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/);
|
|
230
252
|
if (whitespace)
|
|
231
253
|
newValue += whitespace[0];
|
|
232
|
-
this.element.value = newValue + value;
|
|
254
|
+
this.element.value = newValue + value + this.element.value.substr(bounds[1]);
|
|
233
255
|
} else {
|
|
234
256
|
this.element.value = value;
|
|
235
257
|
}
|
|
258
|
+
this.oldElementValue = this.element.value;
|
|
236
259
|
this.element.focus();
|
|
237
|
-
|
|
260
|
+
|
|
238
261
|
if (this.options.afterUpdateElement)
|
|
239
262
|
this.options.afterUpdateElement(this.element, selectedElement);
|
|
240
263
|
},
|
|
@@ -243,24 +266,29 @@ Autocompleter.Base.prototype = {
|
|
|
243
266
|
if(!this.changed && this.hasFocus) {
|
|
244
267
|
this.update.innerHTML = choices;
|
|
245
268
|
Element.cleanWhitespace(this.update);
|
|
246
|
-
Element.cleanWhitespace(this.update.
|
|
269
|
+
Element.cleanWhitespace(this.update.down());
|
|
247
270
|
|
|
248
|
-
if(this.update.firstChild && this.update.
|
|
249
|
-
this.entryCount =
|
|
250
|
-
this.update.
|
|
271
|
+
if(this.update.firstChild && this.update.down().childNodes) {
|
|
272
|
+
this.entryCount =
|
|
273
|
+
this.update.down().childNodes.length;
|
|
251
274
|
for (var i = 0; i < this.entryCount; i++) {
|
|
252
275
|
var entry = this.getEntry(i);
|
|
253
276
|
entry.autocompleteIndex = i;
|
|
254
277
|
this.addObservers(entry);
|
|
255
278
|
}
|
|
256
|
-
} else {
|
|
279
|
+
} else {
|
|
257
280
|
this.entryCount = 0;
|
|
258
281
|
}
|
|
259
282
|
|
|
260
283
|
this.stopIndicator();
|
|
261
|
-
|
|
262
284
|
this.index = 0;
|
|
263
|
-
|
|
285
|
+
|
|
286
|
+
if(this.entryCount==1 && this.options.autoSelect) {
|
|
287
|
+
this.selectEntry();
|
|
288
|
+
this.hide();
|
|
289
|
+
} else {
|
|
290
|
+
this.render();
|
|
291
|
+
}
|
|
264
292
|
}
|
|
265
293
|
},
|
|
266
294
|
|
|
@@ -270,42 +298,51 @@ Autocompleter.Base.prototype = {
|
|
|
270
298
|
},
|
|
271
299
|
|
|
272
300
|
onObserverEvent: function() {
|
|
273
|
-
this.changed = false;
|
|
301
|
+
this.changed = false;
|
|
302
|
+
this.tokenBounds = null;
|
|
274
303
|
if(this.getToken().length>=this.options.minChars) {
|
|
275
|
-
this.startIndicator();
|
|
276
304
|
this.getUpdatedChoices();
|
|
277
305
|
} else {
|
|
278
306
|
this.active = false;
|
|
279
307
|
this.hide();
|
|
280
308
|
}
|
|
309
|
+
this.oldElementValue = this.element.value;
|
|
281
310
|
},
|
|
282
311
|
|
|
283
312
|
getToken: function() {
|
|
284
|
-
var
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
var
|
|
295
|
-
|
|
296
|
-
for (var
|
|
297
|
-
|
|
298
|
-
if (
|
|
299
|
-
|
|
313
|
+
var bounds = this.getTokenBounds();
|
|
314
|
+
return this.element.value.substring(bounds[0], bounds[1]).strip();
|
|
315
|
+
},
|
|
316
|
+
|
|
317
|
+
getTokenBounds: function() {
|
|
318
|
+
if (null != this.tokenBounds) return this.tokenBounds;
|
|
319
|
+
var value = this.element.value;
|
|
320
|
+
if (value.strip().empty()) return [-1, 0];
|
|
321
|
+
var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue);
|
|
322
|
+
var offset = (diff == this.oldElementValue.length ? 1 : 0);
|
|
323
|
+
var prevTokenPos = -1, nextTokenPos = value.length;
|
|
324
|
+
var tp;
|
|
325
|
+
for (var index = 0, l = this.options.tokens.length; index < l; ++index) {
|
|
326
|
+
tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
|
|
327
|
+
if (tp > prevTokenPos) prevTokenPos = tp;
|
|
328
|
+
tp = value.indexOf(this.options.tokens[index], diff + offset);
|
|
329
|
+
if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
|
|
300
330
|
}
|
|
301
|
-
return
|
|
331
|
+
return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
|
|
302
332
|
}
|
|
303
|
-
}
|
|
333
|
+
});
|
|
304
334
|
|
|
305
|
-
|
|
306
|
-
|
|
335
|
+
Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) {
|
|
336
|
+
var boundary = Math.min(newS.length, oldS.length);
|
|
337
|
+
for (var index = 0; index < boundary; ++index)
|
|
338
|
+
if (newS[index] != oldS[index])
|
|
339
|
+
return index;
|
|
340
|
+
return boundary;
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
Ajax.Autocompleter = Class.create(Autocompleter.Base, {
|
|
307
344
|
initialize: function(element, update, url, options) {
|
|
308
|
-
|
|
345
|
+
this.baseInitialize(element, update, options);
|
|
309
346
|
this.options.asynchronous = true;
|
|
310
347
|
this.options.onComplete = this.onComplete.bind(this);
|
|
311
348
|
this.options.defaultParams = this.options.parameters || null;
|
|
@@ -313,13 +350,15 @@ Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.pro
|
|
|
313
350
|
},
|
|
314
351
|
|
|
315
352
|
getUpdatedChoices: function() {
|
|
316
|
-
|
|
353
|
+
this.startIndicator();
|
|
354
|
+
|
|
355
|
+
var entry = encodeURIComponent(this.options.paramName) + '=' +
|
|
317
356
|
encodeURIComponent(this.getToken());
|
|
318
357
|
|
|
319
358
|
this.options.parameters = this.options.callback ?
|
|
320
359
|
this.options.callback(this.element, entry) : entry;
|
|
321
360
|
|
|
322
|
-
if(this.options.defaultParams)
|
|
361
|
+
if(this.options.defaultParams)
|
|
323
362
|
this.options.parameters += '&' + this.options.defaultParams;
|
|
324
363
|
|
|
325
364
|
new Ajax.Request(this.url, this.options);
|
|
@@ -328,7 +367,6 @@ Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.pro
|
|
|
328
367
|
onComplete: function(request) {
|
|
329
368
|
this.updateChoices(request.responseText);
|
|
330
369
|
}
|
|
331
|
-
|
|
332
370
|
});
|
|
333
371
|
|
|
334
372
|
// The local array autocompleter. Used when you'd prefer to
|
|
@@ -344,7 +382,7 @@ Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.pro
|
|
|
344
382
|
// - choices - How many autocompletion choices to offer
|
|
345
383
|
//
|
|
346
384
|
// - partialSearch - If false, the autocompleter will match entered
|
|
347
|
-
// text only at the beginning of strings in the
|
|
385
|
+
// text only at the beginning of strings in the
|
|
348
386
|
// autocomplete array. Defaults to true, which will
|
|
349
387
|
// match text at the beginning of any *word* in the
|
|
350
388
|
// strings in the autocomplete array. If you want to
|
|
@@ -361,13 +399,12 @@ Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.pro
|
|
|
361
399
|
// - ignoreCase - Whether to ignore case when autocompleting.
|
|
362
400
|
// Defaults to true.
|
|
363
401
|
//
|
|
364
|
-
// It's possible to pass in a custom function as the 'selector'
|
|
402
|
+
// It's possible to pass in a custom function as the 'selector'
|
|
365
403
|
// option, if you prefer to write your own autocompletion logic.
|
|
366
404
|
// In that case, the other options above will not apply unless
|
|
367
405
|
// you support them.
|
|
368
406
|
|
|
369
|
-
Autocompleter.Local = Class.create(
|
|
370
|
-
Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
|
|
407
|
+
Autocompleter.Local = Class.create(Autocompleter.Base, {
|
|
371
408
|
initialize: function(element, update, array, options) {
|
|
372
409
|
this.baseInitialize(element, update, options);
|
|
373
410
|
this.options.array = array;
|
|
@@ -390,20 +427,20 @@ Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
|
|
|
390
427
|
var entry = instance.getToken();
|
|
391
428
|
var count = 0;
|
|
392
429
|
|
|
393
|
-
for (var i = 0; i < instance.options.array.length &&
|
|
394
|
-
ret.length < instance.options.choices ; i++) {
|
|
430
|
+
for (var i = 0; i < instance.options.array.length &&
|
|
431
|
+
ret.length < instance.options.choices ; i++) {
|
|
395
432
|
|
|
396
433
|
var elem = instance.options.array[i];
|
|
397
|
-
var foundPos = instance.options.ignoreCase ?
|
|
398
|
-
elem.toLowerCase().indexOf(entry.toLowerCase()) :
|
|
434
|
+
var foundPos = instance.options.ignoreCase ?
|
|
435
|
+
elem.toLowerCase().indexOf(entry.toLowerCase()) :
|
|
399
436
|
elem.indexOf(entry);
|
|
400
437
|
|
|
401
438
|
while (foundPos != -1) {
|
|
402
|
-
if (foundPos == 0 && elem.length != entry.length) {
|
|
403
|
-
ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
|
|
439
|
+
if (foundPos == 0 && elem.length != entry.length) {
|
|
440
|
+
ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
|
|
404
441
|
elem.substr(entry.length) + "</li>");
|
|
405
442
|
break;
|
|
406
|
-
} else if (entry.length >= instance.options.partialChars &&
|
|
443
|
+
} else if (entry.length >= instance.options.partialChars &&
|
|
407
444
|
instance.options.partialSearch && foundPos != -1) {
|
|
408
445
|
if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
|
|
409
446
|
partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
|
|
@@ -413,23 +450,22 @@ Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
|
|
|
413
450
|
}
|
|
414
451
|
}
|
|
415
452
|
|
|
416
|
-
foundPos = instance.options.ignoreCase ?
|
|
417
|
-
elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
|
|
453
|
+
foundPos = instance.options.ignoreCase ?
|
|
454
|
+
elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
|
|
418
455
|
elem.indexOf(entry, foundPos + 1);
|
|
419
456
|
|
|
420
457
|
}
|
|
421
458
|
}
|
|
422
459
|
if (partial.length)
|
|
423
|
-
ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
|
|
460
|
+
ret = ret.concat(partial.slice(0, instance.options.choices - ret.length));
|
|
424
461
|
return "<ul>" + ret.join('') + "</ul>";
|
|
425
462
|
}
|
|
426
|
-
}, options || {});
|
|
463
|
+
}, options || { });
|
|
427
464
|
}
|
|
428
465
|
});
|
|
429
466
|
|
|
430
|
-
// AJAX in-place editor
|
|
431
|
-
//
|
|
432
|
-
// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor
|
|
467
|
+
// AJAX in-place editor and collection editor
|
|
468
|
+
// Full rewrite by Christophe Porteneuve <tdd@tddsworld.com> (April 2007).
|
|
433
469
|
|
|
434
470
|
// Use this if you notice weird scrolling problems on some browsers,
|
|
435
471
|
// the DOM might be a bit confused when this gets called so do this
|
|
@@ -438,303 +474,480 @@ Field.scrollFreeActivate = function(field) {
|
|
|
438
474
|
setTimeout(function() {
|
|
439
475
|
Field.activate(field);
|
|
440
476
|
}, 1);
|
|
441
|
-
}
|
|
477
|
+
};
|
|
442
478
|
|
|
443
|
-
Ajax.InPlaceEditor = Class.create(
|
|
444
|
-
Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99";
|
|
445
|
-
Ajax.InPlaceEditor.prototype = {
|
|
479
|
+
Ajax.InPlaceEditor = Class.create({
|
|
446
480
|
initialize: function(element, url, options) {
|
|
447
481
|
this.url = url;
|
|
448
|
-
this.element = $(element);
|
|
449
|
-
|
|
450
|
-
this.
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
onComplete: function(transport, element) {
|
|
458
|
-
new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
|
|
459
|
-
},
|
|
460
|
-
onFailure: function(transport) {
|
|
461
|
-
alert("Error communicating with the server: " + transport.responseText.stripTags());
|
|
462
|
-
},
|
|
463
|
-
callback: function(form) {
|
|
464
|
-
return Form.serialize(form);
|
|
465
|
-
},
|
|
466
|
-
handleLineBreaks: true,
|
|
467
|
-
loadingText: 'Loading...',
|
|
468
|
-
savingClassName: 'inplaceeditor-saving',
|
|
469
|
-
loadingClassName: 'inplaceeditor-loading',
|
|
470
|
-
formClassName: 'inplaceeditor-form',
|
|
471
|
-
highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
|
|
472
|
-
highlightendcolor: "#FFFFFF",
|
|
473
|
-
externalControl: null,
|
|
474
|
-
ajaxOptions: {}
|
|
475
|
-
}, options || {});
|
|
476
|
-
|
|
477
|
-
if(!this.options.formId && this.element.id) {
|
|
478
|
-
this.options.formId = this.element.id + "-inplaceeditor";
|
|
479
|
-
if ($(this.options.formId)) {
|
|
480
|
-
// there's already a form with that name, don't specify an id
|
|
481
|
-
this.options.formId = null;
|
|
482
|
-
}
|
|
482
|
+
this.element = element = $(element);
|
|
483
|
+
this.prepareOptions();
|
|
484
|
+
this._controls = { };
|
|
485
|
+
arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!!
|
|
486
|
+
Object.extend(this.options, options || { });
|
|
487
|
+
if (!this.options.formId && this.element.id) {
|
|
488
|
+
this.options.formId = this.element.id + '-inplaceeditor';
|
|
489
|
+
if ($(this.options.formId))
|
|
490
|
+
this.options.formId = '';
|
|
483
491
|
}
|
|
484
|
-
|
|
485
|
-
if (this.options.externalControl) {
|
|
492
|
+
if (this.options.externalControl)
|
|
486
493
|
this.options.externalControl = $(this.options.externalControl);
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
this.
|
|
490
|
-
if (!this.originalBackground) {
|
|
491
|
-
this.originalBackground = "transparent";
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
+
if (!this.options.externalControl)
|
|
495
|
+
this.options.externalControlOnly = false;
|
|
496
|
+
this._originalBackground = this.element.getStyle('background-color') || 'transparent';
|
|
494
497
|
this.element.title = this.options.clickToEditText;
|
|
495
|
-
|
|
496
|
-
this.
|
|
497
|
-
this.
|
|
498
|
-
this.
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
498
|
+
this._boundCancelHandler = this.handleFormCancellation.bind(this);
|
|
499
|
+
this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this);
|
|
500
|
+
this._boundFailureHandler = this.handleAJAXFailure.bind(this);
|
|
501
|
+
this._boundSubmitHandler = this.handleFormSubmission.bind(this);
|
|
502
|
+
this._boundWrapperHandler = this.wrapUp.bind(this);
|
|
503
|
+
this.registerListeners();
|
|
504
|
+
},
|
|
505
|
+
checkForEscapeOrReturn: function(e) {
|
|
506
|
+
if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return;
|
|
507
|
+
if (Event.KEY_ESC == e.keyCode)
|
|
508
|
+
this.handleFormCancellation(e);
|
|
509
|
+
else if (Event.KEY_RETURN == e.keyCode)
|
|
510
|
+
this.handleFormSubmission(e);
|
|
511
|
+
},
|
|
512
|
+
createControl: function(mode, handler, extraClasses) {
|
|
513
|
+
var control = this.options[mode + 'Control'];
|
|
514
|
+
var text = this.options[mode + 'Text'];
|
|
515
|
+
if ('button' == control) {
|
|
516
|
+
var btn = document.createElement('input');
|
|
517
|
+
btn.type = 'submit';
|
|
518
|
+
btn.value = text;
|
|
519
|
+
btn.className = 'editor_' + mode + '_button';
|
|
520
|
+
if ('cancel' == mode)
|
|
521
|
+
btn.onclick = this._boundCancelHandler;
|
|
522
|
+
this._form.appendChild(btn);
|
|
523
|
+
this._controls[mode] = btn;
|
|
524
|
+
} else if ('link' == control) {
|
|
525
|
+
var link = document.createElement('a');
|
|
526
|
+
link.href = '#';
|
|
527
|
+
link.appendChild(document.createTextNode(text));
|
|
528
|
+
link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler;
|
|
529
|
+
link.className = 'editor_' + mode + '_link';
|
|
530
|
+
if (extraClasses)
|
|
531
|
+
link.className += ' ' + extraClasses;
|
|
532
|
+
this._form.appendChild(link);
|
|
533
|
+
this._controls[mode] = link;
|
|
506
534
|
}
|
|
507
535
|
},
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
this.
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
// stop the event to avoid a page refresh in Safari
|
|
521
|
-
if (evt) {
|
|
522
|
-
Event.stop(evt);
|
|
536
|
+
createEditField: function() {
|
|
537
|
+
var text = (this.options.loadTextURL ? this.options.loadingText : this.getText());
|
|
538
|
+
var fld;
|
|
539
|
+
if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) {
|
|
540
|
+
fld = document.createElement('input');
|
|
541
|
+
fld.type = 'text';
|
|
542
|
+
var size = this.options.size || this.options.cols || 0;
|
|
543
|
+
if (0 < size) fld.size = size;
|
|
544
|
+
} else {
|
|
545
|
+
fld = document.createElement('textarea');
|
|
546
|
+
fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows);
|
|
547
|
+
fld.cols = this.options.cols || 40;
|
|
523
548
|
}
|
|
524
|
-
|
|
549
|
+
fld.name = this.options.paramName;
|
|
550
|
+
fld.value = text; // No HTML breaks conversion anymore
|
|
551
|
+
fld.className = 'editor_field';
|
|
552
|
+
if (this.options.submitOnBlur)
|
|
553
|
+
fld.onblur = this._boundSubmitHandler;
|
|
554
|
+
this._controls.editor = fld;
|
|
555
|
+
if (this.options.loadTextURL)
|
|
556
|
+
this.loadExternalText();
|
|
557
|
+
this._form.appendChild(this._controls.editor);
|
|
525
558
|
},
|
|
526
559
|
createForm: function() {
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
560
|
+
var ipe = this;
|
|
561
|
+
function addText(mode, condition) {
|
|
562
|
+
var text = ipe.options['text' + mode + 'Controls'];
|
|
563
|
+
if (!text || condition === false) return;
|
|
564
|
+
ipe._form.appendChild(document.createTextNode(text));
|
|
565
|
+
};
|
|
566
|
+
this._form = $(document.createElement('form'));
|
|
567
|
+
this._form.id = this.options.formId;
|
|
568
|
+
this._form.addClassName(this.options.formClassName);
|
|
569
|
+
this._form.onsubmit = this._boundSubmitHandler;
|
|
532
570
|
this.createEditField();
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
this.
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
571
|
+
if ('textarea' == this._controls.editor.tagName.toLowerCase())
|
|
572
|
+
this._form.appendChild(document.createElement('br'));
|
|
573
|
+
if (this.options.onFormCustomization)
|
|
574
|
+
this.options.onFormCustomization(this, this._form);
|
|
575
|
+
addText('Before', this.options.okControl || this.options.cancelControl);
|
|
576
|
+
this.createControl('ok', this._boundSubmitHandler);
|
|
577
|
+
addText('Between', this.options.okControl && this.options.cancelControl);
|
|
578
|
+
this.createControl('cancel', this._boundCancelHandler, 'editor_cancel');
|
|
579
|
+
addText('After', this.options.okControl || this.options.cancelControl);
|
|
580
|
+
},
|
|
581
|
+
destroy: function() {
|
|
582
|
+
if (this._oldInnerHTML)
|
|
583
|
+
this.element.innerHTML = this._oldInnerHTML;
|
|
584
|
+
this.leaveEditMode();
|
|
585
|
+
this.unregisterListeners();
|
|
586
|
+
},
|
|
587
|
+
enterEditMode: function(e) {
|
|
588
|
+
if (this._saving || this._editing) return;
|
|
589
|
+
this._editing = true;
|
|
590
|
+
this.triggerCallback('onEnterEditMode');
|
|
591
|
+
if (this.options.externalControl)
|
|
592
|
+
this.options.externalControl.hide();
|
|
593
|
+
this.element.hide();
|
|
594
|
+
this.createForm();
|
|
595
|
+
this.element.parentNode.insertBefore(this._form, this.element);
|
|
596
|
+
if (!this.options.loadTextURL)
|
|
597
|
+
this.postProcessEditField();
|
|
598
|
+
if (e) Event.stop(e);
|
|
549
599
|
},
|
|
550
|
-
|
|
551
|
-
if (
|
|
552
|
-
|
|
600
|
+
enterHover: function(e) {
|
|
601
|
+
if (this.options.hoverClassName)
|
|
602
|
+
this.element.addClassName(this.options.hoverClassName);
|
|
603
|
+
if (this._saving) return;
|
|
604
|
+
this.triggerCallback('onEnterHover');
|
|
553
605
|
},
|
|
554
|
-
|
|
555
|
-
return
|
|
606
|
+
getText: function() {
|
|
607
|
+
return this.element.innerHTML.unescapeHTML();
|
|
556
608
|
},
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
if(this.
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
text = this.getText();
|
|
609
|
+
handleAJAXFailure: function(transport) {
|
|
610
|
+
this.triggerCallback('onFailure', transport);
|
|
611
|
+
if (this._oldInnerHTML) {
|
|
612
|
+
this.element.innerHTML = this._oldInnerHTML;
|
|
613
|
+
this._oldInnerHTML = null;
|
|
563
614
|
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
615
|
+
},
|
|
616
|
+
handleFormCancellation: function(e) {
|
|
617
|
+
this.wrapUp();
|
|
618
|
+
if (e) Event.stop(e);
|
|
619
|
+
},
|
|
620
|
+
handleFormSubmission: function(e) {
|
|
621
|
+
var form = this._form;
|
|
622
|
+
var value = $F(this._controls.editor);
|
|
623
|
+
this.prepareSubmission();
|
|
624
|
+
var params = this.options.callback(form, value) || '';
|
|
625
|
+
if (Object.isString(params))
|
|
626
|
+
params = params.toQueryParams();
|
|
627
|
+
params.editorId = this.element.id;
|
|
628
|
+
if (this.options.htmlResponse) {
|
|
629
|
+
var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions);
|
|
630
|
+
Object.extend(options, {
|
|
631
|
+
parameters: params,
|
|
632
|
+
onComplete: this._boundWrapperHandler,
|
|
633
|
+
onFailure: this._boundFailureHandler
|
|
634
|
+
});
|
|
635
|
+
new Ajax.Updater({ success: this.element }, this.url, options);
|
|
575
636
|
} else {
|
|
576
|
-
this.options.
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
this.
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
if(this.options.loadTextURL) {
|
|
586
|
-
this.loadExternalText();
|
|
637
|
+
var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
|
|
638
|
+
Object.extend(options, {
|
|
639
|
+
parameters: params,
|
|
640
|
+
onComplete: this._boundWrapperHandler,
|
|
641
|
+
onFailure: this._boundFailureHandler
|
|
642
|
+
});
|
|
643
|
+
new Ajax.Request(this.url, options);
|
|
587
644
|
}
|
|
588
|
-
|
|
645
|
+
if (e) Event.stop(e);
|
|
589
646
|
},
|
|
590
|
-
|
|
591
|
-
|
|
647
|
+
leaveEditMode: function() {
|
|
648
|
+
this.element.removeClassName(this.options.savingClassName);
|
|
649
|
+
this.removeForm();
|
|
650
|
+
this.leaveHover();
|
|
651
|
+
this.element.style.backgroundColor = this._originalBackground;
|
|
652
|
+
this.element.show();
|
|
653
|
+
if (this.options.externalControl)
|
|
654
|
+
this.options.externalControl.show();
|
|
655
|
+
this._saving = false;
|
|
656
|
+
this._editing = false;
|
|
657
|
+
this._oldInnerHTML = null;
|
|
658
|
+
this.triggerCallback('onLeaveEditMode');
|
|
659
|
+
},
|
|
660
|
+
leaveHover: function(e) {
|
|
661
|
+
if (this.options.hoverClassName)
|
|
662
|
+
this.element.removeClassName(this.options.hoverClassName);
|
|
663
|
+
if (this._saving) return;
|
|
664
|
+
this.triggerCallback('onLeaveHover');
|
|
592
665
|
},
|
|
593
666
|
loadExternalText: function() {
|
|
594
|
-
|
|
595
|
-
this.
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
this.
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
// do this first, sometimes the ajax call returns before we get a chance to switch on Saving...
|
|
628
|
-
// which means this will actually switch on Saving... *after* we've left edit mode causing Saving...
|
|
629
|
-
// to be displayed indefinitely
|
|
630
|
-
this.onLoading();
|
|
631
|
-
|
|
632
|
-
new Ajax.Updater(
|
|
633
|
-
{
|
|
634
|
-
success: this.element,
|
|
635
|
-
// don't update on failure (this could be an option)
|
|
636
|
-
failure: null
|
|
637
|
-
},
|
|
638
|
-
this.url,
|
|
639
|
-
Object.extend({
|
|
640
|
-
parameters: this.options.callback(form, value),
|
|
641
|
-
onComplete: this.onComplete.bind(this),
|
|
642
|
-
onFailure: this.onFailure.bind(this)
|
|
643
|
-
}, this.options.ajaxOptions)
|
|
644
|
-
);
|
|
645
|
-
// stop the event to avoid a page refresh in Safari
|
|
646
|
-
if (arguments.length > 1) {
|
|
647
|
-
Event.stop(arguments[0]);
|
|
648
|
-
}
|
|
649
|
-
return false;
|
|
650
|
-
},
|
|
651
|
-
onLoading: function() {
|
|
652
|
-
this.saving = true;
|
|
667
|
+
this._form.addClassName(this.options.loadingClassName);
|
|
668
|
+
this._controls.editor.disabled = true;
|
|
669
|
+
var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
|
|
670
|
+
Object.extend(options, {
|
|
671
|
+
parameters: 'editorId=' + encodeURIComponent(this.element.id),
|
|
672
|
+
onComplete: Prototype.emptyFunction,
|
|
673
|
+
onSuccess: function(transport) {
|
|
674
|
+
this._form.removeClassName(this.options.loadingClassName);
|
|
675
|
+
var text = transport.responseText;
|
|
676
|
+
if (this.options.stripLoadedTextTags)
|
|
677
|
+
text = text.stripTags();
|
|
678
|
+
this._controls.editor.value = text;
|
|
679
|
+
this._controls.editor.disabled = false;
|
|
680
|
+
this.postProcessEditField();
|
|
681
|
+
}.bind(this),
|
|
682
|
+
onFailure: this._boundFailureHandler
|
|
683
|
+
});
|
|
684
|
+
new Ajax.Request(this.options.loadTextURL, options);
|
|
685
|
+
},
|
|
686
|
+
postProcessEditField: function() {
|
|
687
|
+
var fpc = this.options.fieldPostCreation;
|
|
688
|
+
if (fpc)
|
|
689
|
+
$(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']();
|
|
690
|
+
},
|
|
691
|
+
prepareOptions: function() {
|
|
692
|
+
this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions);
|
|
693
|
+
Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks);
|
|
694
|
+
[this._extraDefaultOptions].flatten().compact().each(function(defs) {
|
|
695
|
+
Object.extend(this.options, defs);
|
|
696
|
+
}.bind(this));
|
|
697
|
+
},
|
|
698
|
+
prepareSubmission: function() {
|
|
699
|
+
this._saving = true;
|
|
653
700
|
this.removeForm();
|
|
654
701
|
this.leaveHover();
|
|
655
702
|
this.showSaving();
|
|
656
703
|
},
|
|
704
|
+
registerListeners: function() {
|
|
705
|
+
this._listeners = { };
|
|
706
|
+
var listener;
|
|
707
|
+
$H(Ajax.InPlaceEditor.Listeners).each(function(pair) {
|
|
708
|
+
listener = this[pair.value].bind(this);
|
|
709
|
+
this._listeners[pair.key] = listener;
|
|
710
|
+
if (!this.options.externalControlOnly)
|
|
711
|
+
this.element.observe(pair.key, listener);
|
|
712
|
+
if (this.options.externalControl)
|
|
713
|
+
this.options.externalControl.observe(pair.key, listener);
|
|
714
|
+
}.bind(this));
|
|
715
|
+
},
|
|
716
|
+
removeForm: function() {
|
|
717
|
+
if (!this._form) return;
|
|
718
|
+
this._form.remove();
|
|
719
|
+
this._form = null;
|
|
720
|
+
this._controls = { };
|
|
721
|
+
},
|
|
657
722
|
showSaving: function() {
|
|
658
|
-
this.
|
|
723
|
+
this._oldInnerHTML = this.element.innerHTML;
|
|
659
724
|
this.element.innerHTML = this.options.savingText;
|
|
660
|
-
|
|
661
|
-
this.element.style.backgroundColor = this.
|
|
662
|
-
|
|
725
|
+
this.element.addClassName(this.options.savingClassName);
|
|
726
|
+
this.element.style.backgroundColor = this._originalBackground;
|
|
727
|
+
this.element.show();
|
|
663
728
|
},
|
|
664
|
-
|
|
665
|
-
if(this.
|
|
666
|
-
|
|
667
|
-
this.form = null;
|
|
729
|
+
triggerCallback: function(cbName, arg) {
|
|
730
|
+
if ('function' == typeof this.options[cbName]) {
|
|
731
|
+
this.options[cbName](this, arg);
|
|
668
732
|
}
|
|
669
733
|
},
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
this.
|
|
675
|
-
|
|
676
|
-
|
|
734
|
+
unregisterListeners: function() {
|
|
735
|
+
$H(this._listeners).each(function(pair) {
|
|
736
|
+
if (!this.options.externalControlOnly)
|
|
737
|
+
this.element.stopObserving(pair.key, pair.value);
|
|
738
|
+
if (this.options.externalControl)
|
|
739
|
+
this.options.externalControl.stopObserving(pair.key, pair.value);
|
|
740
|
+
}.bind(this));
|
|
677
741
|
},
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
742
|
+
wrapUp: function(transport) {
|
|
743
|
+
this.leaveEditMode();
|
|
744
|
+
// Can't use triggerCallback due to backward compatibility: requires
|
|
745
|
+
// binding + direct element
|
|
746
|
+
this._boundComplete(transport, this.element);
|
|
747
|
+
}
|
|
748
|
+
});
|
|
749
|
+
|
|
750
|
+
Object.extend(Ajax.InPlaceEditor.prototype, {
|
|
751
|
+
dispose: Ajax.InPlaceEditor.prototype.destroy
|
|
752
|
+
});
|
|
753
|
+
|
|
754
|
+
Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
|
|
755
|
+
initialize: function($super, element, url, options) {
|
|
756
|
+
this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions;
|
|
757
|
+
$super(element, url, options);
|
|
758
|
+
},
|
|
759
|
+
|
|
760
|
+
createEditField: function() {
|
|
761
|
+
var list = document.createElement('select');
|
|
762
|
+
list.name = this.options.paramName;
|
|
763
|
+
list.size = 1;
|
|
764
|
+
this._controls.editor = list;
|
|
765
|
+
this._collection = this.options.collection || [];
|
|
766
|
+
if (this.options.loadCollectionURL)
|
|
767
|
+
this.loadCollection();
|
|
768
|
+
else
|
|
769
|
+
this.checkForExternalText();
|
|
770
|
+
this._form.appendChild(this._controls.editor);
|
|
771
|
+
},
|
|
772
|
+
|
|
773
|
+
loadCollection: function() {
|
|
774
|
+
this._form.addClassName(this.options.loadingClassName);
|
|
775
|
+
this.showLoadingText(this.options.loadingCollectionText);
|
|
776
|
+
var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
|
|
777
|
+
Object.extend(options, {
|
|
778
|
+
parameters: 'editorId=' + encodeURIComponent(this.element.id),
|
|
779
|
+
onComplete: Prototype.emptyFunction,
|
|
780
|
+
onSuccess: function(transport) {
|
|
781
|
+
var js = transport.responseText.strip();
|
|
782
|
+
if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
|
|
783
|
+
throw('Server returned an invalid collection representation.');
|
|
784
|
+
this._collection = eval(js);
|
|
785
|
+
this.checkForExternalText();
|
|
786
|
+
}.bind(this),
|
|
787
|
+
onFailure: this.onFailure
|
|
688
788
|
});
|
|
789
|
+
new Ajax.Request(this.options.loadCollectionURL, options);
|
|
689
790
|
},
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
this.
|
|
693
|
-
this.
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
791
|
+
|
|
792
|
+
showLoadingText: function(text) {
|
|
793
|
+
this._controls.editor.disabled = true;
|
|
794
|
+
var tempOption = this._controls.editor.firstChild;
|
|
795
|
+
if (!tempOption) {
|
|
796
|
+
tempOption = document.createElement('option');
|
|
797
|
+
tempOption.value = '';
|
|
798
|
+
this._controls.editor.appendChild(tempOption);
|
|
799
|
+
tempOption.selected = true;
|
|
698
800
|
}
|
|
699
|
-
|
|
700
|
-
this.saving = false;
|
|
701
|
-
this.oldInnerHTML = null;
|
|
702
|
-
this.onLeaveEditMode();
|
|
801
|
+
tempOption.update((text || '').stripScripts().stripTags());
|
|
703
802
|
},
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
this.
|
|
803
|
+
|
|
804
|
+
checkForExternalText: function() {
|
|
805
|
+
this._text = this.getText();
|
|
806
|
+
if (this.options.loadTextURL)
|
|
807
|
+
this.loadExternalText();
|
|
808
|
+
else
|
|
809
|
+
this.buildOptionList();
|
|
707
810
|
},
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
811
|
+
|
|
812
|
+
loadExternalText: function() {
|
|
813
|
+
this.showLoadingText(this.options.loadingText);
|
|
814
|
+
var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
|
|
815
|
+
Object.extend(options, {
|
|
816
|
+
parameters: 'editorId=' + encodeURIComponent(this.element.id),
|
|
817
|
+
onComplete: Prototype.emptyFunction,
|
|
818
|
+
onSuccess: function(transport) {
|
|
819
|
+
this._text = transport.responseText.strip();
|
|
820
|
+
this.buildOptionList();
|
|
821
|
+
}.bind(this),
|
|
822
|
+
onFailure: this.onFailure
|
|
823
|
+
});
|
|
824
|
+
new Ajax.Request(this.options.loadTextURL, options);
|
|
825
|
+
},
|
|
826
|
+
|
|
827
|
+
buildOptionList: function() {
|
|
828
|
+
this._form.removeClassName(this.options.loadingClassName);
|
|
829
|
+
this._collection = this._collection.map(function(entry) {
|
|
830
|
+
return 2 === entry.length ? entry : [entry, entry].flatten();
|
|
831
|
+
});
|
|
832
|
+
var marker = ('value' in this.options) ? this.options.value : this._text;
|
|
833
|
+
var textFound = this._collection.any(function(entry) {
|
|
834
|
+
return entry[0] == marker;
|
|
835
|
+
}.bind(this));
|
|
836
|
+
this._controls.editor.update('');
|
|
837
|
+
var option;
|
|
838
|
+
this._collection.each(function(entry, index) {
|
|
839
|
+
option = document.createElement('option');
|
|
840
|
+
option.value = entry[0];
|
|
841
|
+
option.selected = textFound ? entry[0] == marker : 0 == index;
|
|
842
|
+
option.appendChild(document.createTextNode(entry[1]));
|
|
843
|
+
this._controls.editor.appendChild(option);
|
|
844
|
+
}.bind(this));
|
|
845
|
+
this._controls.editor.disabled = false;
|
|
846
|
+
Field.scrollFreeActivate(this._controls.editor);
|
|
847
|
+
}
|
|
848
|
+
});
|
|
849
|
+
|
|
850
|
+
//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! ****
|
|
851
|
+
//**** This only exists for a while, in order to let ****
|
|
852
|
+
//**** users adapt to the new API. Read up on the new ****
|
|
853
|
+
//**** API and convert your code to it ASAP! ****
|
|
854
|
+
|
|
855
|
+
Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) {
|
|
856
|
+
if (!options) return;
|
|
857
|
+
function fallback(name, expr) {
|
|
858
|
+
if (name in options || expr === undefined) return;
|
|
859
|
+
options[name] = expr;
|
|
860
|
+
};
|
|
861
|
+
fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' :
|
|
862
|
+
options.cancelLink == options.cancelButton == false ? false : undefined)));
|
|
863
|
+
fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' :
|
|
864
|
+
options.okLink == options.okButton == false ? false : undefined)));
|
|
865
|
+
fallback('highlightColor', options.highlightcolor);
|
|
866
|
+
fallback('highlightEndColor', options.highlightendcolor);
|
|
867
|
+
};
|
|
868
|
+
|
|
869
|
+
Object.extend(Ajax.InPlaceEditor, {
|
|
870
|
+
DefaultOptions: {
|
|
871
|
+
ajaxOptions: { },
|
|
872
|
+
autoRows: 3, // Use when multi-line w/ rows == 1
|
|
873
|
+
cancelControl: 'link', // 'link'|'button'|false
|
|
874
|
+
cancelText: 'cancel',
|
|
875
|
+
clickToEditText: 'Click to edit',
|
|
876
|
+
externalControl: null, // id|elt
|
|
877
|
+
externalControlOnly: false,
|
|
878
|
+
fieldPostCreation: 'activate', // 'activate'|'focus'|false
|
|
879
|
+
formClassName: 'inplaceeditor-form',
|
|
880
|
+
formId: null, // id|elt
|
|
881
|
+
highlightColor: '#ffff99',
|
|
882
|
+
highlightEndColor: '#ffffff',
|
|
883
|
+
hoverClassName: '',
|
|
884
|
+
htmlResponse: true,
|
|
885
|
+
loadingClassName: 'inplaceeditor-loading',
|
|
886
|
+
loadingText: 'Loading...',
|
|
887
|
+
okControl: 'button', // 'link'|'button'|false
|
|
888
|
+
okText: 'ok',
|
|
889
|
+
paramName: 'value',
|
|
890
|
+
rows: 1, // If 1 and multi-line, uses autoRows
|
|
891
|
+
savingClassName: 'inplaceeditor-saving',
|
|
892
|
+
savingText: 'Saving...',
|
|
893
|
+
size: 0,
|
|
894
|
+
stripLoadedTextTags: false,
|
|
895
|
+
submitOnBlur: false,
|
|
896
|
+
textAfterControls: '',
|
|
897
|
+
textBeforeControls: '',
|
|
898
|
+
textBetweenControls: ''
|
|
899
|
+
},
|
|
900
|
+
DefaultCallbacks: {
|
|
901
|
+
callback: function(form) {
|
|
902
|
+
return Form.serialize(form);
|
|
903
|
+
},
|
|
904
|
+
onComplete: function(transport, element) {
|
|
905
|
+
// For backward compatibility, this one is bound to the IPE, and passes
|
|
906
|
+
// the element directly. It was too often customized, so we don't break it.
|
|
907
|
+
new Effect.Highlight(element, {
|
|
908
|
+
startcolor: this.options.highlightColor, keepBackgroundImage: true });
|
|
909
|
+
},
|
|
910
|
+
onEnterEditMode: null,
|
|
911
|
+
onEnterHover: function(ipe) {
|
|
912
|
+
ipe.element.style.backgroundColor = ipe.options.highlightColor;
|
|
913
|
+
if (ipe._effect)
|
|
914
|
+
ipe._effect.cancel();
|
|
915
|
+
},
|
|
916
|
+
onFailure: function(transport, ipe) {
|
|
917
|
+
alert('Error communication with the server: ' + transport.responseText.stripTags());
|
|
918
|
+
},
|
|
919
|
+
onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls.
|
|
920
|
+
onLeaveEditMode: null,
|
|
921
|
+
onLeaveHover: function(ipe) {
|
|
922
|
+
ipe._effect = new Effect.Highlight(ipe.element, {
|
|
923
|
+
startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor,
|
|
924
|
+
restorecolor: ipe._originalBackground, keepBackgroundImage: true
|
|
925
|
+
});
|
|
722
926
|
}
|
|
927
|
+
},
|
|
928
|
+
Listeners: {
|
|
929
|
+
click: 'enterEditMode',
|
|
930
|
+
keydown: 'checkForEscapeOrReturn',
|
|
931
|
+
mouseover: 'enterHover',
|
|
932
|
+
mouseout: 'leaveHover'
|
|
723
933
|
}
|
|
934
|
+
});
|
|
935
|
+
|
|
936
|
+
Ajax.InPlaceCollectionEditor.DefaultOptions = {
|
|
937
|
+
loadingCollectionText: 'Loading options...'
|
|
724
938
|
};
|
|
725
939
|
|
|
726
|
-
// Delayed observer, like Form.Element.Observer,
|
|
940
|
+
// Delayed observer, like Form.Element.Observer,
|
|
727
941
|
// but waits for delay after last key input
|
|
728
942
|
// Ideal for live-search fields
|
|
729
943
|
|
|
730
|
-
Form.Element.DelayedObserver = Class.create(
|
|
731
|
-
Form.Element.DelayedObserver.prototype = {
|
|
944
|
+
Form.Element.DelayedObserver = Class.create({
|
|
732
945
|
initialize: function(element, delay, callback) {
|
|
733
946
|
this.delay = delay || 0.5;
|
|
734
947
|
this.element = $(element);
|
|
735
948
|
this.callback = callback;
|
|
736
949
|
this.timer = null;
|
|
737
|
-
this.lastValue = $F(this.element);
|
|
950
|
+
this.lastValue = $F(this.element);
|
|
738
951
|
Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
|
|
739
952
|
},
|
|
740
953
|
delayedListener: function(event) {
|
|
@@ -747,4 +960,4 @@ Form.Element.DelayedObserver.prototype = {
|
|
|
747
960
|
this.timer = null;
|
|
748
961
|
this.callback(this.element, $F(this.element));
|
|
749
962
|
}
|
|
750
|
-
};
|
|
963
|
+
});
|