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