##// END OF EJS Templates
* project settings split in 4 tabs...
Jean-Philippe Lang -
r178:190fef513fea
parent child
Show More
@@ -22,16 +22,16 class IssueCategoriesController < ApplicationController
22 def edit
22 def edit
23 if request.post? and @category.update_attributes(params[:category])
23 if request.post? and @category.update_attributes(params[:category])
24 flash[:notice] = l(:notice_successful_update)
24 flash[:notice] = l(:notice_successful_update)
25 redirect_to :controller => 'projects', :action => 'settings', :id => @project
25 redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project
26 end
26 end
27 end
27 end
28
28
29 def destroy
29 def destroy
30 @category.destroy
30 @category.destroy
31 redirect_to :controller => 'projects', :action => 'settings', :id => @project
31 redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project
32 rescue
32 rescue
33 flash[:notice] = "Categorie can't be deleted"
33 flash[:notice] = "Categorie can't be deleted"
34 redirect_to :controller => 'projects', :action => 'settings', :id => @project
34 redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project
35 end
35 end
36
36
37 private
37 private
@@ -16,21 +16,21
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class MembersController < ApplicationController
18 class MembersController < ApplicationController
19 layout 'base'
19 layout 'base'
20 before_filter :find_project, :authorize
20 before_filter :find_project, :authorize
21
21
22 def edit
22 def edit
23 if request.post? and @member.update_attributes(params[:member])
23 if request.post? and @member.update_attributes(params[:member])
24 flash[:notice] = l(:notice_successful_update)
24 flash[:notice] = l(:notice_successful_update)
25 redirect_to :controller => 'projects', :action => 'settings', :id => @project
25 redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project
26 end
26 end
27 end
27 end
28
28
29 def destroy
29 def destroy
30 @member.destroy
30 @member.destroy
31 flash[:notice] = l(:notice_successful_delete)
31 flash[:notice] = l(:notice_successful_delete)
32 redirect_to :controller => 'projects', :action => 'settings', :id => @project
32 redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project
33 end
33 end
34
34
35 private
35 private
36 def find_project
36 def find_project
@@ -138,7 +138,7 class ProjectsController < ApplicationController
138 @issue_category = @project.issue_categories.build(params[:issue_category])
138 @issue_category = @project.issue_categories.build(params[:issue_category])
139 if @issue_category.save
139 if @issue_category.save
140 flash[:notice] = l(:notice_successful_create)
140 flash[:notice] = l(:notice_successful_create)
141 redirect_to :action => 'settings', :id => @project
141 redirect_to :action => 'settings', :tab => 'categories', :id => @project
142 else
142 else
143 settings
143 settings
144 render :action => 'settings'
144 render :action => 'settings'
@@ -151,7 +151,7 class ProjectsController < ApplicationController
151 @version = @project.versions.build(params[:version])
151 @version = @project.versions.build(params[:version])
152 if request.post? and @version.save
152 if request.post? and @version.save
153 flash[:notice] = l(:notice_successful_create)
153 flash[:notice] = l(:notice_successful_create)
154 redirect_to :action => 'settings', :id => @project
154 redirect_to :action => 'settings', :tab => 'versions', :id => @project
155 end
155 end
156 end
156 end
157
157
@@ -161,7 +161,7 class ProjectsController < ApplicationController
161 if request.post?
161 if request.post?
162 if @member.save
162 if @member.save
163 flash[:notice] = l(:notice_successful_create)
163 flash[:notice] = l(:notice_successful_create)
164 redirect_to :action => 'settings', :id => @project
164 redirect_to :action => 'settings', :tab => 'members', :id => @project
165 else
165 else
166 settings
166 settings
167 render :action => 'settings'
167 render :action => 'settings'
@@ -22,16 +22,16 class VersionsController < ApplicationController
22 def edit
22 def edit
23 if request.post? and @version.update_attributes(params[:version])
23 if request.post? and @version.update_attributes(params[:version])
24 flash[:notice] = l(:notice_successful_update)
24 flash[:notice] = l(:notice_successful_update)
25 redirect_to :controller => 'projects', :action => 'settings', :id => @project
25 redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
26 end
26 end
27 end
27 end
28
28
29 def destroy
29 def destroy
30 @version.destroy
30 @version.destroy
31 redirect_to :controller => 'projects', :action => 'settings', :id => @project
31 redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
32 rescue
32 rescue
33 flash[:notice] = "Unable to delete version"
33 flash[:notice] = "Unable to delete version"
34 redirect_to :controller => 'projects', :action => 'settings', :id => @project
34 redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
35 end
35 end
36
36
37 def download
37 def download
@@ -1,13 +1,24
1 <h2><%=l(:label_settings)%></h2>
1 <h2><%=l(:label_settings)%></h2>
2
2
3 <div class="tabs">
4 <ul>
5 <li><%= link_to l(:label_information_plural), {}, :id=> "tab-info", :onclick => "showTab('info'); this.blur(); return false;" %></li>
6 <li><%= link_to l(:label_member_plural), {}, :id=> "tab-members", :onclick => "showTab('members'); this.blur(); return false;" %></li>
7 <li><%= link_to l(:label_version_plural), {}, :id=> "tab-versions", :onclick => "showTab('versions'); this.blur(); return false;" %></li>
8 <li><%= link_to l(:label_issue_category_plural), {}, :id=> "tab-categories", :onclick => "showTab('categories'); this.blur(); return false;" %></li>
9 </ul>
10 </div>
11
12 <div id="tab-content-info" class="tab-content">
3 <% if authorize_for('projects', 'edit') %>
13 <% if authorize_for('projects', 'edit') %>
4 <% labelled_tabular_form_for :project, @project, :url => { :action => "edit", :id => @project } do |f| %>
14 <% labelled_tabular_form_for :project, @project, :url => { :action => "edit", :id => @project } do |f| %>
5 <%= render :partial => 'form', :locals => { :f => f } %>
15 <%= render :partial => 'form', :locals => { :f => f } %>
6 <%= submit_tag l(:button_save) %>
16 <%= submit_tag l(:button_save) %>
7 <% end %>
17 <% end %>
8 <br />&nbsp;
9 <% end %>
18 <% end %>
10
19 </div>
20
21 <div id="tab-content-members" class="tab-content" style="display:none;">
11 <div class="box">
22 <div class="box">
12 <h3><%=l(:label_member_plural)%></h3>
23 <h3><%=l(:label_member_plural)%></h3>
13 <%= error_messages_for 'member' %>
24 <%= error_messages_for 'member' %>
@@ -36,7 +47,7
36 <% if authorize_for('projects', 'add_member') %>
47 <% if authorize_for('projects', 'add_member') %>
37 <hr />
48 <hr />
38 <label><%=l(:label_member_new)%></label><br/>
49 <label><%=l(:label_member_new)%></label><br/>
39 <%= start_form_tag :controller => 'projects', :action => 'add_member', :id => @project %>
50 <%= start_form_tag :controller => 'projects', :action => 'add_member', :tab => 'members', :id => @project %>
40 <select name="member[user_id]">
51 <select name="member[user_id]">
41 <%= options_from_collection_for_select @users, "id", "display_name", @member.user_id %>
52 <%= options_from_collection_for_select @users, "id", "display_name", @member.user_id %>
42 </select>
53 </select>
@@ -47,7 +58,9
47 <%= end_form_tag %>
58 <%= end_form_tag %>
48 <% end %>
59 <% end %>
49 </div>
60 </div>
50
61 </div>
62
63 <div id="tab-content-versions" class="tab-content" style="display:none;">
51 <div class="box">
64 <div class="box">
52 <h3><%=l(:label_version_plural)%></h3>
65 <h3><%=l(:label_version_plural)%></h3>
53 <table>
66 <table>
@@ -68,8 +81,9
68 <%= link_to l(:label_version_new), :controller => 'projects', :action => 'add_version', :id => @project %>
81 <%= link_to l(:label_version_new), :controller => 'projects', :action => 'add_version', :id => @project %>
69 <% end %>
82 <% end %>
70 </div>
83 </div>
71
84 </div>
72
85
86 <div id="tab-content-categories" class="tab-content" style="display:none;">
73 <div class="box">
87 <div class="box">
74 <h3><%=l(:label_issue_category_plural)%></h3>
88 <h3><%=l(:label_issue_category_plural)%></h3>
75 <table>
89 <table>
@@ -95,7 +109,7
95 </table>
109 </table>
96 <% if authorize_for('projects', 'add_issue_category') %>
110 <% if authorize_for('projects', 'add_issue_category') %>
97 <hr />
111 <hr />
98 <%= start_form_tag :action => 'add_issue_category', :id => @project %>
112 <%= start_form_tag :action => 'add_issue_category', :tab => 'categories', :id => @project %>
99 <label for="issue_category_name"><%=l(:label_issue_category_new)%></label><br/>
113 <label for="issue_category_name"><%=l(:label_issue_category_new)%></label><br/>
100 <%= error_messages_for 'issue_category' %>
114 <%= error_messages_for 'issue_category' %>
101 <%= text_field 'issue_category', 'name', :size => 25 %>
115 <%= text_field 'issue_category', 'name', :size => 25 %>
@@ -103,3 +117,7
103 <%= end_form_tag %>
117 <%= end_form_tag %>
104 <% end %>
118 <% end %>
105 </div>
119 </div>
120 </div>
121
122 <%= tab = params[:tab] ? h(params[:tab]) : 'info'
123 javascript_tag "showTab('#{tab}');" %> No newline at end of file
@@ -16,4 +16,18 function addFileField() {
16 p = document.getElementById("attachments_p");
16 p = document.getElementById("attachments_p");
17 p.appendChild(document.createElement("br"));
17 p.appendChild(document.createElement("br"));
18 p.appendChild(f);
18 p.appendChild(f);
19 }
20
21 function showTab(name) {
22 var f = $$('div#content .tab-content');
23 for(var i=0; i<f.length; i++){
24 Element.hide(f[i]);
25 }
26 var f = $$('div.tabs a');
27 for(var i=0; i<f.length; i++){
28 Element.removeClassName(f[i], "selected");
29 }
30 Element.show('tab-content-' + name);
31 Element.addClassName('tab-' + name, "selected");
32 return false;
19 } No newline at end of file
33 }
This diff has been collapsed as it changes many lines, (1132 lines changed) Show them Hide them
@@ -1,21 +1,20
1 /* Prototype JavaScript framework, version 1.4.0
1 /* Prototype JavaScript framework, version 1.5.0_rc1
2 * (c) 2005 Sam Stephenson <sam@conio.net>
2 * (c) 2005 Sam Stephenson <sam@conio.net>
3 *
3 *
4 * THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff
5 * against the source tree, available from the Prototype darcs repository.
6 *
7 * Prototype is freely distributable under the terms of an MIT-style license.
4 * Prototype is freely distributable under the terms of an MIT-style license.
8 *
9 * For details, see the Prototype web site: http://prototype.conio.net/
5 * For details, see the Prototype web site: http://prototype.conio.net/
10 *
6 *
11 /*--------------------------------------------------------------------------*/
7 /*--------------------------------------------------------------------------*/
12
8
13 var Prototype = {
9 var Prototype = {
14 Version: '1.4.0',
10 Version: '1.5.0_rc1',
15 ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
11 BrowserFeatures: {
12 XPath: !!document.evaluate
13 },
16
14
15 ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
17 emptyFunction: function() {},
16 emptyFunction: function() {},
18 K: function(x) {return x}
17 K: function(x) { return x }
19 }
18 }
20
19
21 var Class = {
20 var Class = {
@@ -29,22 +28,42 var Class = {
29 var Abstract = new Object();
28 var Abstract = new Object();
30
29
31 Object.extend = function(destination, source) {
30 Object.extend = function(destination, source) {
32 for (property in source) {
31 for (var property in source) {
33 destination[property] = source[property];
32 destination[property] = source[property];
34 }
33 }
35 return destination;
34 return destination;
36 }
35 }
37
36
38 Object.inspect = function(object) {
37 Object.extend(Object, {
39 try {
38 inspect: function(object) {
40 if (object == undefined) return 'undefined';
39 try {
41 if (object == null) return 'null';
40 if (object === undefined) return 'undefined';
42 return object.inspect ? object.inspect() : object.toString();
41 if (object === null) return 'null';
43 } catch (e) {
42 return object.inspect ? object.inspect() : object.toString();
44 if (e instanceof RangeError) return '...';
43 } catch (e) {
45 throw 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);
46 }
65 }
47 }
66 });
48
67
49 Function.prototype.bind = function() {
68 Function.prototype.bind = function() {
50 var __method = this, args = $A(arguments), object = args.shift();
69 var __method = this, args = $A(arguments), object = args.shift();
@@ -54,9 +73,9 Function.prototype.bind = function() {
54 }
73 }
55
74
56 Function.prototype.bindAsEventListener = function(object) {
75 Function.prototype.bindAsEventListener = function(object) {
57 var __method = this;
76 var __method = this, args = $A(arguments), object = args.shift();
58 return function(event) {
77 return function(event) {
59 return __method.call(object, event || window.event);
78 return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));
60 }
79 }
61 }
80 }
62
81
@@ -106,40 +125,69 PeriodicalExecuter.prototype = {
106 },
125 },
107
126
108 registerCallback: function() {
127 registerCallback: function() {
109 setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
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;
110 },
135 },
111
136
112 onTimerEvent: function() {
137 onTimerEvent: function() {
113 if (!this.currentlyExecuting) {
138 if (!this.currentlyExecuting) {
114 try {
139 try {
115 this.currentlyExecuting = true;
140 this.currentlyExecuting = true;
116 this.callback();
141 this.callback(this);
117 } finally {
142 } finally {
118 this.currentlyExecuting = false;
143 this.currentlyExecuting = false;
119 }
144 }
120 }
145 }
121 }
146 }
122 }
147 }
148 Object.extend(String.prototype, {
149 gsub: function(pattern, replacement) {
150 var result = '', source = this, match;
151 replacement = arguments.callee.prepareReplacement(replacement);
152
153 while (source.length > 0) {
154 if (match = source.match(pattern)) {
155 result += source.slice(0, match.index);
156 result += (replacement(match) || '').toString();
157 source = source.slice(match.index + match[0].length);
158 } else {
159 result += source, source = '';
160 }
161 }
162 return result;
163 },
123
164
124 /*--------------------------------------------------------------------------*/
165 sub: function(pattern, replacement, count) {
166 replacement = this.gsub.prepareReplacement(replacement);
167 count = count === undefined ? 1 : count;
125
168
126 function $() {
169 return this.gsub(pattern, function(match) {
127 var elements = new Array();
170 if (--count < 0) return match[0];
171 return replacement(match);
172 });
173 },
128
174
129 for (var i = 0; i < arguments.length; i++) {
175 scan: function(pattern, iterator) {
130 var element = arguments[i];
176 this.gsub(pattern, iterator);
131 if (typeof element == 'string')
177 return this;
132 element = document.getElementById(element);
178 },
133
179
134 if (arguments.length == 1)
180 truncate: function(length, truncation) {
135 return element;
181 length = length || 30;
182 truncation = truncation === undefined ? '...' : truncation;
183 return this.length > length ?
184 this.slice(0, length - truncation.length) + truncation : this;
185 },
136
186
137 elements.push(element);
187 strip: function() {
138 }
188 return this.replace(/^\s+/, '').replace(/\s+$/, '');
189 },
139
190
140 return elements;
141 }
142 Object.extend(String.prototype, {
143 stripTags: function() {
191 stripTags: function() {
144 return this.replace(/<\/?[^>]+>/gi, '');
192 return this.replace(/<\/?[^>]+>/gi, '');
145 },
193 },
@@ -157,7 +205,7 Object.extend(String.prototype, {
157 },
205 },
158
206
159 evalScripts: function() {
207 evalScripts: function() {
160 return this.extractScripts().map(eval);
208 return this.extractScripts().map(function(script) { return eval(script) });
161 },
209 },
162
210
163 escapeHTML: function() {
211 escapeHTML: function() {
@@ -174,10 +222,13 Object.extend(String.prototype, {
174 },
222 },
175
223
176 toQueryParams: function() {
224 toQueryParams: function() {
177 var pairs = this.match(/^\??(.*)$/)[1].split('&');
225 var match = this.strip().match(/[^?]*$/)[0];
226 if (!match) return {};
227 var pairs = match.split('&');
178 return pairs.inject({}, function(params, pairString) {
228 return pairs.inject({}, function(params, pairString) {
179 var pair = pairString.split('=');
229 var pair = pairString.split('=');
180 params[pair[0]] = pair[1];
230 var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
231 params[decodeURIComponent(pair[0])] = value;
181 return params;
232 return params;
182 });
233 });
183 },
234 },
@@ -194,7 +245,7 Object.extend(String.prototype, {
194 ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
245 ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
195 : oStringList[0];
246 : oStringList[0];
196
247
197 for (var i = 1, len = oStringList.length; i < len; i++) {
248 for (var i = 1, length = oStringList.length; i < length; i++) {
198 var s = oStringList[i];
249 var s = oStringList[i];
199 camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
250 camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
200 }
251 }
@@ -202,13 +253,40 Object.extend(String.prototype, {
202 return camelizedString;
253 return camelizedString;
203 },
254 },
204
255
205 inspect: function() {
256 inspect: function(useDoubleQuotes) {
206 return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'";
257 var escapedString = this.replace(/\\/g, '\\\\');
258 if (useDoubleQuotes)
259 return '"' + escapedString.replace(/"/g, '\\"') + '"';
260 else
261 return "'" + escapedString.replace(/'/g, '\\\'') + "'";
207 }
262 }
208 });
263 });
209
264
265 String.prototype.gsub.prepareReplacement = function(replacement) {
266 if (typeof replacement == 'function') return replacement;
267 var template = new Template(replacement);
268 return function(match) { return template.evaluate(match) };
269 }
270
210 String.prototype.parseQuery = String.prototype.toQueryParams;
271 String.prototype.parseQuery = String.prototype.toQueryParams;
211
272
273 var Template = Class.create();
274 Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
275 Template.prototype = {
276 initialize: function(template, pattern) {
277 this.template = template.toString();
278 this.pattern = pattern || Template.Pattern;
279 },
280
281 evaluate: function(object) {
282 return this.template.gsub(this.pattern, function(match) {
283 var before = match[1];
284 if (before == '\\') return match[2];
285 return before + (object[match[3]] || '').toString();
286 });
287 }
288 }
289
212 var $break = new Object();
290 var $break = new Object();
213 var $continue = new Object();
291 var $continue = new Object();
214
292
@@ -226,6 +304,14 var Enumerable = {
226 } catch (e) {
304 } catch (e) {
227 if (e != $break) throw e;
305 if (e != $break) throw e;
228 }
306 }
307 return this;
308 },
309
310 eachSlice: function(number, iterator) {
311 var index = -number, slices = [], array = this.toArray();
312 while ((index += number) < array.length)
313 slices.push(array.slice(index, index+number));
314 return slices.collect(iterator || Prototype.K);
229 },
315 },
230
316
231 all: function(iterator) {
317 all: function(iterator) {
@@ -238,7 +324,7 var Enumerable = {
238 },
324 },
239
325
240 any: function(iterator) {
326 any: function(iterator) {
241 var result = true;
327 var result = false;
242 this.each(function(value, index) {
328 this.each(function(value, index) {
243 if (result = !!(iterator || Prototype.K)(value, index))
329 if (result = !!(iterator || Prototype.K)(value, index))
244 throw $break;
330 throw $break;
@@ -254,7 +340,7 var Enumerable = {
254 return results;
340 return results;
255 },
341 },
256
342
257 detect: function (iterator) {
343 detect: function(iterator) {
258 var result;
344 var result;
259 this.each(function(value, index) {
345 this.each(function(value, index) {
260 if (iterator(value, index)) {
346 if (iterator(value, index)) {
@@ -295,6 +381,15 var Enumerable = {
295 return found;
381 return found;
296 },
382 },
297
383
384 inGroupsOf: function(number, fillWith) {
385 fillWith = fillWith || null;
386 var results = this.eachSlice(number);
387 if (results.length > 0) (number - results.last().length).times(function() {
388 results.last().push(fillWith)
389 });
390 return results;
391 },
392
298 inject: function(memo, iterator) {
393 inject: function(memo, iterator) {
299 this.each(function(value, index) {
394 this.each(function(value, index) {
300 memo = iterator(memo, value, index);
395 memo = iterator(memo, value, index);
@@ -313,7 +408,7 var Enumerable = {
313 var result;
408 var result;
314 this.each(function(value, index) {
409 this.each(function(value, index) {
315 value = (iterator || Prototype.K)(value, index);
410 value = (iterator || Prototype.K)(value, index);
316 if (value >= (result || value))
411 if (result == undefined || value >= result)
317 result = value;
412 result = value;
318 });
413 });
319 return result;
414 return result;
@@ -323,7 +418,7 var Enumerable = {
323 var result;
418 var result;
324 this.each(function(value, index) {
419 this.each(function(value, index) {
325 value = (iterator || Prototype.K)(value, index);
420 value = (iterator || Prototype.K)(value, index);
326 if (value <= (result || value))
421 if (result == undefined || value < result)
327 result = value;
422 result = value;
328 });
423 });
329 return result;
424 return result;
@@ -375,8 +470,7 var Enumerable = {
375
470
376 var collections = [this].concat(args).map($A);
471 var collections = [this].concat(args).map($A);
377 return this.map(function(value, index) {
472 return this.map(function(value, index) {
378 iterator(value = collections.pluck(index));
473 return iterator(collections.pluck(index));
379 return value;
380 });
474 });
381 },
475 },
382
476
@@ -398,7 +492,7 var $A = Array.from = function(iterable) {
398 return iterable.toArray();
492 return iterable.toArray();
399 } else {
493 } else {
400 var results = [];
494 var results = [];
401 for (var i = 0; i < iterable.length; i++)
495 for (var i = 0, length = iterable.length; i < length; i++)
402 results.push(iterable[i]);
496 results.push(iterable[i]);
403 return results;
497 return results;
404 }
498 }
@@ -406,11 +500,12 var $A = Array.from = function(iterable) {
406
500
407 Object.extend(Array.prototype, Enumerable);
501 Object.extend(Array.prototype, Enumerable);
408
502
409 Array.prototype._reverse = Array.prototype.reverse;
503 if (!Array.prototype._reverse)
504 Array.prototype._reverse = Array.prototype.reverse;
410
505
411 Object.extend(Array.prototype, {
506 Object.extend(Array.prototype, {
412 _each: function(iterator) {
507 _each: function(iterator) {
413 for (var i = 0; i < this.length; i++)
508 for (var i = 0, length = this.length; i < length; i++)
414 iterator(this[i]);
509 iterator(this[i]);
415 },
510 },
416
511
@@ -435,7 +530,7 Object.extend(Array.prototype, {
435
530
436 flatten: function() {
531 flatten: function() {
437 return this.inject([], function(array, value) {
532 return this.inject([], function(array, value) {
438 return array.concat(value.constructor == Array ?
533 return array.concat(value && value.constructor == Array ?
439 value.flatten() : [value]);
534 value.flatten() : [value]);
440 });
535 });
441 },
536 },
@@ -448,7 +543,7 Object.extend(Array.prototype, {
448 },
543 },
449
544
450 indexOf: function(object) {
545 indexOf: function(object) {
451 for (var i = 0; i < this.length; i++)
546 for (var i = 0, length = this.length; i < length; i++)
452 if (this[i] == object) return i;
547 if (this[i] == object) return i;
453 return -1;
548 return -1;
454 },
549 },
@@ -457,21 +552,29 Object.extend(Array.prototype, {
457 return (inline !== false ? this : this.toArray())._reverse();
552 return (inline !== false ? this : this.toArray())._reverse();
458 },
553 },
459
554
460 shift: function() {
555 reduce: function() {
461 var result = this[0];
556 return this.length > 1 ? this : this[0];
462 for (var i = 0; i < this.length - 1; i++)
557 },
463 this[i] = this[i + 1];
558
464 this.length--;
559 uniq: function() {
465 return result;
560 return this.inject([], function(array, value) {
561 return array.include(value) ? array : array.concat([value]);
562 });
563 },
564
565 clone: function() {
566 return [].concat(this);
466 },
567 },
467
568
468 inspect: function() {
569 inspect: function() {
469 return '[' + this.map(Object.inspect).join(', ') + ']';
570 return '[' + this.map(Object.inspect).join(', ') + ']';
470 }
571 }
471 });
572 });
573
574 Array.prototype.toArray = Array.prototype.clone;
472 var Hash = {
575 var Hash = {
473 _each: function(iterator) {
576 _each: function(iterator) {
474 for (key in this) {
577 for (var key in this) {
475 var value = this[key];
578 var value = this[key];
476 if (typeof value == 'function') continue;
579 if (typeof value == 'function') continue;
477
580
@@ -491,7 +594,7 var Hash = {
491 },
594 },
492
595
493 merge: function(hash) {
596 merge: function(hash) {
494 return $H(hash).inject($H(this), function(mergedHash, pair) {
597 return $H(hash).inject(this, function(mergedHash, pair) {
495 mergedHash[pair.key] = pair.value;
598 mergedHash[pair.key] = pair.value;
496 return mergedHash;
599 return mergedHash;
497 });
600 });
@@ -499,6 +602,8 var Hash = {
499
602
500 toQueryString: function() {
603 toQueryString: function() {
501 return this.map(function(pair) {
604 return this.map(function(pair) {
605 if (!pair.value && pair.value !== 0) pair[1] = '';
606 if (!pair.key) return;
502 return pair.map(encodeURIComponent).join('=');
607 return pair.map(encodeURIComponent).join('=');
503 }).join('&');
608 }).join('&');
504 },
609 },
@@ -527,10 +632,10 Object.extend(ObjectRange.prototype, {
527
632
528 _each: function(iterator) {
633 _each: function(iterator) {
529 var value = this.start;
634 var value = this.start;
530 do {
635 while (this.include(value)) {
531 iterator(value);
636 iterator(value);
532 value = value.succ();
637 value = value.succ();
533 } while (this.include(value));
638 }
534 },
639 },
535
640
536 include: function(value) {
641 include: function(value) {
@@ -549,9 +654,9 var $R = function(start, end, exclusive) {
549 var Ajax = {
654 var Ajax = {
550 getTransport: function() {
655 getTransport: function() {
551 return Try.these(
656 return Try.these(
657 function() {return new XMLHttpRequest()},
552 function() {return new ActiveXObject('Msxml2.XMLHTTP')},
658 function() {return new ActiveXObject('Msxml2.XMLHTTP')},
553 function() {return new ActiveXObject('Microsoft.XMLHTTP')},
659 function() {return new ActiveXObject('Microsoft.XMLHTTP')}
554 function() {return new XMLHttpRequest()}
555 ) || false;
660 ) || false;
556 },
661 },
557
662
@@ -565,18 +670,18 Ajax.Responders = {
565 this.responders._each(iterator);
670 this.responders._each(iterator);
566 },
671 },
567
672
568 register: function(responderToAdd) {
673 register: function(responder) {
569 if (!this.include(responderToAdd))
674 if (!this.include(responder))
570 this.responders.push(responderToAdd);
675 this.responders.push(responder);
571 },
676 },
572
677
573 unregister: function(responderToRemove) {
678 unregister: function(responder) {
574 this.responders = this.responders.without(responderToRemove);
679 this.responders = this.responders.without(responder);
575 },
680 },
576
681
577 dispatch: function(callback, request, transport, json) {
682 dispatch: function(callback, request, transport, json) {
578 this.each(function(responder) {
683 this.each(function(responder) {
579 if (responder[callback] && typeof responder[callback] == 'function') {
684 if (typeof responder[callback] == 'function') {
580 try {
685 try {
581 responder[callback].apply(responder, [request, transport, json]);
686 responder[callback].apply(responder, [request, transport, json]);
582 } catch (e) {}
687 } catch (e) {}
@@ -591,7 +696,6 Ajax.Responders.register({
591 onCreate: function() {
696 onCreate: function() {
592 Ajax.activeRequestCount++;
697 Ajax.activeRequestCount++;
593 },
698 },
594
595 onComplete: function() {
699 onComplete: function() {
596 Ajax.activeRequestCount--;
700 Ajax.activeRequestCount--;
597 }
701 }
@@ -603,19 +707,15 Ajax.Base.prototype = {
603 this.options = {
707 this.options = {
604 method: 'post',
708 method: 'post',
605 asynchronous: true,
709 asynchronous: true,
710 contentType: 'application/x-www-form-urlencoded',
711 encoding: 'UTF-8',
606 parameters: ''
712 parameters: ''
607 }
713 }
608 Object.extend(this.options, options || {});
714 Object.extend(this.options, options || {});
609 },
610
611 responseIsSuccess: function() {
612 return this.transport.status == undefined
613 || this.transport.status == 0
614 || (this.transport.status >= 200 && this.transport.status < 300);
615 },
616
715
617 responseIsFailure: function() {
716 this.options.method = this.options.method.toLowerCase();
618 return !this.responseIsSuccess();
717 this.options.parameters = $H(typeof this.options.parameters == 'string' ?
718 this.options.parameters.toQueryParams() : this.options.parameters);
619 }
719 }
620 }
720 }
621
721
@@ -631,111 +731,145 Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
631 },
731 },
632
732
633 request: function(url) {
733 request: function(url) {
634 var parameters = this.options.parameters || '';
734 var params = this.options.parameters;
635 if (parameters.length > 0) parameters += '&_=';
735 if (params.any()) params['_'] = '';
636
736
637 try {
737 if (!['get', 'post'].include(this.options.method)) {
638 this.url = url;
738 // simulate other verbs over post
639 if (this.options.method == 'get' && parameters.length > 0)
739 params['_method'] = this.options.method;
640 this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
740 this.options.method = 'post';
741 }
742
743 this.url = url;
744
745 // when GET, append parameters to URL
746 if (this.options.method == 'get' && params.any())
747 this.url += (this.url.indexOf('?') >= 0 ? '&' : '?') +
748 params.toQueryString();
641
749
750 try {
642 Ajax.Responders.dispatch('onCreate', this, this.transport);
751 Ajax.Responders.dispatch('onCreate', this, this.transport);
643
752
644 this.transport.open(this.options.method, this.url,
753 this.transport.open(this.options.method.toUpperCase(), this.url,
645 this.options.asynchronous);
754 this.options.asynchronous, this.options.username,
755 this.options.password);
646
756
647 if (this.options.asynchronous) {
757 if (this.options.asynchronous)
648 this.transport.onreadystatechange = this.onStateChange.bind(this);
758 setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
649 setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
650 }
651
759
760 this.transport.onreadystatechange = this.onStateChange.bind(this);
652 this.setRequestHeaders();
761 this.setRequestHeaders();
653
762
654 var body = this.options.postBody ? this.options.postBody : parameters;
763 var body = this.options.method == 'post' ?
655 this.transport.send(this.options.method == 'post' ? body : null);
764 (this.options.postBody || params.toQueryString()) : null;
656
765
657 } catch (e) {
766 this.transport.send(body);
767
768 /* Force Firefox to handle ready state 4 for synchronous requests */
769 if (!this.options.asynchronous && this.transport.overrideMimeType)
770 this.onStateChange();
771 }
772 catch (e) {
658 this.dispatchException(e);
773 this.dispatchException(e);
659 }
774 }
660 },
775 },
661
776
777 onStateChange: function() {
778 var readyState = this.transport.readyState;
779 if (readyState > 1)
780 this.respondToReadyState(this.transport.readyState);
781 },
782
662 setRequestHeaders: function() {
783 setRequestHeaders: function() {
663 var requestHeaders =
784 var headers = {
664 ['X-Requested-With', 'XMLHttpRequest',
785 'X-Requested-With': 'XMLHttpRequest',
665 'X-Prototype-Version', Prototype.Version];
786 'X-Prototype-Version': Prototype.Version,
787 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
788 };
666
789
667 if (this.options.method == 'post') {
790 if (this.options.method == 'post') {
668 requestHeaders.push('Content-type',
791 headers['Content-type'] = this.options.contentType +
669 'application/x-www-form-urlencoded');
792 (this.options.encoding ? '; charset=' + this.options.encoding : '');
670
793
671 /* Force "Connection: close" for Mozilla browsers to work around
794 /* Force "Connection: close" for older Mozilla browsers to work
672 * a bug where XMLHttpReqeuest sends an incorrect Content-length
795 * around a bug where XMLHttpRequest sends an incorrect
673 * header. See Mozilla Bugzilla #246651.
796 * Content-length header. See Mozilla Bugzilla #246651.
674 */
797 */
675 if (this.transport.overrideMimeType)
798 if (this.transport.overrideMimeType &&
676 requestHeaders.push('Connection', 'close');
799 (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
800 headers['Connection'] = 'close';
677 }
801 }
678
802
679 if (this.options.requestHeaders)
803 // user-defined headers
680 requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
804 if (typeof this.options.requestHeaders == 'object') {
805 var extras = this.options.requestHeaders;
681
806
682 for (var i = 0; i < requestHeaders.length; i += 2)
807 if (typeof extras.push == 'function')
683 this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
808 for (var i = 0; i < extras.length; i += 2)
684 },
809 headers[extras[i]] = extras[i+1];
685
810 else
686 onStateChange: function() {
811 $H(extras).each(function(pair) { headers[pair.key] = pair.value });
687 var readyState = this.transport.readyState;
812 }
688 if (readyState != 1)
689 this.respondToReadyState(this.transport.readyState);
690 },
691
692 header: function(name) {
693 try {
694 return this.transport.getResponseHeader(name);
695 } catch (e) {}
696 },
697
813
698 evalJSON: function() {
814 for (var name in headers)
699 try {
815 this.transport.setRequestHeader(name, headers[name]);
700 return eval(this.header('X-JSON'));
701 } catch (e) {}
702 },
816 },
703
817
704 evalResponse: function() {
818 success: function() {
705 try {
819 return !this.transport.status
706 return eval(this.transport.responseText);
820 || (this.transport.status >= 200 && this.transport.status < 300);
707 } catch (e) {
708 this.dispatchException(e);
709 }
710 },
821 },
711
822
712 respondToReadyState: function(readyState) {
823 respondToReadyState: function(readyState) {
713 var event = Ajax.Request.Events[readyState];
824 var state = Ajax.Request.Events[readyState];
714 var transport = this.transport, json = this.evalJSON();
825 var transport = this.transport, json = this.evalJSON();
715
826
716 if (event == 'Complete') {
827 if (state == 'Complete') {
717 try {
828 try {
718 (this.options['on' + this.transport.status]
829 (this.options['on' + this.transport.status]
719 || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
830 || this.options['on' + (this.success() ? 'Success' : 'Failure')]
720 || Prototype.emptyFunction)(transport, json);
831 || Prototype.emptyFunction)(transport, json);
721 } catch (e) {
832 } catch (e) {
722 this.dispatchException(e);
833 this.dispatchException(e);
723 }
834 }
724
725 if ((this.header('Content-type') || '').match(/^text\/javascript/i))
726 this.evalResponse();
727 }
835 }
728
836
729 try {
837 try {
730 (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
838 (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
731 Ajax.Responders.dispatch('on' + event, this, transport, json);
839 Ajax.Responders.dispatch('on' + state, this, transport, json);
732 } catch (e) {
840 } catch (e) {
733 this.dispatchException(e);
841 this.dispatchException(e);
734 }
842 }
735
843
736 /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
844 if (state == 'Complete') {
737 if (event == 'Complete')
845 if ((this.getHeader('Content-type') || '').strip().
846 match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
847 this.evalResponse();
848
849 // avoid memory leak in MSIE: clean up
738 this.transport.onreadystatechange = Prototype.emptyFunction;
850 this.transport.onreadystatechange = Prototype.emptyFunction;
851 }
852 },
853
854 getHeader: function(name) {
855 try {
856 return this.transport.getResponseHeader(name);
857 } catch (e) { return null }
858 },
859
860 evalJSON: function() {
861 try {
862 var json = this.getHeader('X-JSON');
863 return json ? eval('(' + json + ')') : null;
864 } catch (e) { return null }
865 },
866
867 evalResponse: function() {
868 try {
869 return eval(this.transport.responseText);
870 } catch (e) {
871 this.dispatchException(e);
872 }
739 },
873 },
740
874
741 dispatchException: function(exception) {
875 dispatchException: function(exception) {
@@ -748,41 +882,37 Ajax.Updater = Class.create();
748
882
749 Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
883 Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
750 initialize: function(container, url, options) {
884 initialize: function(container, url, options) {
751 this.containers = {
885 this.container = {
752 success: container.success ? $(container.success) : $(container),
886 success: (container.success || container),
753 failure: container.failure ? $(container.failure) :
887 failure: (container.failure || (container.success ? null : container))
754 (container.success ? null : $(container))
755 }
888 }
756
889
757 this.transport = Ajax.getTransport();
890 this.transport = Ajax.getTransport();
758 this.setOptions(options);
891 this.setOptions(options);
759
892
760 var onComplete = this.options.onComplete || Prototype.emptyFunction;
893 var onComplete = this.options.onComplete || Prototype.emptyFunction;
761 this.options.onComplete = (function(transport, object) {
894 this.options.onComplete = (function(transport, param) {
762 this.updateContent();
895 this.updateContent();
763 onComplete(transport, object);
896 onComplete(transport, param);
764 }).bind(this);
897 }).bind(this);
765
898
766 this.request(url);
899 this.request(url);
767 },
900 },
768
901
769 updateContent: function() {
902 updateContent: function() {
770 var receiver = this.responseIsSuccess() ?
903 var receiver = this.container[this.success() ? 'success' : 'failure'];
771 this.containers.success : this.containers.failure;
772 var response = this.transport.responseText;
904 var response = this.transport.responseText;
773
905
774 if (!this.options.evalScripts)
906 if (!this.options.evalScripts) response = response.stripScripts();
775 response = response.stripScripts();
776
907
777 if (receiver) {
908 if (receiver = $(receiver)) {
778 if (this.options.insertion) {
909 if (this.options.insertion)
779 new this.options.insertion(receiver, response);
910 new this.options.insertion(receiver, response);
780 } else {
911 else
781 Element.update(receiver, response);
912 receiver.update(response);
782 }
783 }
913 }
784
914
785 if (this.responseIsSuccess()) {
915 if (this.success()) {
786 if (this.onComplete)
916 if (this.onComplete)
787 setTimeout(this.onComplete.bind(this), 10);
917 setTimeout(this.onComplete.bind(this), 10);
788 }
918 }
@@ -811,7 +941,7 Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
811 },
941 },
812
942
813 stop: function() {
943 stop: function() {
814 this.updater.onComplete = undefined;
944 this.updater.options.onComplete = undefined;
815 clearTimeout(this.timer);
945 clearTimeout(this.timer);
816 (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
946 (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
817 },
947 },
@@ -831,55 +961,208 Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
831 this.updater = new Ajax.Updater(this.container, this.url, this.options);
961 this.updater = new Ajax.Updater(this.container, this.url, this.options);
832 }
962 }
833 });
963 });
964 function $(element) {
965 if (arguments.length > 1) {
966 for (var i = 0, elements = [], length = arguments.length; i < length; i++)
967 elements.push($(arguments[i]));
968 return elements;
969 }
970 if (typeof element == 'string')
971 element = document.getElementById(element);
972 return Element.extend(element);
973 }
974
975 if (Prototype.BrowserFeatures.XPath) {
976 document._getElementsByXPath = function(expression, parentElement) {
977 var results = [];
978 var query = document.evaluate(expression, $(parentElement) || document,
979 null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
980 for (var i = 0, len = query.snapshotLength; i < len; i++)
981 results.push(query.snapshotItem(i));
982 return results;
983 }
984 }
985
834 document.getElementsByClassName = function(className, parentElement) {
986 document.getElementsByClassName = function(className, parentElement) {
835 var children = ($(parentElement) || document.body).getElementsByTagName('*');
987 if (Prototype.BrowserFeatures.XPath) {
836 return $A(children).inject([], function(elements, child) {
988 var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
837 if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
989 return document._getElementsByXPath(q, parentElement);
838 elements.push(child);
990 } else {
991 var children = ($(parentElement) || document.body).getElementsByTagName('*');
992 var elements = [], child;
993 for (var i = 0, length = children.length; i < length; i++) {
994 child = children[i];
995 if (Element.hasClassName(child, className))
996 elements.push(Element.extend(child));
997 }
839 return elements;
998 return elements;
840 });
999 }
841 }
1000 }
842
1001
843 /*--------------------------------------------------------------------------*/
1002 /*--------------------------------------------------------------------------*/
844
1003
845 if (!window.Element) {
1004 if (!window.Element)
846 var Element = new Object();
1005 var Element = new Object();
1006
1007 Element.extend = function(element) {
1008 if (!element) return;
1009 if (_nativeExtensions || element.nodeType == 3) return element;
1010
1011 if (!element._extended && element.tagName && element != window) {
1012 var methods = Object.clone(Element.Methods), cache = Element.extend.cache;
1013
1014 if (element.tagName == 'FORM')
1015 Object.extend(methods, Form.Methods);
1016 if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
1017 Object.extend(methods, Form.Element.Methods);
1018
1019 for (var property in methods) {
1020 var value = methods[property];
1021 if (typeof value == 'function')
1022 element[property] = cache.findOrStore(value);
1023 }
1024
1025 var methods = Object.clone(Element.Methods.Simulated), cache = Element.extend.cache;
1026 for (var property in methods) {
1027 var value = methods[property];
1028 if ('function' == typeof value && !(property in element))
1029 element[property] = cache.findOrStore(value);
1030 }
1031 }
1032
1033 element._extended = true;
1034 return element;
847 }
1035 }
848
1036
849 Object.extend(Element, {
1037 Element.extend.cache = {
1038 findOrStore: function(value) {
1039 return this[value] = this[value] || function() {
1040 return value.apply(null, [this].concat($A(arguments)));
1041 }
1042 }
1043 }
1044
1045 Element.Methods = {
850 visible: function(element) {
1046 visible: function(element) {
851 return $(element).style.display != 'none';
1047 return $(element).style.display != 'none';
852 },
1048 },
853
1049
854 toggle: function() {
1050 toggle: function(element) {
855 for (var i = 0; i < arguments.length; i++) {
1051 element = $(element);
856 var element = $(arguments[i]);
1052 Element[Element.visible(element) ? 'hide' : 'show'](element);
857 Element[Element.visible(element) ? 'hide' : 'show'](element);
1053 return element;
858 }
859 },
1054 },
860
1055
861 hide: function() {
1056 hide: function(element) {
862 for (var i = 0; i < arguments.length; i++) {
1057 $(element).style.display = 'none';
863 var element = $(arguments[i]);
1058 return element;
864 element.style.display = 'none';
865 }
866 },
1059 },
867
1060
868 show: function() {
1061 show: function(element) {
869 for (var i = 0; i < arguments.length; i++) {
1062 $(element).style.display = '';
870 var element = $(arguments[i]);
1063 return element;
871 element.style.display = '';
872 }
873 },
1064 },
874
1065
875 remove: function(element) {
1066 remove: function(element) {
876 element = $(element);
1067 element = $(element);
877 element.parentNode.removeChild(element);
1068 element.parentNode.removeChild(element);
1069 return element;
878 },
1070 },
879
1071
880 update: function(element, html) {
1072 update: function(element, html) {
1073 html = typeof html == 'undefined' ? '' : html.toString();
881 $(element).innerHTML = html.stripScripts();
1074 $(element).innerHTML = html.stripScripts();
882 setTimeout(function() {html.evalScripts()}, 10);
1075 setTimeout(function() {html.evalScripts()}, 10);
1076 return element;
1077 },
1078
1079 replace: function(element, html) {
1080 element = $(element);
1081 if (element.outerHTML) {
1082 element.outerHTML = html.stripScripts();
1083 } else {
1084 var range = element.ownerDocument.createRange();
1085 range.selectNodeContents(element);
1086 element.parentNode.replaceChild(
1087 range.createContextualFragment(html.stripScripts()), element);
1088 }
1089 setTimeout(function() {html.evalScripts()}, 10);
1090 return element;
1091 },
1092
1093 inspect: function(element) {
1094 element = $(element);
1095 var result = '<' + element.tagName.toLowerCase();
1096 $H({'id': 'id', 'className': 'class'}).each(function(pair) {
1097 var property = pair.first(), attribute = pair.last();
1098 var value = (element[property] || '').toString();
1099 if (value) result += ' ' + attribute + '=' + value.inspect(true);
1100 });
1101 return result + '>';
1102 },
1103
1104 recursivelyCollect: function(element, property) {
1105 element = $(element);
1106 var elements = [];
1107 while (element = element[property])
1108 if (element.nodeType == 1)
1109 elements.push(Element.extend(element));
1110 return elements;
1111 },
1112
1113 ancestors: function(element) {
1114 return $(element).recursivelyCollect('parentNode');
1115 },
1116
1117 descendants: function(element) {
1118 element = $(element);
1119 return $A(element.getElementsByTagName('*'));
1120 },
1121
1122 previousSiblings: function(element) {
1123 return $(element).recursivelyCollect('previousSibling');
1124 },
1125
1126 nextSiblings: function(element) {
1127 return $(element).recursivelyCollect('nextSibling');
1128 },
1129
1130 siblings: function(element) {
1131 element = $(element);
1132 return element.previousSiblings().reverse().concat(element.nextSiblings());
1133 },
1134
1135 match: function(element, selector) {
1136 element = $(element);
1137 if (typeof selector == 'string')
1138 selector = new Selector(selector);
1139 return selector.match(element);
1140 },
1141
1142 up: function(element, expression, index) {
1143 return Selector.findElement($(element).ancestors(), expression, index);
1144 },
1145
1146 down: function(element, expression, index) {
1147 return Selector.findElement($(element).descendants(), expression, index);
1148 },
1149
1150 previous: function(element, expression, index) {
1151 return Selector.findElement($(element).previousSiblings(), expression, index);
1152 },
1153
1154 next: function(element, expression, index) {
1155 return Selector.findElement($(element).nextSiblings(), expression, index);
1156 },
1157
1158 getElementsBySelector: function() {
1159 var args = $A(arguments), element = $(args.shift());
1160 return Selector.findChildElements(element, args);
1161 },
1162
1163 getElementsByClassName: function(element, className) {
1164 element = $(element);
1165 return document.getElementsByClassName(className, element);
883 },
1166 },
884
1167
885 getHeight: function(element) {
1168 getHeight: function(element) {
@@ -893,38 +1176,66 Object.extend(Element, {
893
1176
894 hasClassName: function(element, className) {
1177 hasClassName: function(element, className) {
895 if (!(element = $(element))) return;
1178 if (!(element = $(element))) return;
896 return Element.classNames(element).include(className);
1179 var elementClassName = element.className;
1180 if (elementClassName.length == 0) return false;
1181 if (elementClassName == className ||
1182 elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
1183 return true;
1184 return false;
897 },
1185 },
898
1186
899 addClassName: function(element, className) {
1187 addClassName: function(element, className) {
900 if (!(element = $(element))) return;
1188 if (!(element = $(element))) return;
901 return Element.classNames(element).add(className);
1189 Element.classNames(element).add(className);
1190 return element;
902 },
1191 },
903
1192
904 removeClassName: function(element, className) {
1193 removeClassName: function(element, className) {
905 if (!(element = $(element))) return;
1194 if (!(element = $(element))) return;
906 return Element.classNames(element).remove(className);
1195 Element.classNames(element).remove(className);
1196 return element;
1197 },
1198
1199 observe: function() {
1200 Event.observe.apply(Event, arguments);
1201 return $A(arguments).first();
1202 },
1203
1204 stopObserving: function() {
1205 Event.stopObserving.apply(Event, arguments);
1206 return $A(arguments).first();
907 },
1207 },
908
1208
909 // removes whitespace-only text node children
1209 // removes whitespace-only text node children
910 cleanWhitespace: function(element) {
1210 cleanWhitespace: function(element) {
911 element = $(element);
1211 element = $(element);
912 for (var i = 0; i < element.childNodes.length; i++) {
1212 var node = element.firstChild;
913 var node = element.childNodes[i];
1213 while (node) {
1214 var nextNode = node.nextSibling;
914 if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
1215 if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
915 Element.remove(node);
1216 element.removeChild(node);
1217 node = nextNode;
916 }
1218 }
1219 return element;
917 },
1220 },
918
1221
919 empty: function(element) {
1222 empty: function(element) {
920 return $(element).innerHTML.match(/^\s*$/);
1223 return $(element).innerHTML.match(/^\s*$/);
921 },
1224 },
922
1225
1226 childOf: function(element, ancestor) {
1227 element = $(element), ancestor = $(ancestor);
1228 while (element = element.parentNode)
1229 if (element == ancestor) return true;
1230 return false;
1231 },
1232
923 scrollTo: function(element) {
1233 scrollTo: function(element) {
924 element = $(element);
1234 element = $(element);
925 var x = element.x ? element.x : element.offsetLeft,
1235 var x = element.x ? element.x : element.offsetLeft,
926 y = element.y ? element.y : element.offsetTop;
1236 y = element.y ? element.y : element.offsetTop;
927 window.scrollTo(x, y);
1237 window.scrollTo(x, y);
1238 return element;
928 },
1239 },
929
1240
930 getStyle: function(element, style) {
1241 getStyle: function(element, style) {
@@ -947,8 +1258,9 Object.extend(Element, {
947
1258
948 setStyle: function(element, style) {
1259 setStyle: function(element, style) {
949 element = $(element);
1260 element = $(element);
950 for (name in style)
1261 for (var name in style)
951 element.style[name.camelize()] = style[name];
1262 element.style[name.camelize()] = style[name];
1263 return element;
952 },
1264 },
953
1265
954 getDimensions: function(element) {
1266 getDimensions: function(element) {
@@ -985,6 +1297,7 Object.extend(Element, {
985 element.style.left = 0;
1297 element.style.left = 0;
986 }
1298 }
987 }
1299 }
1300 return element;
988 },
1301 },
989
1302
990 undoPositioned: function(element) {
1303 undoPositioned: function(element) {
@@ -997,23 +1310,105 Object.extend(Element, {
997 element.style.bottom =
1310 element.style.bottom =
998 element.style.right = '';
1311 element.style.right = '';
999 }
1312 }
1313 return element;
1000 },
1314 },
1001
1315
1002 makeClipping: function(element) {
1316 makeClipping: function(element) {
1003 element = $(element);
1317 element = $(element);
1004 if (element._overflow) return;
1318 if (element._overflow) return element;
1005 element._overflow = element.style.overflow;
1319 element._overflow = element.style.overflow || 'auto';
1006 if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
1320 if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
1007 element.style.overflow = 'hidden';
1321 element.style.overflow = 'hidden';
1322 return element;
1008 },
1323 },
1009
1324
1010 undoClipping: function(element) {
1325 undoClipping: function(element) {
1011 element = $(element);
1326 element = $(element);
1012 if (element._overflow) return;
1327 if (!element._overflow) return element;
1013 element.style.overflow = element._overflow;
1328 element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
1014 element._overflow = undefined;
1329 element._overflow = null;
1330 return element;
1015 }
1331 }
1016 });
1332 }
1333
1334 Element.Methods.Simulated = {
1335 hasAttribute: function(element, attribute) {
1336 return $(element).getAttributeNode(attribute).specified;
1337 }
1338 }
1339
1340 // IE is missing .innerHTML support for TABLE-related elements
1341 if(document.all){
1342 Element.Methods.update = function(element, html) {
1343 element = $(element);
1344 html = typeof html == 'undefined' ? '' : html.toString();
1345 var tagName = element.tagName.toUpperCase();
1346 if (['THEAD','TBODY','TR','TD'].indexOf(tagName) > -1) {
1347 var div = document.createElement('div');
1348 switch (tagName) {
1349 case 'THEAD':
1350 case 'TBODY':
1351 div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>';
1352 depth = 2;
1353 break;
1354 case 'TR':
1355 div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>';
1356 depth = 3;
1357 break;
1358 case 'TD':
1359 div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>';
1360 depth = 4;
1361 }
1362 $A(element.childNodes).each(function(node){
1363 element.removeChild(node)
1364 });
1365 depth.times(function(){ div = div.firstChild });
1366
1367 $A(div.childNodes).each(
1368 function(node){ element.appendChild(node) });
1369 } else {
1370 element.innerHTML = html.stripScripts();
1371 }
1372 setTimeout(function() {html.evalScripts()}, 10);
1373 return element;
1374 }
1375 }
1376
1377 Object.extend(Element, Element.Methods);
1378
1379 var _nativeExtensions = false;
1380
1381 if(/Konqueror|Safari|KHTML/.test(navigator.userAgent))
1382 ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) {
1383 var className = 'HTML' + tag + 'Element';
1384 if(window[className]) return;
1385 var klass = window[className] = {};
1386 klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__;
1387 });
1388
1389 Element.addMethods = function(methods) {
1390 Object.extend(Element.Methods, methods || {});
1391
1392 function copy(methods, destination, onlyIfAbsent) {
1393 onlyIfAbsent = onlyIfAbsent || false;
1394 var cache = Element.extend.cache;
1395 for (var property in methods) {
1396 var value = methods[property];
1397 if (!onlyIfAbsent || !(property in destination))
1398 destination[property] = cache.findOrStore(value);
1399 }
1400 }
1401
1402 if (typeof HTMLElement != 'undefined') {
1403 copy(Element.Methods, HTMLElement.prototype);
1404 copy(Element.Methods.Simulated, HTMLElement.prototype, true);
1405 copy(Form.Methods, HTMLFormElement.prototype);
1406 [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
1407 copy(Form.Element.Methods, klass.prototype);
1408 });
1409 _nativeExtensions = true;
1410 }
1411 }
1017
1412
1018 var Toggle = new Object();
1413 var Toggle = new Object();
1019 Toggle.display = Element.toggle;
1414 Toggle.display = Element.toggle;
@@ -1033,7 +1428,8 Abstract.Insertion.prototype = {
1033 try {
1428 try {
1034 this.element.insertAdjacentHTML(this.adjacency, this.content);
1429 this.element.insertAdjacentHTML(this.adjacency, this.content);
1035 } catch (e) {
1430 } catch (e) {
1036 if (this.element.tagName.toLowerCase() == 'tbody') {
1431 var tagName = this.element.tagName.toLowerCase();
1432 if (tagName == 'tbody' || tagName == 'tr') {
1037 this.insertContent(this.contentFromAnonymousTable());
1433 this.insertContent(this.contentFromAnonymousTable());
1038 } else {
1434 } else {
1039 throw e;
1435 throw e;
@@ -1132,76 +1528,176 Element.ClassNames.prototype = {
1132
1528
1133 add: function(classNameToAdd) {
1529 add: function(classNameToAdd) {
1134 if (this.include(classNameToAdd)) return;
1530 if (this.include(classNameToAdd)) return;
1135 this.set(this.toArray().concat(classNameToAdd).join(' '));
1531 this.set($A(this).concat(classNameToAdd).join(' '));
1136 },
1532 },
1137
1533
1138 remove: function(classNameToRemove) {
1534 remove: function(classNameToRemove) {
1139 if (!this.include(classNameToRemove)) return;
1535 if (!this.include(classNameToRemove)) return;
1140 this.set(this.select(function(className) {
1536 this.set($A(this).without(classNameToRemove).join(' '));
1141 return className != classNameToRemove;
1142 }).join(' '));
1143 },
1537 },
1144
1538
1145 toString: function() {
1539 toString: function() {
1146 return this.toArray().join(' ');
1540 return $A(this).join(' ');
1147 }
1541 }
1148 }
1542 }
1149
1543
1150 Object.extend(Element.ClassNames.prototype, Enumerable);
1544 Object.extend(Element.ClassNames.prototype, Enumerable);
1151 var Field = {
1545 var Selector = Class.create();
1152 clear: function() {
1546 Selector.prototype = {
1153 for (var i = 0; i < arguments.length; i++)
1547 initialize: function(expression) {
1154 $(arguments[i]).value = '';
1548 this.params = {classNames: []};
1549 this.expression = expression.toString().strip();
1550 this.parseExpression();
1551 this.compileMatcher();
1155 },
1552 },
1156
1553
1157 focus: function(element) {
1554 parseExpression: function() {
1158 $(element).focus();
1555 function abort(message) { throw 'Parse error in selector: ' + message; }
1556
1557 if (this.expression == '') abort('empty expression');
1558
1559 var params = this.params, expr = this.expression, match, modifier, clause, rest;
1560 while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
1561 params.attributes = params.attributes || [];
1562 params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
1563 expr = match[1];
1564 }
1565
1566 if (expr == '*') return this.params.wildcard = true;
1567
1568 while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
1569 modifier = match[1], clause = match[2], rest = match[3];
1570 switch (modifier) {
1571 case '#': params.id = clause; break;
1572 case '.': params.classNames.push(clause); break;
1573 case '':
1574 case undefined: params.tagName = clause.toUpperCase(); break;
1575 default: abort(expr.inspect());
1576 }
1577 expr = rest;
1578 }
1579
1580 if (expr.length > 0) abort(expr.inspect());
1581 },
1582
1583 buildMatchExpression: function() {
1584 var params = this.params, conditions = [], clause;
1585
1586 if (params.wildcard)
1587 conditions.push('true');
1588 if (clause = params.id)
1589 conditions.push('element.id == ' + clause.inspect());
1590 if (clause = params.tagName)
1591 conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
1592 if ((clause = params.classNames).length > 0)
1593 for (var i = 0; i < clause.length; i++)
1594 conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')');
1595 if (clause = params.attributes) {
1596 clause.each(function(attribute) {
1597 var value = 'element.getAttribute(' + attribute.name.inspect() + ')';
1598 var splitValueBy = function(delimiter) {
1599 return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
1600 }
1601
1602 switch (attribute.operator) {
1603 case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break;
1604 case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
1605 case '|=': conditions.push(
1606 splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
1607 ); break;
1608 case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break;
1609 case '':
1610 case undefined: conditions.push(value + ' != null'); break;
1611 default: throw 'Unknown operator ' + attribute.operator + ' in selector';
1612 }
1613 });
1614 }
1615
1616 return conditions.join(' && ');
1159 },
1617 },
1160
1618
1161 present: function() {
1619 compileMatcher: function() {
1162 for (var i = 0; i < arguments.length; i++)
1620 this.match = new Function('element', 'if (!element.tagName) return false; \
1163 if ($(arguments[i]).value == '') return false;
1621 return ' + this.buildMatchExpression());
1164 return true;
1165 },
1622 },
1166
1623
1167 select: function(element) {
1624 findElements: function(scope) {
1168 $(element).select();
1625 var element;
1626
1627 if (element = $(this.params.id))
1628 if (this.match(element))
1629 if (!scope || Element.childOf(element, scope))
1630 return [element];
1631
1632 scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
1633
1634 var results = [];
1635 for (var i = 0, length = scope.length; i < length; i++)
1636 if (this.match(element = scope[i]))
1637 results.push(Element.extend(element));
1638
1639 return results;
1169 },
1640 },
1170
1641
1171 activate: function(element) {
1642 toString: function() {
1172 element = $(element);
1643 return this.expression;
1173 element.focus();
1174 if (element.select)
1175 element.select();
1176 }
1644 }
1177 }
1645 }
1178
1646
1179 /*--------------------------------------------------------------------------*/
1647 Object.extend(Selector, {
1648 matchElements: function(elements, expression) {
1649 var selector = new Selector(expression);
1650 return elements.select(selector.match.bind(selector)).collect(Element.extend);
1651 },
1180
1652
1653 findElement: function(elements, expression, index) {
1654 if (typeof expression == 'number') index = expression, expression = false;
1655 return Selector.matchElements(elements, expression || '*')[index || 0];
1656 },
1657
1658 findChildElements: function(element, expressions) {
1659 return expressions.map(function(expression) {
1660 return expression.strip().split(/\s+/).inject([null], function(results, expr) {
1661 var selector = new Selector(expr);
1662 return results.inject([], function(elements, result) {
1663 return elements.concat(selector.findElements(result || element));
1664 });
1665 });
1666 }).flatten();
1667 }
1668 });
1669
1670 function $$() {
1671 return Selector.findChildElements(document, $A(arguments));
1672 }
1181 var Form = {
1673 var Form = {
1182 serialize: function(form) {
1674 reset: function(form) {
1183 var elements = Form.getElements($(form));
1675 $(form).reset();
1184 var queryComponents = new Array();
1676 return form;
1677 },
1185
1678
1186 for (var i = 0; i < elements.length; i++) {
1679 serializeElements: function(elements) {
1187 var queryComponent = Form.Element.serialize(elements[i]);
1680 return elements.inject([], function(queryComponents, element) {
1188 if (queryComponent)
1681 var queryComponent = Form.Element.serialize(element);
1189 queryComponents.push(queryComponent);
1682 if (queryComponent) queryComponents.push(queryComponent);
1190 }
1683 return queryComponents;
1684 }).join('&');
1685 }
1686 };
1191
1687
1192 return queryComponents.join('&');
1688 Form.Methods = {
1689 serialize: function(form) {
1690 return Form.serializeElements($(form).getElements());
1193 },
1691 },
1194
1692
1195 getElements: function(form) {
1693 getElements: function(form) {
1196 form = $(form);
1694 return $A($(form).getElementsByTagName('*')).inject([],
1197 var elements = new Array();
1695 function(elements, child) {
1198
1696 if (Form.Element.Serializers[child.tagName.toLowerCase()])
1199 for (tagName in Form.Element.Serializers) {
1697 elements.push(Element.extend(child));
1200 var tagElements = form.getElementsByTagName(tagName);
1698 return elements;
1201 for (var j = 0; j < tagElements.length; j++)
1699 }
1202 elements.push(tagElements[j]);
1700 );
1203 }
1204 return elements;
1205 },
1701 },
1206
1702
1207 getInputs: function(form, typeName, name) {
1703 getInputs: function(form, typeName, name) {
@@ -1212,53 +1708,68 var Form = {
1212 return inputs;
1708 return inputs;
1213
1709
1214 var matchingInputs = new Array();
1710 var matchingInputs = new Array();
1215 for (var i = 0; i < inputs.length; i++) {
1711 for (var i = 0, length = inputs.length; i < length; i++) {
1216 var input = inputs[i];
1712 var input = inputs[i];
1217 if ((typeName && input.type != typeName) ||
1713 if ((typeName && input.type != typeName) ||
1218 (name && input.name != name))
1714 (name && input.name != name))
1219 continue;
1715 continue;
1220 matchingInputs.push(input);
1716 matchingInputs.push(Element.extend(input));
1221 }
1717 }
1222
1718
1223 return matchingInputs;
1719 return matchingInputs;
1224 },
1720 },
1225
1721
1226 disable: function(form) {
1722 disable: function(form) {
1227 var elements = Form.getElements(form);
1723 form = $(form);
1228 for (var i = 0; i < elements.length; i++) {
1724 form.getElements().each(function(element) {
1229 var element = elements[i];
1230 element.blur();
1725 element.blur();
1231 element.disabled = 'true';
1726 element.disabled = 'true';
1232 }
1727 });
1728 return form;
1233 },
1729 },
1234
1730
1235 enable: function(form) {
1731 enable: function(form) {
1236 var elements = Form.getElements(form);
1732 form = $(form);
1237 for (var i = 0; i < elements.length; i++) {
1733 form.getElements().each(function(element) {
1238 var element = elements[i];
1239 element.disabled = '';
1734 element.disabled = '';
1240 }
1735 });
1736 return form;
1241 },
1737 },
1242
1738
1243 findFirstElement: function(form) {
1739 findFirstElement: function(form) {
1244 return Form.getElements(form).find(function(element) {
1740 return $(form).getElements().find(function(element) {
1245 return element.type != 'hidden' && !element.disabled &&
1741 return element.type != 'hidden' && !element.disabled &&
1246 ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
1742 ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
1247 });
1743 });
1248 },
1744 },
1249
1745
1250 focusFirstElement: function(form) {
1746 focusFirstElement: function(form) {
1251 Field.activate(Form.findFirstElement(form));
1747 form = $(form);
1748 form.findFirstElement().activate();
1749 return form;
1750 }
1751 }
1752
1753 Object.extend(Form, Form.Methods);
1754
1755 /*--------------------------------------------------------------------------*/
1756
1757 Form.Element = {
1758 focus: function(element) {
1759 $(element).focus();
1760 return element;
1252 },
1761 },
1253
1762
1254 reset: function(form) {
1763 select: function(element) {
1255 $(form).reset();
1764 $(element).select();
1765 return element;
1256 }
1766 }
1257 }
1767 }
1258
1768
1259 Form.Element = {
1769 Form.Element.Methods = {
1260 serialize: function(element) {
1770 serialize: function(element) {
1261 element = $(element);
1771 element = $(element);
1772 if (element.disabled) return '';
1262 var method = element.tagName.toLowerCase();
1773 var method = element.tagName.toLowerCase();
1263 var parameter = Form.Element.Serializers[method](element);
1774 var parameter = Form.Element.Serializers[method](element);
1264
1775
@@ -1282,20 +1793,52 Form.Element = {
1282
1793
1283 if (parameter)
1794 if (parameter)
1284 return parameter[1];
1795 return parameter[1];
1796 },
1797
1798 clear: function(element) {
1799 $(element).value = '';
1800 return element;
1801 },
1802
1803 present: function(element) {
1804 return $(element).value != '';
1805 },
1806
1807 activate: function(element) {
1808 element = $(element);
1809 element.focus();
1810 if (element.select)
1811 element.select();
1812 return element;
1813 },
1814
1815 disable: function(element) {
1816 element = $(element);
1817 element.disabled = true;
1818 return element;
1819 },
1820
1821 enable: function(element) {
1822 element = $(element);
1823 element.blur();
1824 element.disabled = false;
1825 return element;
1285 }
1826 }
1286 }
1827 }
1287
1828
1829 Object.extend(Form.Element, Form.Element.Methods);
1830 var Field = Form.Element;
1831
1832 /*--------------------------------------------------------------------------*/
1833
1288 Form.Element.Serializers = {
1834 Form.Element.Serializers = {
1289 input: function(element) {
1835 input: function(element) {
1290 switch (element.type.toLowerCase()) {
1836 switch (element.type.toLowerCase()) {
1291 case 'submit':
1292 case 'hidden':
1293 case 'password':
1294 case 'text':
1295 return Form.Element.Serializers.textarea(element);
1296 case 'checkbox':
1837 case 'checkbox':
1297 case 'radio':
1838 case 'radio':
1298 return Form.Element.Serializers.inputSelector(element);
1839 return Form.Element.Serializers.inputSelector(element);
1840 default:
1841 return Form.Element.Serializers.textarea(element);
1299 }
1842 }
1300 return false;
1843 return false;
1301 },
1844 },
@@ -1317,24 +1860,20 Form.Element.Serializers = {
1317 selectOne: function(element) {
1860 selectOne: function(element) {
1318 var value = '', opt, index = element.selectedIndex;
1861 var value = '', opt, index = element.selectedIndex;
1319 if (index >= 0) {
1862 if (index >= 0) {
1320 opt = element.options[index];
1863 opt = Element.extend(element.options[index]);
1321 value = opt.value;
1864 // Uses the new potential extension if hasAttribute isn't native.
1322 if (!value && !('value' in opt))
1865 value = opt.hasAttribute('value') ? opt.value : opt.text;
1323 value = opt.text;
1324 }
1866 }
1325 return [element.name, value];
1867 return [element.name, value];
1326 },
1868 },
1327
1869
1328 selectMany: function(element) {
1870 selectMany: function(element) {
1329 var value = new Array();
1871 var value = [];
1330 for (var i = 0; i < element.length; i++) {
1872 for (var i = 0; i < element.length; i++) {
1331 var opt = element.options[i];
1873 var opt = Element.extend(element.options[i]);
1332 if (opt.selected) {
1874 if (opt.selected)
1333 var optValue = opt.value;
1875 // Uses the new potential extension if hasAttribute isn't native.
1334 if (!optValue && !('value' in opt))
1876 value.push(opt.hasAttribute('value') ? opt.value : opt.text);
1335 optValue = opt.text;
1336 value.push(optValue);
1337 }
1338 }
1877 }
1339 return [element.name, value];
1878 return [element.name, value];
1340 }
1879 }
@@ -1408,9 +1947,7 Abstract.EventObserver.prototype = {
1408 },
1947 },
1409
1948
1410 registerFormCallbacks: function() {
1949 registerFormCallbacks: function() {
1411 var elements = Form.getElements(this.element);
1950 Form.getElements(this.element).each(this.registerCallback.bind(this));
1412 for (var i = 0; i < elements.length; i++)
1413 this.registerCallback(elements[i]);
1414 },
1951 },
1415
1952
1416 registerCallback: function(element) {
1953 registerCallback: function(element) {
@@ -1420,11 +1957,7 Abstract.EventObserver.prototype = {
1420 case 'radio':
1957 case 'radio':
1421 Event.observe(element, 'click', this.onElementEvent.bind(this));
1958 Event.observe(element, 'click', this.onElementEvent.bind(this));
1422 break;
1959 break;
1423 case 'password':
1960 default:
1424 case 'text':
1425 case 'textarea':
1426 case 'select-one':
1427 case 'select-multiple':
1428 Event.observe(element, 'change', this.onElementEvent.bind(this));
1961 Event.observe(element, 'change', this.onElementEvent.bind(this));
1429 break;
1962 break;
1430 }
1963 }
@@ -1459,6 +1992,10 Object.extend(Event, {
1459 KEY_RIGHT: 39,
1992 KEY_RIGHT: 39,
1460 KEY_DOWN: 40,
1993 KEY_DOWN: 40,
1461 KEY_DELETE: 46,
1994 KEY_DELETE: 46,
1995 KEY_HOME: 36,
1996 KEY_END: 35,
1997 KEY_PAGEUP: 33,
1998 KEY_PAGEDOWN: 34,
1462
1999
1463 element: function(event) {
2000 element: function(event) {
1464 return event.target || event.srcElement;
2001 return event.target || event.srcElement;
@@ -1514,7 +2051,7 Object.extend(Event, {
1514
2051
1515 unloadCache: function() {
2052 unloadCache: function() {
1516 if (!Event.observers) return;
2053 if (!Event.observers) return;
1517 for (var i = 0; i < Event.observers.length; i++) {
2054 for (var i = 0, length = Event.observers.length; i < length; i++) {
1518 Event.stopObserving.apply(this, Event.observers[i]);
2055 Event.stopObserving.apply(this, Event.observers[i]);
1519 Event.observers[i][0] = null;
2056 Event.observers[i][0] = null;
1520 }
2057 }
@@ -1522,7 +2059,7 Object.extend(Event, {
1522 },
2059 },
1523
2060
1524 observe: function(element, name, observer, useCapture) {
2061 observe: function(element, name, observer, useCapture) {
1525 var element = $(element);
2062 element = $(element);
1526 useCapture = useCapture || false;
2063 useCapture = useCapture || false;
1527
2064
1528 if (name == 'keypress' &&
2065 if (name == 'keypress' &&
@@ -1530,11 +2067,11 Object.extend(Event, {
1530 || element.attachEvent))
2067 || element.attachEvent))
1531 name = 'keydown';
2068 name = 'keydown';
1532
2069
1533 this._observeAndCache(element, name, observer, useCapture);
2070 Event._observeAndCache(element, name, observer, useCapture);
1534 },
2071 },
1535
2072
1536 stopObserving: function(element, name, observer, useCapture) {
2073 stopObserving: function(element, name, observer, useCapture) {
1537 var element = $(element);
2074 element = $(element);
1538 useCapture = useCapture || false;
2075 useCapture = useCapture || false;
1539
2076
1540 if (name == 'keypress' &&
2077 if (name == 'keypress' &&
@@ -1545,13 +2082,16 Object.extend(Event, {
1545 if (element.removeEventListener) {
2082 if (element.removeEventListener) {
1546 element.removeEventListener(name, observer, useCapture);
2083 element.removeEventListener(name, observer, useCapture);
1547 } else if (element.detachEvent) {
2084 } else if (element.detachEvent) {
1548 element.detachEvent('on' + name, observer);
2085 try {
2086 element.detachEvent('on' + name, observer);
2087 } catch (e) {}
1549 }
2088 }
1550 }
2089 }
1551 });
2090 });
1552
2091
1553 /* prevent memory leaks in IE */
2092 /* prevent memory leaks in IE */
1554 Event.observe(window, 'unload', Event.unloadCache, false);
2093 if (navigator.appVersion.match(/\bMSIE\b/))
2094 Event.observe(window, 'unload', Event.unloadCache, false);
1555 var Position = {
2095 var Position = {
1556 // set to true if needed, warning: firefox performance problems
2096 // set to true if needed, warning: firefox performance problems
1557 // NOT neeeded for page scrolling, only if draggable contained in
2097 // NOT neeeded for page scrolling, only if draggable contained in
@@ -1598,7 +2138,8 var Position = {
1598 valueL += element.offsetLeft || 0;
2138 valueL += element.offsetLeft || 0;
1599 element = element.offsetParent;
2139 element = element.offsetParent;
1600 if (element) {
2140 if (element) {
1601 p = Element.getStyle(element, 'position');
2141 if(element.tagName=='BODY') break;
2142 var p = Element.getStyle(element, 'position');
1602 if (p == 'relative' || p == 'absolute') break;
2143 if (p == 'relative' || p == 'absolute') break;
1603 }
2144 }
1604 } while (element);
2145 } while (element);
@@ -1654,17 +2195,6 var Position = {
1654 element.offsetWidth;
2195 element.offsetWidth;
1655 },
2196 },
1656
2197
1657 clone: function(source, target) {
1658 source = $(source);
1659 target = $(target);
1660 target.style.position = 'absolute';
1661 var offsets = this.cumulativeOffset(source);
1662 target.style.top = offsets[1] + 'px';
1663 target.style.left = offsets[0] + 'px';
1664 target.style.width = source.offsetWidth + 'px';
1665 target.style.height = source.offsetHeight + 'px';
1666 },
1667
1668 page: function(forElement) {
2198 page: function(forElement) {
1669 var valueT = 0, valueL = 0;
2199 var valueT = 0, valueL = 0;
1670
2200
@@ -1681,8 +2211,10 var Position = {
1681
2211
1682 element = forElement;
2212 element = forElement;
1683 do {
2213 do {
1684 valueT -= element.scrollTop || 0;
2214 if (!window.opera || element.tagName=='BODY') {
1685 valueL -= element.scrollLeft || 0;
2215 valueT -= element.scrollTop || 0;
2216 valueL -= element.scrollLeft || 0;
2217 }
1686 } while (element = element.parentNode);
2218 } while (element = element.parentNode);
1687
2219
1688 return [valueL, valueT];
2220 return [valueL, valueT];
@@ -1782,4 +2314,6 if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
1782
2314
1783 return [valueL, valueT];
2315 return [valueL, valueT];
1784 }
2316 }
1785 } No newline at end of file
2317 }
2318
2319 Element.addMethods(); No newline at end of file
@@ -215,6 +215,30 font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
215 #content dt{font-weight:bold; margin-bottom:5px;}
215 #content dt{font-weight:bold; margin-bottom:5px;}
216 #content dd{margin:0 0 10px 15px;}
216 #content dd{margin:0 0 10px 15px;}
217
217
218 #content .tabs{height: 2.6em;}
219 #content .tabs ul{margin:0;}
220 #content .tabs ul li{
221 float:left;
222 list-style-type:none;
223 white-space:nowrap;
224 margin-right:8px;
225 background:#fff;
226 }
227 #content .tabs ul li a{
228 display:block;
229 font-size: 0.9em;
230 text-decoration:none;
231 line-height:1em;
232 padding:4px;
233 border: 1px solid #c0c0c0;
234 }
235
236 #content .tabs ul li a.selected, #content .tabs ul li a:hover{
237 background-color: #80b0da;
238 border: 1px solid #80b0da;
239 color: #fff;
240 text-decoration:none;
241 }
218
242
219 /***********************************************/
243 /***********************************************/
220
244
General Comments 0
You need to be logged in to leave comments. Login now