Commit 0d3ca253472bd95b0b3f60d7ebe7c87f2655cdb2

Authored by Leandro Santos
2 parents 5204221c 7ce466a9

fix conflit with master

Showing 56 changed files with 435 additions and 4426 deletions   Show diff stats
Gemfile
... ... @@ -18,10 +18,8 @@ gem 'rest-client', '~> 1.6.7'
18 18 gem 'exception_notification', '~> 4.0.1'
19 19 gem 'gettext', '~> 2.2.1', :require => false, :group => :development
20 20 gem 'locale', '~> 2.0.5'
21   -
22 21 gem 'whenever', :require => false
23   -
24   -gem 'eita-jrails', path: 'vendor/plugins/eita-jrails'
  22 +gem 'eita-jrails', :require => false
25 23  
26 24 group :production do
27 25 gem 'dalli', '~> 2.7.0'
... ...
app/helpers/application_helper.rb
... ... @@ -592,7 +592,7 @@ module ApplicationHelper
592 592 extra_info = extra_info.nil? ? '' : content_tag( 'span', extra_info, :class => 'extra_info' )
593 593 links = links_for_balloon(profile)
594 594 content_tag('div', content_tag(tag,
595   - (environment.enabled?(:show_balloon_with_profile_links_when_clicked) ? link_to( content_tag( 'span', _('Profile links')), '#', :onclick => "toggleSubmenu(this, '#{profile.short_name}', #{CGI::escapeHTML(links.to_json)}); return false", :class => "menu-submenu-trigger #{trigger_class}", :url => url) : "") +
  595 + (environment.enabled?(:show_balloon_with_profile_links_when_clicked) ? popover_menu(_('Profile links'),profile.short_name,links,{:class => trigger_class, :url => url}) : "") +
596 596 link_to(
597 597 content_tag( 'span', profile_image( profile, size ), :class => 'profile-image' ) +
598 598 content_tag( 'span', h(name), :class => ( profile.class == Person ? 'fn' : 'org' ) ) +
... ... @@ -604,6 +604,14 @@ module ApplicationHelper
604 604 :class => 'vcard'), :class => 'common-profile-list-block')
605 605 end
606 606  
  607 + def popover_menu(title,menu_title,links,html_options={})
  608 + html_options[:class] = "" unless html_options[:class]
  609 + html_options[:class] << " menu-submenu-trigger"
  610 + html_options[:onclick] = "toggleSubmenu(this, '#{menu_title}', #{CGI::escapeHTML(links.to_json)}); return false"
  611 +
  612 + link_to(content_tag(:span, title), '#', html_options)
  613 + end
  614 +
607 615 def gravatar_default
608 616 (respond_to?(:theme_option) && theme_option.present? && theme_option['gravatar']) || NOOSFERO_CONF['gravatar'] || 'mm'
609 617 end
... ... @@ -718,7 +726,7 @@ module ApplicationHelper
718 726 class NoosferoFormBuilder < ActionView::Helpers::FormBuilder
719 727 extend ActionView::Helpers::TagHelper
720 728  
721   - def self.output_field(text, field_html, field_id = nil)
  729 + def self.output_field(text, field_html, field_id = nil, options = {})
722 730 # try to guess an id if none given
723 731 if field_id.nil?
724 732 field_html =~ /id=['"]([^'"]*)['"]/
... ... @@ -1050,7 +1058,7 @@ module ApplicationHelper
1050 1058 end
1051 1059  
1052 1060 link_to(content_tag(:span, _('Contents'), :class => 'icon-menu-articles'), {:controller => "search", :action => 'contents', :category_path => nil}, :id => 'submenu-contents') +
1053   - link_to(content_tag(:span, _('Contents menu')), '#', :onclick => "toggleSubmenu(this,'',#{CGI::escapeHTML(links.to_json)}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-contents-trigger')
  1061 + popover_menu(_('Contents menu'),'',links,:class => 'up', :id => 'submenu-contents-trigger')
1054 1062 end
1055 1063 alias :browse_contents_menu :search_contents_menu
1056 1064  
... ... @@ -1066,7 +1074,7 @@ module ApplicationHelper
1066 1074 end
1067 1075  
1068 1076 link_to(content_tag(:span, _('People'), :class => 'icon-menu-people'), {:controller => "search", :action => 'people', :category_path => ''}, :id => 'submenu-people') +
1069   - link_to(content_tag(:span, _('People menu')), '#', :onclick => "toggleSubmenu(this,'',#{CGI::escapeHTML(links.to_json)}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-people-trigger')
  1077 + popover_menu(_('People menu'),'',links,:class => 'up', :id => 'submenu-people-trigger')
1070 1078 end
1071 1079 alias :browse_people_menu :search_people_menu
1072 1080  
... ... @@ -1082,7 +1090,7 @@ module ApplicationHelper
1082 1090 end
1083 1091  
1084 1092 link_to(content_tag(:span, _('Communities'), :class => 'icon-menu-community'), {:controller => "search", :action => 'communities'}, :id => 'submenu-communities') +
1085   - link_to(content_tag(:span, _('Communities menu')), '#', :onclick => "toggleSubmenu(this,'',#{CGI::escapeHTML(links.to_json)}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-communities-trigger')
  1093 + popover_menu(_('Communities menu'),'',links,:class => 'up', :id => 'submenu-communities-trigger')
1086 1094 end
1087 1095 alias :browse_communities_menu :search_communities_menu
1088 1096  
... ...
app/helpers/block_helper.rb
... ... @@ -19,7 +19,7 @@ module BlockHelper
19 19 content_tag('span', _('Title')) +
20 20 text_field_tag('block[images][][title]', image[:title], :class => 'highlight-title', :size => 45)
21 21 }</label></td>
22   - <td>#{link_to '', '#', :class=>'button icon-button icon-delete delete-highlight', :confirm=>_('Are you sure you want to remove this highlight')}</td>
  22 + <td>#{button_without_text(:delete, _('Remove'), '#', class: 'delete-highlight', :confirm=>_('Are you sure you want to remove this highlight'))}</td>
23 23 </tr>
24 24 "
25 25 end
... ...
app/helpers/categories_helper.rb
... ... @@ -25,10 +25,13 @@ module CategoriesHelper
25 25 )
26 26 end
27 27  
28   - def update_categories_link(body, category_id=nil, html_options={})
  28 + #TODO: remove this function and, in views, use existing basic buttons
  29 + def update_categories_link(type, body, category_id=nil, html_options={})
  30 + html_class = 'select-subcategory-link'
  31 + html_class = " icon-#{type} btn btn-primary btn-xs" if type.present?
29 32 link_to body,
30 33 { :action => "update_categories", :category_id => category_id, :id => @object },
31   - {:id => category_id ? "select-category-#{category_id}-link" : nil, :remote => true, :class => 'select-subcategory-link'}.merge(html_options)
  34 + {:id => category_id ? "select-category-#{category_id}-link" : nil, :remote => true, :class => html_class}.merge(html_options)
32 35 end
33 36  
34 37 end
... ...
app/helpers/language_helper.rb
1 1 module LanguageHelper
2 2 def language
3   - locale
  3 + locale.to_s
4 4 end
5 5  
6 6 def tinymce_language
... ... @@ -20,7 +20,7 @@ module LanguageHelper
20 20 separator = options[:separator] || ' &mdash; '
21 21  
22 22 if options[:element] == 'dropdown'
23   - select_tag('lang',
  23 + select_tag('lang',
24 24 options_for_select(locales.map{|code,name| [name, code]}, current),
25 25 :onchange => "document.location.href= #{url_for(params.merge(:lang => 'LANGUAGE'))}.replace(/LANGUAGE/, this.value) ;",
26 26 :help => _('The language you choose here is the language used for options, buttons, etc. It does not affect the language of the content created by other users.')
... ...
app/helpers/layout_helper.rb
... ... @@ -31,12 +31,12 @@ module LayoutHelper
31 31 plugins_javascripts = @plugins.map { |plugin| [plugin.js_files].flatten.map { |js| plugin.class.public_path(js) } }.flatten
32 32  
33 33 output = ''
34   - output += render :file => 'layouts/_javascript'
35   - output += javascript_tag 'render_all_jquery_ui_widgets()'
  34 + output += render 'layouts/javascript'
36 35 unless plugins_javascripts.empty?
37 36 output += javascript_include_tag plugins_javascripts, :cache => "cache/plugins-#{Digest::MD5.hexdigest plugins_javascripts.to_s}"
38 37 end
39 38 output += theme_javascript_ng.to_s
  39 + output += javascript_tag 'render_all_jquery_ui_widgets()'
40 40  
41 41 output
42 42 end
... ... @@ -86,6 +86,7 @@ module LayoutHelper
86 86 end
87 87 end
88 88  
  89 +
89 90 def icon_theme_stylesheet_path
90 91 icon_themes = []
91 92 theme_icon_themes = theme_option(:icon_theme) || []
... ... @@ -116,8 +117,5 @@ module LayoutHelper
116 117 end
117 118 end
118 119  
119   - def meta_description_tag(article=nil)
120   - article ? CGI.escapeHTML(truncate(strip_tags(article.body.to_s), :length => 200)) : environment.name
121   - end
122 120 end
123 121  
... ...
app/mailers/comment_notifier.rb
1   -class Comment::Notifier < ActionMailer::Base
  1 +class CommentNotifier < ActionMailer::Base
2 2 def notification(comment)
3 3 profile = comment.article.profile
4 4 @recipient = profile.nickname || profile.name
... ...
app/mailers/scrap_notifier.rb
1   -class Scrap::Notifier < ActionMailer::Base
  1 +class ScrapNotifier < ActionMailer::Base
2 2 def notification(scrap)
3 3 sender, receiver = scrap.sender, scrap.receiver
4 4 @recipient = receiver.name
... ...
app/models/comment.rb
... ... @@ -150,11 +150,11 @@ class Comment &lt; ActiveRecord::Base
150 150 def notify_by_mail
151 151 if source.kind_of?(Article) && article.notify_comments?
152 152 if !notification_emails.empty?
153   - Comment::Notifier.notification(self).deliver
  153 + CommentNotifier.notification(self).deliver
154 154 end
155 155 emails = article.followers - [author_email]
156 156 if !emails.empty?
157   - Comment::Notifier.mail_to_followers(self, emails).deliver
  157 + CommentNotifier.mail_to_followers(self, emails).deliver
158 158 end
159 159 end
160 160 end
... ...
app/models/scrap.rb
... ... @@ -25,7 +25,7 @@ class Scrap &lt; ActiveRecord::Base
25 25  
26 26 after_create do |scrap|
27 27 scrap.root.update_attribute('updated_at', DateTime.now) unless scrap.root.nil?
28   - Scrap::Notifier.notification(scrap).deliver if scrap.send_notification?
  28 + ScrapNotifier.notification(scrap).deliver if scrap.send_notification?
29 29 end
30 30  
31 31 before_validation :strip_all_html_tags
... ...
app/models/user.rb
... ... @@ -102,6 +102,7 @@ class User &lt; ActiveRecord::Base
102 102 validates_length_of :email, :within => 3..100, :if => (lambda {|user| !user.email.blank?})
103 103 validates_uniqueness_of :login, :email, :case_sensitive => false, :scope => :environment_id
104 104 before_save :encrypt_password
  105 + before_save :normalize_email, if: proc{ |u| u.email.present? }
105 106 validates_format_of :email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda {|user| !user.email.blank?})
106 107  
107 108 validates_inclusion_of :terms_accepted, :in => [ '1' ], :if => lambda { |u| ! u.terms_of_use.blank? }, :message => N_('{fn} must be checked in order to signup.').fix_i18n
... ... @@ -118,18 +119,6 @@ class User &lt; ActiveRecord::Base
118 119 self.update_attribute :last_login_at, Time.now
119 120 end
120 121  
121   - #FIXME make this test
122   - def generate_private_token!
123   - self.private_token = SecureRandom.hex
124   - self.private_token_generated_at = DateTime.now
125   - save(:validate => false)
126   - end
127   -
128   - #FIXME make this test
129   - def private_token_expired?
130   - self.generate_private_token! if self.private_token.nil? || (self.private_token_generated_at + 2.weeks < DateTime.now)
131   - end
132   -
133 122 # Activates the user in the database.
134 123 def activate
135 124 return false unless self.person
... ... @@ -347,7 +336,25 @@ class User &lt; ActiveRecord::Base
347 336 @is_password_required = false
348 337 end
349 338  
  339 + #FIXME make this test
  340 + def generate_private_token!
  341 + self.private_token = SecureRandom.hex
  342 + self.private_token_generated_at = DateTime.now
  343 + save(:validate => false)
  344 + end
  345 +
  346 + #FIXME make this test
  347 + def private_token_expired?
  348 + self.generate_private_token! if self.private_token.nil? || (self.private_token_generated_at + 2.weeks < DateTime.now)
  349 + end
  350 +
  351 +
350 352 protected
  353 +
  354 + def normalize_email
  355 + self.email = self.email.squish.downcase
  356 + end
  357 +
351 358 # before filter
352 359 def encrypt_password
353 360 return if password.blank?
... ... @@ -375,6 +382,6 @@ class User &lt; ActiveRecord::Base
375 382  
376 383 def delay_activation_check
377 384 return if person.is_template?
378   - Delayed::Job.enqueue(UserActivationJob.new(self.id), {:priority => 0, :run_at => 72.hours.from_now})
  385 + Delayed::Job.enqueue(UserActivationJob.new(self.id), {:priority => 0, :run_at => (NOOSFERO_CONF['hours_until_user_activation_check'] || 72).hours.from_now})
379 386 end
380 387 end
... ...
app/views/account/login.html.erb
... ... @@ -7,7 +7,7 @@
7 7  
8 8 <%= @message %>
9 9  
10   -<%= labelled_form_for :user, :url => login_url do |f| %>
  10 +<%= labelled_form_for :user, :url => login_url, :horizontal => true do |f| %>
11 11  
12 12 <%= f.text_field :login, :id => 'main_user_login', :onchange => 'this.value = convToValidLogin( this.value )', :value => params[:userlogin] %>
13 13  
... ...
app/views/account/login_block.html.erb
... ... @@ -20,9 +20,7 @@
20 20 <% button_bar do %>
21 21 <%= submit_button( 'login', _('Log in') )%>
22 22 <% unless @plugins.dispatch(:allow_user_registration).include?(false) %>
23   - <%= link_to content_tag( 'span', _('New user') ),
24   - { :controller => 'account', :action => 'signup' },
25   - :class => 'button with-text icon-add' %>
  23 + <%= button(:add, _('New user'), { :controller => 'account', :action => 'signup' }) %>
26 24 <% end %>
27 25 <% end %>
28 26  
... ...
app/views/blocks/login_block.html.erb
... ... @@ -6,7 +6,7 @@
6 6 <li><%= link_to _('Homepage'), user.public_profile_url %></li>
7 7 </ul>
8 8 <div class="user-actions">
9   - <%= link_to content_tag('span', _('Logout')), { :controller => 'account', :action => 'logout' }, :class => 'button with-text icon-menu-logout' %>
  9 + <%= button(:'menu-logout', _('Logout'), :controller => 'account', :action => 'logout') %>
10 10 </div>
11 11 </div>
12 12 <% else %>
... ...
app/views/blocks/profile_info_actions/_community.html.erb
... ... @@ -5,11 +5,11 @@
5 5 <% if logged_in? %>
6 6 <% if profile.enable_contact? %>
7 7 <li>
8   - <%= link_to content_tag('span', _('Send an e-mail')),
9   - { :profile => profile.identifier,
10   - :controller => 'contact',
11   - :action => 'new' },
12   - {:class => 'button with-text icon-menu-mail', :title => _('Send an e-mail to the administrators')} %>
  8 + <%= button(:'menu-mail', _('Send an e-mail'),
  9 + { :profile => profile.identifier,
  10 + :controller => 'contact',
  11 + :action => 'new' },
  12 + { :title => _('Send an e-mail to the administrators')}) %>
13 13 </li>
14 14 <% end %>
15 15  
... ...
app/views/blocks/profile_info_actions/_enterprise.html.erb
1 1 <ul>
2 2 <%if logged_in? %>
3 3 <%if !user.favorite_enterprises.include?(profile) %>
4   - <li><%= link_to content_tag('span', _('Add as favorite')), { :profile => user.identifier, :controller => 'favorite_enterprises', :action => 'add', :id => profile.id }, :class => 'button with-text icon-add', :title => _('Add enterprise as favorite') %></li>
  4 + <li><%= button(:add, _('Add as favorite'), { :profile => user.identifier, :controller => 'favorite_enterprises', :action => 'add', :id => profile.id }, :title => _('Add enterprise as favorite')) %></li>
5 5 <% end %>
6 6 <% end %>
7 7 <% if profile.enable_contact? %>
8   - <li> <%= link_to content_tag('span', _('Send an e-mail')), {:profile => profile.identifier, :controller => 'contact', :action => 'new'}, {:id => 'enterprise-contact-button', :class => 'button with-text icon-menu-mail'} %> </li>
  8 + <li><%= button(:'menu-mail', _('Send an e-mail'), {:profile => profile.identifier, :controller => 'contact', :action => 'new'}, {:id => 'enterprise-contact-button'} ) %></li>
9 9 <% end %>
10 10  
11 11 <li><%= report_abuse(profile, :button) %></li>
... ...
app/views/blocks/profile_info_actions/_join_leave_community.html.erb
... ... @@ -22,8 +22,6 @@
22 22 <% end %>
23 23 <% end %>
24 24 <% else %>
25   - <%= link_to content_tag('span', _('Join')), profile.join_not_logged_url,
26   - :class => 'button with-text icon-add',
27   - :title => _('Join this community') %>
  25 + <%= button(:add, _('Join'), profile.join_not_logged_url, :title => _('Join this community')) %>
28 26 <% end %>
29 27 </div>
... ...
app/views/blocks/profile_info_actions/_person.html.erb
... ... @@ -8,7 +8,7 @@
8 8 <% end %>
9 9  
10 10 <% if user.is_a_friend?(profile) && profile.enable_contact? %>
11   - <li> <%= link_to content_tag('span', _('Send an e-mail')), {:profile => profile.identifier, :controller => 'contact', :action => 'new'}, :class => 'button with-text icon-menu-mail' %> </li>
  11 + <li><%= button(:back, _('Send an e-mail'), {:profile => profile.identifier, :controller => 'contact', :action => 'new'}) %></li>
12 12 <% end %>
13 13  
14 14 <li><%= report_abuse(profile, :button) %></li>
... ...
app/views/box_organizer/_highlights_block.html.erb
... ... @@ -15,7 +15,7 @@
15 15 </tbody>
16 16 </table>
17 17  
18   -<%= link_to(_('New highlight'), '#', :class => 'button icon-add with-text new-highlight-button')%>
  18 +<%= button(:add, _('New highlight'), '#', class: 'new-highlight-button') %>
19 19  
20 20 <%= labelled_form_field _('Image transition:'), select('block', 'interval', [[_('No automatic transition'), 0]] + [1, 2, 3, 4, 5, 10, 20, 30, 60].map {|item| [n_('Every 1 second', 'Every %d seconds', item) % item, item]}) %>
21 21  
... ...
app/views/box_organizer/add_block.html.erb 0 → 100644
... ... @@ -0,0 +1,49 @@
  1 +<div id="add-block-dialog">
  2 + <%= form_tag do %>
  3 +
  4 + <p><%= _('In what area do you want to put your new block?') %></p>
  5 +
  6 + <div id="box-position">
  7 + <% @boxes.each do |box| %>
  8 + <% name = box.central? ? _('Main area') : _('Area %d') % box.position %>
  9 + <%= labelled_radio_button(name, :box_id, box.id, box.central?, { 'data-position' => box.position }) %>
  10 + <% end %>
  11 + </div>
  12 +
  13 + <script type="text/javascript">
  14 + jQuery('#box-position input').bind('change',
  15 + function () {
  16 + showCenter = jQuery(this).attr('data-position') == '1';
  17 + jQuery('#center-block-types').toggle(showCenter);
  18 + jQuery('#side-block-types').toggle(!showCenter);
  19 + }
  20 + );
  21 + </script>
  22 +
  23 + <p><%= _('Select the type of block you want to add to your page.') %></p>
  24 +
  25 + <div id="center-block-types" class="block-types">
  26 + <% @center_block_types.each do |block| %>
  27 + <div class='block-type'>
  28 + <%= labelled_radio_button(block.description, :type, block.name) %>
  29 + </div>
  30 + <% end %>
  31 + </div>
  32 +
  33 + <div id="side-block-types" class="block-types" style="display:none">
  34 + <% @side_block_types.each do |block| %>
  35 + <div class='block-type'>
  36 + <%= labelled_radio_button(block.description, :type, block.name) %>
  37 + </div>
  38 + <% end %>
  39 + </div>
  40 +
  41 + <br style='clear: both'/>
  42 +
  43 + <% button_bar do %>
  44 + <%= submit_button(:add, _("Add")) %>
  45 + <%= modal_close_button(_('Close')) %>
  46 + <% end %>
  47 +
  48 + <% end %>
  49 +</div>
... ...
app/views/comment/_comment_actions.html.erb
... ... @@ -2,7 +2,7 @@
2 2 <% if !links_submenu.empty? %>
3 3 <div class="comment-actions">
4 4 <li class="vcard">
5   - <%= link_to(content_tag(:span, _('Contents menu')), '#', :onclick => "toggleSubmenu(this,'',#{CGI::escapeHTML(links_submenu.to_json)}); return false", :class => 'menu-submenu-trigger comment-trigger', :url => url) %>
  5 + <%= popover_menu(_('Contents menu'),'',links_submenu,:class => 'comment-trigger', :url => url) %>
6 6 </li>
7 7 </div>
8 8 <% end %>
... ...
app/views/comment/notifier/mail_to_followers.html.erb
... ... @@ -1,22 +0,0 @@
1   -<%= _('Hi!') %>
2   -
3   -<%= word_wrap(_('%{sender} (%{sender_link}) commented on the content "%{article_title}".') % { :sender => @sender, :sender_link => url_for(@sender_link), :article_title => @article_title }) %>
4   -
5   -<%= word_wrap(_('Title: %s') % @comment_title) if @comment_title %>
6   -
7   -<%= _("Comment:") %>
8   --------------------------------------------------------------------------------
9   -<%= word_wrap(@comment_body) %>
10   --------------------------------------------------------------------------------
11   -
12   -<%= _('Click on the address below to view this comment:') %>
13   -<%= url_for @comment_url %>
14   -
15   -<%= _('Click on the address below to cancel the notification of new comments:') %>
16   -<%= url_for @unsubscribe_url %>
17   -
18   -<%= _("Greetings,") %>
19   -
20   ---
21   -<%= _('%s team.') % @environment %>
22   -<%= url_for @url %>
app/views/comment/notifier/notification.text.erb
... ... @@ -1,19 +0,0 @@
1   -<%= _('Hi, %{recipient}!') % { :recipient => @recipient } %>
2   -
3   -<%= word_wrap(_('%{sender} (%{sender_link}) created a new comment on your article "%{article_title}".') % { :sender => @sender, :sender_link => url_for(@sender_link), :article_title => @article_title }) %>
4   -
5   -<%= word_wrap(_('Title: %s') % @comment_title) %>
6   -
7   -<%= _("Comment:") %>
8   --------------------------------------------------------------------------------
9   -<%= word_wrap(@comment_body) %>
10   --------------------------------------------------------------------------------
11   -
12   -<%= _('Access the address below to view this comment:') %>
13   -<%= url_for @comment_url %>
14   -
15   -<%= _("Greetings,") %>
16   -
17   ---
18   -<%= _('%s team.') % @environment %>
19   -<%= url_for @url %>
app/views/comment_notifier/mail_to_followers.html.erb 0 → 100644
... ... @@ -0,0 +1,22 @@
  1 +<%= _('Hi!') %>
  2 +
  3 +<%= word_wrap(_('%{sender} (%{sender_link}) commented on the content "%{article_title}".') % { :sender => @sender, :sender_link => url_for(@sender_link), :article_title => @article_title }) %>
  4 +
  5 +<%= word_wrap(_('Title: %s') % @comment_title) if @comment_title %>
  6 +
  7 +<%= _("Comment:") %>
  8 +-------------------------------------------------------------------------------
  9 +<%= word_wrap(@comment_body) %>
  10 +-------------------------------------------------------------------------------
  11 +
  12 +<%= _('Click on the address below to view this comment:') %>
  13 +<%= url_for @comment_url %>
  14 +
  15 +<%= _('Click on the address below to cancel the notification of new comments:') %>
  16 +<%= url_for @unsubscribe_url %>
  17 +
  18 +<%= _("Greetings,") %>
  19 +
  20 +--
  21 +<%= _('%s team.') % @environment %>
  22 +<%= url_for @url %>
... ...
app/views/comment_notifier/notification.text.erb 0 → 100644
... ... @@ -0,0 +1,19 @@
  1 +<%= _('Hi, %{recipient}!') % { :recipient => @recipient } %>
  2 +
  3 +<%= word_wrap(_('%{sender} (%{sender_link}) created a new comment on your article "%{article_title}".') % { :sender => @sender, :sender_link => url_for(@sender_link), :article_title => @article_title }) %>
  4 +
  5 +<%= word_wrap(_('Title: %s') % @comment_title) %>
  6 +
  7 +<%= _("Comment:") %>
  8 +-------------------------------------------------------------------------------
  9 +<%= word_wrap(@comment_body) %>
  10 +-------------------------------------------------------------------------------
  11 +
  12 +<%= _('Access the address below to view this comment:') %>
  13 +<%= url_for @comment_url %>
  14 +
  15 +<%= _("Greetings,") %>
  16 +
  17 +--
  18 +<%= _('%s team.') % @environment %>
  19 +<%= url_for @url %>
... ...
app/views/favorite_enterprises/index.html.erb
... ... @@ -9,10 +9,7 @@
9 9 enterprise.identifier, :class => 'profile-link' %>
10 10 <%# profile_image_link enterprise, :portrait, 'div' %>
11 11 <div class="controll">
12   - <%= link_to content_tag('span',_('remove')),
13   - { :action => 'remove', :id => enterprise.id },
14   - :class => 'button icon-delete',
15   - :title => _('remove') %>
  12 + <%= button(:delete, _('remove'), { :action => 'remove', :id => enterprise.id },:title => _('remove')) %>
16 13 </div><!-- end class="controll" -->
17 14 </li>
18 15 <% end %>
... ...
app/views/scrap/notifier/notification.text.erb
... ... @@ -1,16 +0,0 @@
1   -<%= _('Hi, %{recipient}!') % { :recipient => @recipient } %>
2   -
3   -<%= word_wrap(_('%{sender} (%{sender_link}) has left the following scrap for you:') % { :sender => @sender, :sender_link => url_for(@sender_link) }) %>
4   -
5   --------------------------------------------------------------------------------
6   -<%= word_wrap(@scrap_content) %>
7   --------------------------------------------------------------------------------
8   -
9   -<%= _('View this scrap on the wall') %>:
10   -<%= url_for @wall_url %>
11   -
12   -<%= _("Greetings,") %>
13   -
14   ---
15   -<%= _('%s team.') % @environment %>
16   -<%= url_for @url %>
app/views/scrap_notifier/notification.text.erb 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +<%= _('Hi, %{recipient}!') % { :recipient => @recipient } %>
  2 +
  3 +<%= word_wrap(_('%{sender} (%{sender_link}) has left the following scrap for you:') % { :sender => @sender, :sender_link => url_for(@sender_link) }) %>
  4 +
  5 +-------------------------------------------------------------------------------
  6 +<%= word_wrap(@scrap_content) %>
  7 +-------------------------------------------------------------------------------
  8 +
  9 +<%= _('View this scrap on the wall') %>:
  10 +<%= url_for @wall_url %>
  11 +
  12 +<%= _("Greetings,") %>
  13 +
  14 +--
  15 +<%= _('%s team.') % @environment %>
  16 +<%= url_for @url %>
... ...
app/views/search/_sellers_form.html.erb
... ... @@ -18,7 +18,7 @@
18 18 </div>
19 19  
20 20 <div class="button-bar">
21   - <%= submit_tag _('Search'), :class => 'button with-text icon-search' %>
  21 + <%= submit_button :search, _('Search') %>
22 22 </div>
23 23  
24 24 <% end %>
... ...
app/views/shared/_change_image.html.erb
1 1 <%= i.file_field( :uploaded_data, { :onchange => 'updateImg(this.value)' } ) %>
2   - <%= link_to_function(_('Cancel'), "jQuery('#change-image-link').show(); jQuery('#change-image').html('')", :id => 'cancel-change-image-link', :class => 'button icon-cancel with-text', :style => 'display: none') %>
  2 + <%= button_to_function(:cancel,_('Cancel'),"jQuery('#change-image-link').show(); jQuery('#change-image').html('')", :id => 'cancel-change-image-link', :style => 'display: none')%>
... ...
app/views/shared/_select_categories.html.erb
... ... @@ -4,12 +4,12 @@
4 4 <%= hidden_field_tag "#{object_name}[#{object_name}_category_id]", @current_category.id unless multiple %>
5 5 <%= hidden_field_tag "#{object_name}[category_ids][]", @current_category.id if multiple %>
6 6  
7   - <%= update_categories_link("", nil, :id => "cancel-category-button", :class => "button icon-back") %>
  7 + <%= update_categories_link(:back, "", nil, :id => "cancel-category-button") %>
8 8 <%
9 9 categories = [@current_category]
10 10 categories.push(@current_category) while @current_category = @current_category.parent
11 11 %>
12   - <%= categories.compact.reverse.map{|i| update_categories_link(i.name, i.id)}.join %>
  12 + <%= categories.compact.reverse.map{|i| update_categories_link(nil,i.name, i.id)}.join %>
13 13  
14 14 <script>
15 15 function add_category() {
... ...
app/views/shared/_select_subcategories.html.erb
... ... @@ -3,6 +3,6 @@
3 3 <div class="category-helper-label"><%= _('Click to select a category') %></div>
4 4  
5 5 <% categories.select{|i| @object.accept_category?(i)}.each do |category| %>
6   - <%= update_categories_link(category.name, category.id) %>
  6 + <%= update_categories_link(nil,category.name, category.id) %>
7 7 <% end %>
8 8 <% end %>
... ...
app/views/shared/_show_thumbnail.html.erb
... ... @@ -2,7 +2,7 @@
2 2  
3 3 <br/>
4 4  
5   - <%= link_to_function(_('Change image'), 'display_change_image()', :id => 'change-image-link', :class => 'button icon-photos with-text') %>
  5 + <%= button_to_function(:photos, _('Change image'), 'display_change_image()', :id => 'change-image-link' ) %>
6 6  
7 7 <script>
8 8 function display_change_image() {
... ...
app/views/tasks/index.html.erb
... ... @@ -23,7 +23,7 @@
23 23  
24 24 <% if @tasks.empty? %>
25 25 <p>
26   - <%= labelled_select(_('Filter')+': ', :filter_type, :first, :last, @filter, type_collection, :onchange => 'document.location.href = "?filter_type="+this.value')%>
  26 + <%= labelled_select(_('Filter')+': ', :filter_type, :first, :last, @filter, type_collection, :onchange => "document.location.href = '?filter_type='+this.value")%>
27 27 </p>
28 28 <em><%= _('No pending tasks for %s') % profile.name %></em>
29 29 <% else %>
... ...
config/initializers/jrails.rb 0 → 100644
... ... @@ -0,0 +1 @@
  1 +require 'jrails'
... ...
db/schema.rb
... ... @@ -241,6 +241,14 @@ ActiveRecord::Schema.define(:version =&gt; 20150122165042) do
241 241 t.datetime "updated_at"
242 242 end
243 243  
  244 + create_table "chat_messages", :force => true do |t|
  245 + t.integer "to_id"
  246 + t.integer "from_id"
  247 + t.string "body"
  248 + t.datetime "created_at", :null => false
  249 + t.datetime "updated_at", :null => false
  250 + end
  251 +
244 252 create_table "comments", :force => true do |t|
245 253 t.string "title"
246 254 t.text "body"
... ...
debian/control
... ... @@ -42,6 +42,7 @@ Depends: adduser,
42 42 ruby-acts-as-taggable-on,
43 43 ruby-daemons,
44 44 ruby-dalli,
  45 + ruby-eita-jrails (>= 0.9.3-3~),
45 46 ruby-eventmachine (>= 0.12.10-4~),
46 47 ruby-exception-notification,
47 48 ruby-fast-gettext,
... ... @@ -53,7 +54,6 @@ Depends: adduser,
53 54 ruby-nokogiri,
54 55 ruby-pg,
55 56 ruby-progressbar,
56   - ruby-prototype-rails,
57 57 ruby-rack (>= 1.4.5-2~),
58 58 ruby-rails-autolink,
59 59 ruby-redcloth,
... ...
lib/acts_as_having_posts.rb
... ... @@ -22,7 +22,7 @@ module ActsAsHavingPosts
22 22 end
23 23  
24 24 def feed
25   - Article.where(:parent_id => self.id).where(:type => 'RssFeed').first
  25 + children.where(:type => 'RssFeed').first
26 26 end
27 27  
28 28 def feed=(attrs)
... ...
lib/tasks/plugins_tests.rake
... ... @@ -106,7 +106,7 @@ def run_test(name, files)
106 106 files = Array(files)
107 107 plugin = filename2plugin(files.first)
108 108 if name == :cucumber || name == :selenium
109   - run_cucumber task2_profile(name, plugin), files
  109 + run_cucumber task2profile(name, plugin), files
110 110 else
111 111 run_testrb files
112 112 end
... ... @@ -134,7 +134,11 @@ end
134 134  
135 135 def run_tests(name, plugins, run=:all)
136 136 plugins = Array(plugins)
137   - glob = "plugins/{#{plugins.join(',')}}/test/#{task2folder(name)}/**/*.#{task2ext(name)}"
  137 + if name == :cucumber || name == :selenium
  138 + glob = "plugins/{#{plugins.join(',')}}/#{task2folder(name)}/**/*.#{task2ext(name)}"
  139 + else
  140 + glob = "plugins/{#{plugins.join(',')}}/test/#{task2folder(name)}/**/*.#{task2ext(name)}"
  141 + end
138 142 files = Dir.glob(glob)
139 143 if files.empty?
140 144 puts "I: no tests to run #{name}"
... ...
lib/tasks/release.rake
... ... @@ -156,6 +156,8 @@ EOF
156 156  
157 157 sh 'git checkout debian/changelog lib/noosfero/version.rb'
158 158 sh "sed -i \"s/VERSION = '[^']*'/VERSION = '#{new_version}'/\" lib/noosfero/version.rb"
  159 + ENV['DEBFULLNAME'] ||= `git config user.name`.strip
  160 + ENV['DEBEMAIL'] ||= `git config user.email`.strip
159 161 sh "dch --newversion #{new_version} --distribution #{target} --force-distribution '#{release_message}'"
160 162  
161 163 sh 'git diff debian/changelog lib/noosfero/version.rb'
... ...
lib/tasks/test.rake
... ... @@ -17,15 +17,31 @@ NoosferoTasks = %w(test:noosfero_plugins)
17 17 AllTasks = TestTasks + CucumberTasks + NoosferoTasks
18 18  
19 19 task :test do
20   - errors = AllTasks.collect do |task|
  20 + data = []
  21 + failed = []
  22 + AllTasks.each do |task|
  23 + t0 = Time.now.to_i
21 24 begin
22 25 ENV['RAILS_ENV'] = 'test'
23 26 Rake::Task[task].invoke
24   - nil
  27 + status = 'PASS'
25 28 rescue => e
26   - task
  29 + failed << task
  30 + status = 'FAIL'
27 31 end
28   - end.compact
29   - abort "Errors running #{errors.to_sentence}!" if errors.any?
  32 + t1 = Time.now.to_i
  33 + duration = t1 - t0
  34 + data << { :name => task, :status => status, :duration => Time.at(duration).utc.strftime("%H:%M:%S") }
  35 + end
  36 +
  37 + puts
  38 + printf "%-30s %-6s %s\n", 'Task', 'Status', 'Duration'
  39 + printf "%-30s %-6s %s\n", '-' * 30, '-' * 6, '--------'
  40 + data.each do |entry|
  41 + printf "%-30s %-6s %s\n", entry[:name], entry[:status], entry[:duration]
  42 + end
  43 +
  44 + puts
  45 + abort "Errors running #{failed.join(', ')}!" if failed.any?
30 46 end
31 47  
... ...
plugins/comment_classification/features/step_definitions/plugin_steps.rb
1 1 Given /^CommentClassificationPlugin is enabled$/ do
2   - step %{I am logged in as admin}
3   - step %{I am on the environment control panel}
4   - step %{I follow "Plugins"}
5   - step %{I check "Comment Classification"}
6   - step %{I press "Save changes"}
  2 + steps %Q{
  3 + Given I am logged in as admin
  4 + Given I am on the environment control panel
  5 + Given I follow "Plugins"
  6 + Given I check "Comment Classification"
  7 + Given I press "Save changes"
  8 + }
  9 +
7 10 Environment.default.enabled_plugins.should include("CommentClassificationPlugin")
8 11 end
9 12  
... ...
plugins/comment_classification/lib/ext/comment.rb
1 1 require_dependency 'comment'
2   -require 'comment_classification_plugin.rb'
3   -require 'comment_classification_plugin/label.rb'
4 2  
5 3 class Comment
6 4  
... ...
public/500.html
... ... @@ -6,7 +6,7 @@
6 6 <title>Technical problems</title>
7 7 <link rel="stylesheet" type="text/css" href="/designs/themes/default/errors.css"/>
8 8 <link rel="shortcut icon" href='/designs/themes/default/favicon.ico' type="image/x-icon" />
9   - <script type='text/javascript' src='/javascripts/prototype.js'></script>
  9 + <script type='text/javascript' src='/javascripts/jquery.js'></script>
10 10 <script type='text/javascript' src='/javascripts/errors.js'></script>
11 11 </head>
12 12 <body onload='display_error_message()'>
... ...
public/500.html.erb
... ... @@ -6,7 +6,7 @@
6 6 <title>Technical problems</title>
7 7 <link rel="stylesheet" type="text/css" href="/designs/themes/default/errors.css"/>
8 8 <link rel="shortcut icon" href='/designs/themes/default/favicon.ico' type="image/x-icon" />
9   - <script type='text/javascript' src='/javascripts/prototype.js'></script>
  9 + <script type='text/javascript' src='/javascripts/jquery.js'></script>
10 10 <script type='text/javascript' src='/javascripts/errors.js'></script>
11 11 </head>
12 12 <body onload='display_error_message()'>
... ...
public/503.html
... ... @@ -6,7 +6,7 @@
6 6 <title>Noosfero - System Maintainance</title>
7 7 <link rel="stylesheet" type="text/css" href="/designs/themes/default/errors.css"/>
8 8 <link rel="shortcut icon" href='/designs/themes/default/favicon.ico' type="image/x-icon" />
9   - <script type='text/javascript' src='/javascripts/prototype.js'></script>
  9 + <script type='text/javascript' src='/javascripts/jquery.js'></script>
10 10 <script type='text/javascript' src='/javascripts/errors.js'></script>
11 11 </head>
12 12 <body onload='display_error_message()'>
... ...
public/503.html.erb
... ... @@ -6,7 +6,7 @@
6 6 <title>Noosfero - System Maintainance</title>
7 7 <link rel="stylesheet" type="text/css" href="/designs/themes/default/errors.css"/>
8 8 <link rel="shortcut icon" href='/designs/themes/default/favicon.ico' type="image/x-icon" />
9   - <script type='text/javascript' src='/javascripts/prototype.js'></script>
  9 + <script type='text/javascript' src='/javascripts/jquery.js'></script>
10 10 <script type='text/javascript' src='/javascripts/errors.js'></script>
11 11 </head>
12 12 <body onload='display_error_message()'>
... ...
public/javascripts/application.js
... ... @@ -548,33 +548,6 @@ jQuery(function($) {
548 548 $.getJSON(user_data, userDataCallback)
549 549  
550 550 $.ajaxSetup({ cache: false });
551   -
552   - function chatOnlineUsersDataCallBack(data) {
553   - if ($('#chat-online-users').length == 0) {
554   - return;
555   - }
556   - var content = '';
557   - $('#chat-online-users .amount_of_friends').html(data['amount_of_friends']);
558   - $('#chat-online-users').fadeIn();
559   - for (var user in data['friends_list']) {
560   - var name = "<span class='friend_name'>%{name}</span>";
561   - var avatar = data['friends_list'][user]['avatar'];
562   - var jid = data['friends_list'][user]['jid'];
563   - var status_name = data['friends_list'][user]['status'] || 'offline';
564   - avatar = avatar ? '<img src="' + avatar + '" />' : ''
565   - name = name.replace('%{name}',data['friends_list'][user]['name']);
566   - open_chat_link = "onclick='open_chat_window(this, \"#" + jid + "\")'";
567   - var status_icon = "<div class='chat-online-user-status icon-menu-"+ status_name + "-11'><span>" + status_name + '</span></div>';
568   - content += "<li><a href='#' class='chat-online-user' " + open_chat_link + "><div class='chat-online-user-avatar'>" + avatar + '</div>' + name + status_icon + '</a></li>';
569   - }
570   - content ? $('#chat-online-users-hidden-content ul').html(content) : $('#anyone-online').show();
571   - $('#chat-online-users-title').click(function(){
572   - if($('#chat-online-users-content').is(':visible'))
573   - $('#chat-online-users-content').hide();
574   - else
575   - $('#chat-online-users-content').show();
576   - });
577   - }
578 551 });
579 552  
580 553 // controls the display of contact list
... ... @@ -1042,31 +1015,6 @@ log.error = function() {
1042 1015 window.log.apply(window, jQuery.merge(['error'], arguments));
1043 1016 }
1044 1017  
1045   -jQuery(function($) {
1046   - $('.colorbox').live('click', function() {
1047   - $.colorbox({
1048   - href: $(this).attr('href'),
1049   - maxWidth: $(window).width()-50,
1050   - height: $(window).height()-50,
1051   - open: true,
1052   - fixed: true,
1053   - close: 'Cancel',
1054   - onComplete: function(bt) {
1055   - var opt = {}, maxH = $(window).height()-50;
1056   - if ($('#cboxLoadedContent *:first').height() > maxH) opt.height = maxH;
1057   - $.colorbox.resize(opt);
1058   - }
1059   - });
1060   - return false;
1061   - });
1062   -
1063   - $('.colorbox-close').live('click', function() {
1064   - $.colorbox.close();
1065   - return false;
1066   - });
1067   -
1068   -});
1069   -
1070 1018 function showHideTermsOfUse() {
1071 1019 if( jQuery("#article_has_terms_of_use").attr("checked") )
1072 1020 jQuery("#text_area_terms_of_use").show();
... ...
public/javascripts/errors.js
... ... @@ -2,15 +2,15 @@ function display_error_message(language) {
2 2 if (!language) {
3 3 var language = ((navigator.language) ? navigator.language : navigator.userLanguage).replace('-', '_');
4 4 }
5   - element = $(language);
6   - if (!element) {
7   - element = $(language.replace(/_.*$/, ''));
  5 + var $element = $('#' + language);
  6 + if ($element.size() == 0) {
  7 + $element = $('#' + language.replace(/_.*$/, ''));
8 8 }
9   - if (!element) {
  9 + if ($element.size() == 0) {
10 10 element = $('en');
11 11 }
12   - $$('.message').each(function(item) { item.hide() });
13   - element.getElementsBySelector('h1').each(function(title) { document.title = title.innerHTML; });
14   - element.show();
  12 + $('.message').hide();
  13 + $element.show();
  14 + $('title').html($element.find('h1').html());
15 15 }
16 16  
... ...
public/javascripts/jquery.js 0 → 120000
... ... @@ -0,0 +1 @@
  1 +jquery-2.1.1.min.js
0 2 \ No newline at end of file
... ...
public/javascripts/jrails.js
... ... @@ -1 +0,0 @@
1   -../../vendor/plugins/eita-jrails/assets/javascripts/jrails/jrails.js
2 0 \ No newline at end of file
public/javascripts/jrails.js 0 → 100644
... ... @@ -0,0 +1,185 @@
  1 +/*
  2 +*
  3 +* jRails ajax extras
  4 +* version 0.1
  5 +* <aaron@ennerchi.com> | http://www.ennerchi.com
  6 +*
  7 +*/
  8 +
  9 +(function($) {
  10 + // reset a form
  11 + $.fn.reset = function() {
  12 + return this.each(function() {
  13 + // guard against an input with the name of 'reset'
  14 + // note that IE reports the reset function as an 'object'
  15 + if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
  16 + this.reset();
  17 + });
  18 + };
  19 + // enable a form element
  20 + $.fn.enable = function() {
  21 + return this.each(function() {
  22 + this.disabled = false;
  23 + });
  24 + };
  25 + // disable a form element
  26 + $.fn.disable = function() {
  27 + return this.each(function() {
  28 + this.disabled = true;
  29 + });
  30 + };
  31 +
  32 +})(jQuery);
  33 +
  34 +/*
  35 +*
  36 +* jRails form observer plugin
  37 +* version 0.2
  38 +* <aaron@ennerchi.com> | http://www.ennerchi.com
  39 +*
  40 +*/
  41 +
  42 +(function($) {
  43 + $.extend({ // Translate field to event
  44 + fieldEvent: function(el, obs) {
  45 + var field = el[0] || el, e = 'change';
  46 + if (field.type == 'radio' || field.type == 'checkbox') e = 'click';
  47 + else if (obs && (field.type == 'text' || field.type == 'textarea' || field.type == 'password')) e = 'keyup';
  48 + return e;
  49 + }
  50 + });
  51 + $.fn.extend({ // Delayed observer for fields and forms
  52 + delayedObserver: function(delay, callback){
  53 + var el = $(this);
  54 + if (el.length == 0) return;
  55 + if (typeof window.delayedObserverStack == 'undefined') window.delayedObserverStack = [];
  56 + if (typeof window.delayedObserverCallback == 'undefined') {
  57 + window.delayedObserverCallback = function(stackPos) {
  58 + var observed = window.delayedObserverStack[stackPos];
  59 + if (observed.timer) clearTimeout(observed.timer);
  60 + observed.timer = setTimeout(function(){
  61 + observed.timer = null;
  62 + observed.callback(observed.obj, observed.obj.formVal());
  63 + }, observed.delay * 1000);
  64 + observed.oldVal = observed.obj.formVal();
  65 + };
  66 + }
  67 + window.delayedObserverStack.push({
  68 + obj: el, timer: null, delay: delay,
  69 + oldVal: el.formVal(), callback: callback
  70 + });
  71 + var stackPos = window.delayedObserverStack.length-1;
  72 + if (el[0].tagName == 'FORM') {
  73 + $(':input', el).each(function(){
  74 + var field = $(this);
  75 + field.bind($.fieldEvent(field, delay), function(){
  76 + var observed = window.delayedObserverStack[stackPos];
  77 + if (observed.obj.formVal() == observed.oldVal) return;
  78 + else window.delayedObserverCallback(stackPos);
  79 + });
  80 + });
  81 + } else {
  82 + el.bind($.fieldEvent(el, delay), function(){
  83 + var observed = window.delayedObserverStack[stackPos];
  84 + if (observed.obj.formVal() == observed.oldVal) return;
  85 + else window.delayedObserverCallback(stackPos);
  86 + });
  87 + };
  88 + },
  89 + formVal: function() { // Gets form values
  90 + var el = this[0];
  91 + if(el.tagName == 'FORM') return this.serialize();
  92 + if(el.type == 'checkbox' || el.type == 'radio') return this.filter('input:checked').val() || '';
  93 + else return this.val();
  94 + }
  95 + });
  96 +})(jQuery);
  97 +
  98 +/*
  99 +*
  100 +* jRails visual effects stubs
  101 +* version 0.2
  102 +* <aaron@ennerchi.com> | http://www.ennerchi.com
  103 +*
  104 +*/
  105 +
  106 +(function($) {
  107 + $.fn.extend({
  108 + visualEffect : function(o, options) {
  109 + if (options) {
  110 + speed = options.duration * 1000;
  111 + } else {
  112 + speed = null;
  113 + }
  114 + e = o.replace(/\_(.)/g, function(m, l){return l.toUpperCase()});
  115 + return eval('$(this).'+e+'('+ speed + ')');
  116 + },
  117 + appear : function(speed, callback) {
  118 + return this.fadeIn(speed, callback);
  119 + },
  120 + blindDown : function(speed, callback) {
  121 + return this.show('blind', { direction: 'vertical' }, speed, callback);
  122 + },
  123 + blindUp : function(speed, callback) {
  124 + return this.hide('blind', { direction: 'vertical' }, speed, callback);
  125 + },
  126 + blindRight : function(speed, callback) {
  127 + return this.show('blind', { direction: 'horizontal' }, speed, callback);
  128 + },
  129 + blindLeft : function(speed, callback) {
  130 + this.hide('blind', { direction: 'horizontal' }, speed, callback);
  131 + return this;
  132 + },
  133 + dropOut : function(speed, callback) {
  134 + return this.hide('drop', {direction: 'down' }, speed, callback);
  135 + },
  136 + dropIn : function(speed, callback) {
  137 + return this.show('drop', { direction: 'up' }, speed, callback);
  138 + },
  139 + fade : function(speed, callback) {
  140 + return this.fadeOut(speed, callback);
  141 + },
  142 + fadeToggle : function(speed, callback) {
  143 + return this.animate({opacity: 'toggle'}, speed, callback);
  144 + },
  145 + fold : function(speed, callback) {
  146 + return this.hide('fold', {}, speed, callback);
  147 + },
  148 + foldOut : function(speed, callback) {
  149 + return this.show('fold', {}, speed, callback);
  150 + },
  151 + grow : function(speed, callback) {
  152 + return this.show('scale', {}, speed, callback);
  153 + },
  154 + highlight : function(speed, callback) {
  155 + return this.show('highlight', {}, speed, callback);
  156 + },
  157 + puff : function(speed, callback) {
  158 + return this.hide('puff', {}, speed, callback);
  159 + },
  160 + pulsate : function(speed, callback) {
  161 + return this.show('pulsate', {}, speed, callback);
  162 + },
  163 + shake : function(speed, callback) {
  164 + return this.show('shake', {}, speed, callback);
  165 + },
  166 + shrink : function(speed, callback) {
  167 + return this.hide('scale', {}, speed, callback);
  168 + },
  169 + squish : function(speed, callback) {
  170 + return this.hide('scale', { origin: ['top', 'left'] }, speed, callback);
  171 + },
  172 + slideUp : function(speed, callback) {
  173 + return this.hide('slide', { direction: 'up'}, speed, callback);
  174 + },
  175 + slideDown : function(speed, callback) {
  176 + return this.show('slide', { direction: 'up'}, speed, callback);
  177 + },
  178 + switchOff : function(speed, callback) {
  179 + return this.hide('clip', {}, speed, callback);
  180 + },
  181 + switchOn : function(speed, callback) {
  182 + return this.show('clip', {}, speed, callback);
  183 + }
  184 + });
  185 +})(jQuery);
... ...
public/javascripts/prototype.js
... ... @@ -1,4221 +0,0 @@
1   -/* Prototype JavaScript framework, version 1.6.0.2
2   - * (c) 2005-2008 Sam Stephenson
3   - *
4   - * Prototype is freely distributable under the terms of an MIT-style license.
5   - * For details, see the Prototype web site: http://www.prototypejs.org/
6   - *
7   - *--------------------------------------------------------------------------*/
8   -
9   -var Prototype = {
10   - Version: '1.6.0.2',
11   -
12   - Browser: {
13   - IE: !!(window.attachEvent && !window.opera),
14   - Opera: !!window.opera,
15   - WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
16   - Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
17   - MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
18   - },
19   -
20   - BrowserFeatures: {
21   - XPath: !!document.evaluate,
22   - ElementExtensions: !!window.HTMLElement,
23   - SpecificElementExtensions:
24   - document.createElement('div').__proto__ &&
25   - document.createElement('div').__proto__ !==
26   - document.createElement('form').__proto__
27   - },
28   -
29   - ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
30   - JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
31   -
32   - emptyFunction: function() { },
33   - K: function(x) { return x }
34   -};
35   -
36   -if (Prototype.Browser.MobileSafari)
37   - Prototype.BrowserFeatures.SpecificElementExtensions = false;
38   -
39   -
40   -/* Based on Alex Arnell's inheritance implementation. */
41   -var Class = {
42   - create: function() {
43   - var parent = null, properties = $A(arguments);
44   - if (Object.isFunction(properties[0]))
45   - parent = properties.shift();
46   -
47   - function klass() {
48   - this.initialize.apply(this, arguments);
49   - }
50   -
51   - Object.extend(klass, Class.Methods);
52   - klass.superclass = parent;
53   - klass.subclasses = [];
54   -
55   - if (parent) {
56   - var subclass = function() { };
57   - subclass.prototype = parent.prototype;
58   - klass.prototype = new subclass;
59   - parent.subclasses.push(klass);
60   - }
61   -
62   - for (var i = 0; i < properties.length; i++)
63   - klass.addMethods(properties[i]);
64   -
65   - if (!klass.prototype.initialize)
66   - klass.prototype.initialize = Prototype.emptyFunction;
67   -
68   - klass.prototype.constructor = klass;
69   -
70   - return klass;
71   - }
72   -};
73   -
74   -Class.Methods = {
75   - addMethods: function(source) {
76   - var ancestor = this.superclass && this.superclass.prototype;
77   - var properties = Object.keys(source);
78   -
79   - if (!Object.keys({ toString: true }).length)
80   - properties.push("toString", "valueOf");
81   -
82   - for (var i = 0, length = properties.length; i < length; i++) {
83   - var property = properties[i], value = source[property];
84   - if (ancestor && Object.isFunction(value) &&
85   - value.argumentNames().first() == "$super") {
86   - var method = value, value = Object.extend((function(m) {
87   - return function() { return ancestor[m].apply(this, arguments) };
88   - })(property).wrap(method), {
89   - valueOf: function() { return method },
90   - toString: function() { return method.toString() }
91   - });
92   - }
93   - this.prototype[property] = value;
94   - }
95   -
96   - return this;
97   - }
98   -};
99   -
100   -var Abstract = { };
101   -
102   -Object.extend = function(destination, source) {
103   - for (var property in source)
104   - destination[property] = source[property];
105   - return destination;
106   -};
107   -
108   -Object.extend(Object, {
109   - inspect: function(object) {
110   - try {
111   - if (Object.isUndefined(object)) return 'undefined';
112   - if (object === null) return 'null';
113   - return object.inspect ? object.inspect() : String(object);
114   - } catch (e) {
115   - if (e instanceof RangeError) return '...';
116   - throw e;
117   - }
118   - },
119   -
120   - toJSON: function(object) {
121   - var type = typeof object;
122   - switch (type) {
123   - case 'undefined':
124   - case 'function':
125   - case 'unknown': return;
126   - case 'boolean': return object.toString();
127   - }
128   -
129   - if (object === null) return 'null';
130   - if (object.toJSON) return object.toJSON();
131   - if (Object.isElement(object)) return;
132   -
133   - var results = [];
134   - for (var property in object) {
135   - var value = Object.toJSON(object[property]);
136   - if (!Object.isUndefined(value))
137   - results.push(property.toJSON() + ': ' + value);
138   - }
139   -
140   - return '{' + results.join(', ') + '}';
141   - },
142   -
143   - toQueryString: function(object) {
144   - return $H(object).toQueryString();
145   - },
146   -
147   - toHTML: function(object) {
148   - return object && object.toHTML ? object.toHTML() : String.interpret(object);
149   - },
150   -
151   - keys: function(object) {
152   - var keys = [];
153   - for (var property in object)
154   - keys.push(property);
155   - return keys;
156   - },
157   -
158   - values: function(object) {
159   - var values = [];
160   - for (var property in object)
161   - values.push(object[property]);
162   - return values;
163   - },
164   -
165   - clone: function(object) {
166   - return Object.extend({ }, object);
167   - },
168   -
169   - isElement: function(object) {
170   - return object && object.nodeType == 1;
171   - },
172   -
173   - isArray: function(object) {
174   - return object != null && typeof object == "object" &&
175   - 'splice' in object && 'join' in object;
176   - },
177   -
178   - isHash: function(object) {
179   - return object instanceof Hash;
180   - },
181   -
182   - isFunction: function(object) {
183   - return typeof object == "function";
184   - },
185   -
186   - isString: function(object) {
187   - return typeof object == "string";
188   - },
189   -
190   - isNumber: function(object) {
191   - return typeof object == "number";
192   - },
193   -
194   - isUndefined: function(object) {
195   - return typeof object == "undefined";
196   - }
197   -});
198   -
199   -Object.extend(Function.prototype, {
200   - argumentNames: function() {
201   - var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip");
202   - return names.length == 1 && !names[0] ? [] : names;
203   - },
204   -
205   - bind: function() {
206   - if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
207   - var __method = this, args = $A(arguments), object = args.shift();
208   - return function() {
209   - return __method.apply(object, args.concat($A(arguments)));
210   - }
211   - },
212   -
213   - bindAsEventListener: function() {
214   - var __method = this, args = $A(arguments), object = args.shift();
215   - return function(event) {
216   - return __method.apply(object, [event || window.event].concat(args));
217   - }
218   - },
219   -
220   - curry: function() {
221   - if (!arguments.length) return this;
222   - var __method = this, args = $A(arguments);
223   - return function() {
224   - return __method.apply(this, args.concat($A(arguments)));
225   - }
226   - },
227   -
228   - delay: function() {
229   - var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
230   - return window.setTimeout(function() {
231   - return __method.apply(__method, args);
232   - }, timeout);
233   - },
234   -
235   - wrap: function(wrapper) {
236   - var __method = this;
237   - return function() {
238   - return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
239   - }
240   - },
241   -
242   - methodize: function() {
243   - if (this._methodized) return this._methodized;
244   - var __method = this;
245   - return this._methodized = function() {
246   - return __method.apply(null, [this].concat($A(arguments)));
247   - };
248   - }
249   -});
250   -
251   -Function.prototype.defer = Function.prototype.delay.curry(0.01);
252   -
253   -Date.prototype.toJSON = function() {
254   - return '"' + this.getUTCFullYear() + '-' +
255   - (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
256   - this.getUTCDate().toPaddedString(2) + 'T' +
257   - this.getUTCHours().toPaddedString(2) + ':' +
258   - this.getUTCMinutes().toPaddedString(2) + ':' +
259   - this.getUTCSeconds().toPaddedString(2) + 'Z"';
260   -};
261   -
262   -var Try = {
263   - these: function() {
264   - var returnValue;
265   -
266   - for (var i = 0, length = arguments.length; i < length; i++) {
267   - var lambda = arguments[i];
268   - try {
269   - returnValue = lambda();
270   - break;
271   - } catch (e) { }
272   - }
273   -
274   - return returnValue;
275   - }
276   -};
277   -
278   -RegExp.prototype.match = RegExp.prototype.test;
279   -
280   -RegExp.escape = function(str) {
281   - return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
282   -};
283   -
284   -/*--------------------------------------------------------------------------*/
285   -
286   -var PeriodicalExecuter = Class.create({
287   - initialize: function(callback, frequency) {
288   - this.callback = callback;
289   - this.frequency = frequency;
290   - this.currentlyExecuting = false;
291   -
292   - this.registerCallback();
293   - },
294   -
295   - registerCallback: function() {
296   - this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
297   - },
298   -
299   - execute: function() {
300   - this.callback(this);
301   - },
302   -
303   - stop: function() {
304   - if (!this.timer) return;
305   - clearInterval(this.timer);
306   - this.timer = null;
307   - },
308   -
309   - onTimerEvent: function() {
310   - if (!this.currentlyExecuting) {
311   - try {
312   - this.currentlyExecuting = true;
313   - this.execute();
314   - } finally {
315   - this.currentlyExecuting = false;
316   - }
317   - }
318   - }
319   -});
320   -Object.extend(String, {
321   - interpret: function(value) {
322   - return value == null ? '' : String(value);
323   - },
324   - specialChar: {
325   - '\b': '\\b',
326   - '\t': '\\t',
327   - '\n': '\\n',
328   - '\f': '\\f',
329   - '\r': '\\r',
330   - '\\': '\\\\'
331   - }
332   -});
333   -
334   -Object.extend(String.prototype, {
335   - gsub: function(pattern, replacement) {
336   - var result = '', source = this, match;
337   - replacement = arguments.callee.prepareReplacement(replacement);
338   -
339   - while (source.length > 0) {
340   - if (match = source.match(pattern)) {
341   - result += source.slice(0, match.index);
342   - result += String.interpret(replacement(match));
343   - source = source.slice(match.index + match[0].length);
344   - } else {
345   - result += source, source = '';
346   - }
347   - }
348   - return result;
349   - },
350   -
351   - sub: function(pattern, replacement, count) {
352   - replacement = this.gsub.prepareReplacement(replacement);
353   - count = Object.isUndefined(count) ? 1 : count;
354   -
355   - return this.gsub(pattern, function(match) {
356   - if (--count < 0) return match[0];
357   - return replacement(match);
358   - });
359   - },
360   -
361   - scan: function(pattern, iterator) {
362   - this.gsub(pattern, iterator);
363   - return String(this);
364   - },
365   -
366   - truncate: function(length, truncation) {
367   - length = length || 30;
368   - truncation = Object.isUndefined(truncation) ? '...' : truncation;
369   - return this.length > length ?
370   - this.slice(0, length - truncation.length) + truncation : String(this);
371   - },
372   -
373   - strip: function() {
374   - return this.replace(/^\s+/, '').replace(/\s+$/, '');
375   - },
376   -
377   - stripTags: function() {
378   - return this.replace(/<\/?[^>]+>/gi, '');
379   - },
380   -
381   - stripScripts: function() {
382   - return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
383   - },
384   -
385   - extractScripts: function() {
386   - var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
387   - var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
388   - return (this.match(matchAll) || []).map(function(scriptTag) {
389   - return (scriptTag.match(matchOne) || ['', ''])[1];
390   - });
391   - },
392   -
393   - evalScripts: function() {
394   - return this.extractScripts().map(function(script) { return eval(script) });
395   - },
396   -
397   - escapeHTML: function() {
398   - var self = arguments.callee;
399   - self.text.data = this;
400   - return self.div.innerHTML;
401   - },
402   -
403   - unescapeHTML: function() {
404   - var div = new Element('div');
405   - div.innerHTML = this.stripTags();
406   - return div.childNodes[0] ? (div.childNodes.length > 1 ?
407   - $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
408   - div.childNodes[0].nodeValue) : '';
409   - },
410   -
411   - toQueryParams: function(separator) {
412   - var match = this.strip().match(/([^?#]*)(#.*)?$/);
413   - if (!match) return { };
414   -
415   - return match[1].split(separator || '&').inject({ }, function(hash, pair) {
416   - if ((pair = pair.split('='))[0]) {
417   - var key = decodeURIComponent(pair.shift());
418   - var value = pair.length > 1 ? pair.join('=') : pair[0];
419   - if (value != undefined) value = decodeURIComponent(value);
420   -
421   - if (key in hash) {
422   - if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
423   - hash[key].push(value);
424   - }
425   - else hash[key] = value;
426   - }
427   - return hash;
428   - });
429   - },
430   -
431   - toArray: function() {
432   - return this.split('');
433   - },
434   -
435   - succ: function() {
436   - return this.slice(0, this.length - 1) +
437   - String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
438   - },
439   -
440   - times: function(count) {
441   - return count < 1 ? '' : new Array(count + 1).join(this);
442   - },
443   -
444   - camelize: function() {
445   - var parts = this.split('-'), len = parts.length;
446   - if (len == 1) return parts[0];
447   -
448   - var camelized = this.charAt(0) == '-'
449   - ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
450   - : parts[0];
451   -
452   - for (var i = 1; i < len; i++)
453   - camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
454   -
455   - return camelized;
456   - },
457   -
458   - capitalize: function() {
459   - return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
460   - },
461   -
462   - underscore: function() {
463   - return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
464   - },
465   -
466   - dasherize: function() {
467   - return this.gsub(/_/,'-');
468   - },
469   -
470   - inspect: function(useDoubleQuotes) {
471   - var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
472   - var character = String.specialChar[match[0]];
473   - return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
474   - });
475   - if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
476   - return "'" + escapedString.replace(/'/g, '\\\'') + "'";
477   - },
478   -
479   - toJSON: function() {
480   - return this.inspect(true);
481   - },
482   -
483   - unfilterJSON: function(filter) {
484   - return this.sub(filter || Prototype.JSONFilter, '#{1}');
485   - },
486   -
487   - isJSON: function() {
488   - var str = this;
489   - if (str.blank()) return false;
490   - str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
491   - return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
492   - },
493   -
494   - evalJSON: function(sanitize) {
495   - var json = this.unfilterJSON();
496   - try {
497   - if (!sanitize || json.isJSON()) return eval('(' + json + ')');
498   - } catch (e) { }
499   - throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
500   - },
501   -
502   - include: function(pattern) {
503   - return this.indexOf(pattern) > -1;
504   - },
505   -
506   - startsWith: function(pattern) {
507   - return this.indexOf(pattern) === 0;
508   - },
509   -
510   - endsWith: function(pattern) {
511   - var d = this.length - pattern.length;
512   - return d >= 0 && this.lastIndexOf(pattern) === d;
513   - },
514   -
515   - empty: function() {
516   - return this == '';
517   - },
518   -
519   - blank: function() {
520   - return /^\s*$/.test(this);
521   - },
522   -
523   - interpolate: function(object, pattern) {
524   - return new Template(this, pattern).evaluate(object);
525   - }
526   -});
527   -
528   -if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
529   - escapeHTML: function() {
530   - return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
531   - },
532   - unescapeHTML: function() {
533   - return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
534   - }
535   -});
536   -
537   -String.prototype.gsub.prepareReplacement = function(replacement) {
538   - if (Object.isFunction(replacement)) return replacement;
539   - var template = new Template(replacement);
540   - return function(match) { return template.evaluate(match) };
541   -};
542   -
543   -String.prototype.parseQuery = String.prototype.toQueryParams;
544   -
545   -Object.extend(String.prototype.escapeHTML, {
546   - div: document.createElement('div'),
547   - text: document.createTextNode('')
548   -});
549   -
550   -with (String.prototype.escapeHTML) div.appendChild(text);
551   -
552   -var Template = Class.create({
553   - initialize: function(template, pattern) {
554   - this.template = template.toString();
555   - this.pattern = pattern || Template.Pattern;
556   - },
557   -
558   - evaluate: function(object) {
559   - if (Object.isFunction(object.toTemplateReplacements))
560   - object = object.toTemplateReplacements();
561   -
562   - return this.template.gsub(this.pattern, function(match) {
563   - if (object == null) return '';
564   -
565   - var before = match[1] || '';
566   - if (before == '\\') return match[2];
567   -
568   - var ctx = object, expr = match[3];
569   - var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
570   - match = pattern.exec(expr);
571   - if (match == null) return before;
572   -
573   - while (match != null) {
574   - var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
575   - ctx = ctx[comp];
576   - if (null == ctx || '' == match[3]) break;
577   - expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
578   - match = pattern.exec(expr);
579   - }
580   -
581   - return before + String.interpret(ctx);
582   - });
583   - }
584   -});
585   -Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
586   -
587   -var $break = { };
588   -
589   -var Enumerable = {
590   - each: function(iterator, context) {
591   - var index = 0;
592   - iterator = iterator.bind(context);
593   - try {
594   - this._each(function(value) {
595   - iterator(value, index++);
596   - });
597   - } catch (e) {
598   - if (e != $break) throw e;
599   - }
600   - return this;
601   - },
602   -
603   - eachSlice: function(number, iterator, context) {
604   - iterator = iterator ? iterator.bind(context) : Prototype.K;
605   - var index = -number, slices = [], array = this.toArray();
606   - while ((index += number) < array.length)
607   - slices.push(array.slice(index, index+number));
608   - return slices.collect(iterator, context);
609   - },
610   -
611   - all: function(iterator, context) {
612   - iterator = iterator ? iterator.bind(context) : Prototype.K;
613   - var result = true;
614   - this.each(function(value, index) {
615   - result = result && !!iterator(value, index);
616   - if (!result) throw $break;
617   - });
618   - return result;
619   - },
620   -
621   - any: function(iterator, context) {
622   - iterator = iterator ? iterator.bind(context) : Prototype.K;
623   - var result = false;
624   - this.each(function(value, index) {
625   - if (result = !!iterator(value, index))
626   - throw $break;
627   - });
628   - return result;
629   - },
630   -
631   - collect: function(iterator, context) {
632   - iterator = iterator ? iterator.bind(context) : Prototype.K;
633   - var results = [];
634   - this.each(function(value, index) {
635   - results.push(iterator(value, index));
636   - });
637   - return results;
638   - },
639   -
640   - detect: function(iterator, context) {
641   - iterator = iterator.bind(context);
642   - var result;
643   - this.each(function(value, index) {
644   - if (iterator(value, index)) {
645   - result = value;
646   - throw $break;
647   - }
648   - });
649   - return result;
650   - },
651   -
652   - findAll: function(iterator, context) {
653   - iterator = iterator.bind(context);
654   - var results = [];
655   - this.each(function(value, index) {
656   - if (iterator(value, index))
657   - results.push(value);
658   - });
659   - return results;
660   - },
661   -
662   - grep: function(filter, iterator, context) {
663   - iterator = iterator ? iterator.bind(context) : Prototype.K;
664   - var results = [];
665   -
666   - if (Object.isString(filter))
667   - filter = new RegExp(filter);
668   -
669   - this.each(function(value, index) {
670   - if (filter.match(value))
671   - results.push(iterator(value, index));
672   - });
673   - return results;
674   - },
675   -
676   - include: function(object) {
677   - if (Object.isFunction(this.indexOf))
678   - if (this.indexOf(object) != -1) return true;
679   -
680   - var found = false;
681   - this.each(function(value) {
682   - if (value == object) {
683   - found = true;
684   - throw $break;
685   - }
686   - });
687   - return found;
688   - },
689   -
690   - inGroupsOf: function(number, fillWith) {
691   - fillWith = Object.isUndefined(fillWith) ? null : fillWith;
692   - return this.eachSlice(number, function(slice) {
693   - while(slice.length < number) slice.push(fillWith);
694   - return slice;
695   - });
696   - },
697   -
698   - inject: function(memo, iterator, context) {
699   - iterator = iterator.bind(context);
700   - this.each(function(value, index) {
701   - memo = iterator(memo, value, index);
702   - });
703   - return memo;
704   - },
705   -
706   - invoke: function(method) {
707   - var args = $A(arguments).slice(1);
708   - return this.map(function(value) {
709   - return value[method].apply(value, args);
710   - });
711   - },
712   -
713   - max: function(iterator, context) {
714   - iterator = iterator ? iterator.bind(context) : Prototype.K;
715   - var result;
716   - this.each(function(value, index) {
717   - value = iterator(value, index);
718   - if (result == null || value >= result)
719   - result = value;
720   - });
721   - return result;
722   - },
723   -
724   - min: function(iterator, context) {
725   - iterator = iterator ? iterator.bind(context) : Prototype.K;
726   - var result;
727   - this.each(function(value, index) {
728   - value = iterator(value, index);
729   - if (result == null || value < result)
730   - result = value;
731   - });
732   - return result;
733   - },
734   -
735   - partition: function(iterator, context) {
736   - iterator = iterator ? iterator.bind(context) : Prototype.K;
737   - var trues = [], falses = [];
738   - this.each(function(value, index) {
739   - (iterator(value, index) ?
740   - trues : falses).push(value);
741   - });
742   - return [trues, falses];
743   - },
744   -
745   - pluck: function(property) {
746   - var results = [];
747   - this.each(function(value) {
748   - results.push(value[property]);
749   - });
750   - return results;
751   - },
752   -
753   - reject: function(iterator, context) {
754   - iterator = iterator.bind(context);
755   - var results = [];
756   - this.each(function(value, index) {
757   - if (!iterator(value, index))
758   - results.push(value);
759   - });
760   - return results;
761   - },
762   -
763   - sortBy: function(iterator, context) {
764   - iterator = iterator.bind(context);
765   - return this.map(function(value, index) {
766   - return {value: value, criteria: iterator(value, index)};
767   - }).sort(function(left, right) {
768   - var a = left.criteria, b = right.criteria;
769   - return a < b ? -1 : a > b ? 1 : 0;
770   - }).pluck('value');
771   - },
772   -
773   - toArray: function() {
774   - return this.map();
775   - },
776   -
777   - zip: function() {
778   - var iterator = Prototype.K, args = $A(arguments);
779   - if (Object.isFunction(args.last()))
780   - iterator = args.pop();
781   -
782   - var collections = [this].concat(args).map($A);
783   - return this.map(function(value, index) {
784   - return iterator(collections.pluck(index));
785   - });
786   - },
787   -
788   - size: function() {
789   - return this.toArray().length;
790   - },
791   -
792   - inspect: function() {
793   - return '#<Enumerable:' + this.toArray().inspect() + '>';
794   - }
795   -};
796   -
797   -Object.extend(Enumerable, {
798   - map: Enumerable.collect,
799   - find: Enumerable.detect,
800   - select: Enumerable.findAll,
801   - filter: Enumerable.findAll,
802   - member: Enumerable.include,
803   - entries: Enumerable.toArray,
804   - every: Enumerable.all,
805   - some: Enumerable.any
806   -});
807   -function $A(iterable) {
808   - if (!iterable) return [];
809   - if (iterable.toArray) return iterable.toArray();
810   - var length = iterable.length || 0, results = new Array(length);
811   - while (length--) results[length] = iterable[length];
812   - return results;
813   -}
814   -
815   -if (Prototype.Browser.WebKit) {
816   - $A = function(iterable) {
817   - if (!iterable) return [];
818   - if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
819   - iterable.toArray) return iterable.toArray();
820   - var length = iterable.length || 0, results = new Array(length);
821   - while (length--) results[length] = iterable[length];
822   - return results;
823   - };
824   -}
825   -
826   -Array.from = $A;
827   -
828   -Object.extend(Array.prototype, Enumerable);
829   -
830   -if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;
831   -
832   -Object.extend(Array.prototype, {
833   - _each: function(iterator) {
834   - for (var i = 0, length = this.length; i < length; i++)
835   - iterator(this[i]);
836   - },
837   -
838   - clear: function() {
839   - this.length = 0;
840   - return this;
841   - },
842   -
843   - first: function() {
844   - return this[0];
845   - },
846   -
847   - last: function() {
848   - return this[this.length - 1];
849   - },
850   -
851   - compact: function() {
852   - return this.select(function(value) {
853   - return value != null;
854   - });
855   - },
856   -
857   - flatten: function() {
858   - return this.inject([], function(array, value) {
859   - return array.concat(Object.isArray(value) ?
860   - value.flatten() : [value]);
861   - });
862   - },
863   -
864   - without: function() {
865   - var values = $A(arguments);
866   - return this.select(function(value) {
867   - return !values.include(value);
868   - });
869   - },
870   -
871   - reverse: function(inline) {
872   - return (inline !== false ? this : this.toArray())._reverse();
873   - },
874   -
875   - reduce: function() {
876   - return this.length > 1 ? this : this[0];
877   - },
878   -
879   - uniq: function(sorted) {
880   - return this.inject([], function(array, value, index) {
881   - if (0 == index || (sorted ? array.last() != value : !array.include(value)))
882   - array.push(value);
883   - return array;
884   - });
885   - },
886   -
887   - intersect: function(array) {
888   - return this.uniq().findAll(function(item) {
889   - return array.detect(function(value) { return item === value });
890   - });
891   - },
892   -
893   - clone: function() {
894   - return [].concat(this);
895   - },
896   -
897   - size: function() {
898   - return this.length;
899   - },
900   -
901   - inspect: function() {
902   - return '[' + this.map(Object.inspect).join(', ') + ']';
903   - },
904   -
905   - toJSON: function() {
906   - var results = [];
907   - this.each(function(object) {
908   - var value = Object.toJSON(object);
909   - if (!Object.isUndefined(value)) results.push(value);
910   - });
911   - return '[' + results.join(', ') + ']';
912   - }
913   -});
914   -
915   -// use native browser JS 1.6 implementation if available
916   -if (Object.isFunction(Array.prototype.forEach))
917   - Array.prototype._each = Array.prototype.forEach;
918   -
919   -if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {
920   - i || (i = 0);
921   - var length = this.length;
922   - if (i < 0) i = length + i;
923   - for (; i < length; i++)
924   - if (this[i] === item) return i;
925   - return -1;
926   -};
927   -
928   -if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {
929   - i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
930   - var n = this.slice(0, i).reverse().indexOf(item);
931   - return (n < 0) ? n : i - n - 1;
932   -};
933   -
934   -Array.prototype.toArray = Array.prototype.clone;
935   -
936   -function $w(string) {
937   - if (!Object.isString(string)) return [];
938   - string = string.strip();
939   - return string ? string.split(/\s+/) : [];
940   -}
941   -
942   -if (Prototype.Browser.Opera){
943   - Array.prototype.concat = function() {
944   - var array = [];
945   - for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
946   - for (var i = 0, length = arguments.length; i < length; i++) {
947   - if (Object.isArray(arguments[i])) {
948   - for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
949   - array.push(arguments[i][j]);
950   - } else {
951   - array.push(arguments[i]);
952   - }
953   - }
954   - return array;
955   - };
956   -}
957   -Object.extend(Number.prototype, {
958   - toColorPart: function() {
959   - return this.toPaddedString(2, 16);
960   - },
961   -
962   - succ: function() {
963   - return this + 1;
964   - },
965   -
966   - times: function(iterator) {
967   - $R(0, this, true).each(iterator);
968   - return this;
969   - },
970   -
971   - toPaddedString: function(length, radix) {
972   - var string = this.toString(radix || 10);
973   - return '0'.times(length - string.length) + string;
974   - },
975   -
976   - toJSON: function() {
977   - return isFinite(this) ? this.toString() : 'null';
978   - }
979   -});
980   -
981   -$w('abs round ceil floor').each(function(method){
982   - Number.prototype[method] = Math[method].methodize();
983   -});
984   -function $H(object) {
985   - return new Hash(object);
986   -};
987   -
988   -var Hash = Class.create(Enumerable, (function() {
989   -
990   - function toQueryPair(key, value) {
991   - if (Object.isUndefined(value)) return key;
992   - return key + '=' + encodeURIComponent(String.interpret(value));
993   - }
994   -
995   - return {
996   - initialize: function(object) {
997   - this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
998   - },
999   -
1000   - _each: function(iterator) {
1001   - for (var key in this._object) {
1002   - var value = this._object[key], pair = [key, value];
1003   - pair.key = key;
1004   - pair.value = value;
1005   - iterator(pair);
1006   - }
1007   - },
1008   -
1009   - set: function(key, value) {
1010   - return this._object[key] = value;
1011   - },
1012   -
1013   - get: function(key) {
1014   - return this._object[key];
1015   - },
1016   -
1017   - unset: function(key) {
1018   - var value = this._object[key];
1019   - delete this._object[key];
1020   - return value;
1021   - },
1022   -
1023   - toObject: function() {
1024   - return Object.clone(this._object);
1025   - },
1026   -
1027   - keys: function() {
1028   - return this.pluck('key');
1029   - },
1030   -
1031   - values: function() {
1032   - return this.pluck('value');
1033   - },
1034   -
1035   - index: function(value) {
1036   - var match = this.detect(function(pair) {
1037   - return pair.value === value;
1038   - });
1039   - return match && match.key;
1040   - },
1041   -
1042   - merge: function(object) {
1043   - return this.clone().update(object);
1044   - },
1045   -
1046   - update: function(object) {
1047   - return new Hash(object).inject(this, function(result, pair) {
1048   - result.set(pair.key, pair.value);
1049   - return result;
1050   - });
1051   - },
1052   -
1053   - toQueryString: function() {
1054   - return this.map(function(pair) {
1055   - var key = encodeURIComponent(pair.key), values = pair.value;
1056   -
1057   - if (values && typeof values == 'object') {
1058   - if (Object.isArray(values))
1059   - return values.map(toQueryPair.curry(key)).join('&');
1060   - }
1061   - return toQueryPair(key, values);
1062   - }).join('&');
1063   - },
1064   -
1065   - inspect: function() {
1066   - return '#<Hash:{' + this.map(function(pair) {
1067   - return pair.map(Object.inspect).join(': ');
1068   - }).join(', ') + '}>';
1069   - },
1070   -
1071   - toJSON: function() {
1072   - return Object.toJSON(this.toObject());
1073   - },
1074   -
1075   - clone: function() {
1076   - return new Hash(this);
1077   - }
1078   - }
1079   -})());
1080   -
1081   -Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;
1082   -Hash.from = $H;
1083   -var ObjectRange = Class.create(Enumerable, {
1084   - initialize: function(start, end, exclusive) {
1085   - this.start = start;
1086   - this.end = end;
1087   - this.exclusive = exclusive;
1088   - },
1089   -
1090   - _each: function(iterator) {
1091   - var value = this.start;
1092   - while (this.include(value)) {
1093   - iterator(value);
1094   - value = value.succ();
1095   - }
1096   - },
1097   -
1098   - include: function(value) {
1099   - if (value < this.start)
1100   - return false;
1101   - if (this.exclusive)
1102   - return value < this.end;
1103   - return value <= this.end;
1104   - }
1105   -});
1106   -
1107   -var $R = function(start, end, exclusive) {
1108   - return new ObjectRange(start, end, exclusive);
1109   -};
1110   -
1111   -var Ajax = {
1112   - getTransport: function() {
1113   - return Try.these(
1114   - function() {return new XMLHttpRequest()},
1115   - function() {return new ActiveXObject('Msxml2.XMLHTTP')},
1116   - function() {return new ActiveXObject('Microsoft.XMLHTTP')}
1117   - ) || false;
1118   - },
1119   -
1120   - activeRequestCount: 0
1121   -};
1122   -
1123   -Ajax.Responders = {
1124   - responders: [],
1125   -
1126   - _each: function(iterator) {
1127   - this.responders._each(iterator);
1128   - },
1129   -
1130   - register: function(responder) {
1131   - if (!this.include(responder))
1132   - this.responders.push(responder);
1133   - },
1134   -
1135   - unregister: function(responder) {
1136   - this.responders = this.responders.without(responder);
1137   - },
1138   -
1139   - dispatch: function(callback, request, transport, json) {
1140   - this.each(function(responder) {
1141   - if (Object.isFunction(responder[callback])) {
1142   - try {
1143   - responder[callback].apply(responder, [request, transport, json]);
1144   - } catch (e) { }
1145   - }
1146   - });
1147   - }
1148   -};
1149   -
1150   -Object.extend(Ajax.Responders, Enumerable);
1151   -
1152   -Ajax.Responders.register({
1153   - onCreate: function() { Ajax.activeRequestCount++ },
1154   - onComplete: function() { Ajax.activeRequestCount-- }
1155   -});
1156   -
1157   -Ajax.Base = Class.create({
1158   - initialize: function(options) {
1159   - this.options = {
1160   - method: 'post',
1161   - asynchronous: true,
1162   - contentType: 'application/x-www-form-urlencoded',
1163   - encoding: 'UTF-8',
1164   - parameters: '',
1165   - evalJSON: true,
1166   - evalJS: true
1167   - };
1168   - Object.extend(this.options, options || { });
1169   -
1170   - this.options.method = this.options.method.toLowerCase();
1171   -
1172   - if (Object.isString(this.options.parameters))
1173   - this.options.parameters = this.options.parameters.toQueryParams();
1174   - else if (Object.isHash(this.options.parameters))
1175   - this.options.parameters = this.options.parameters.toObject();
1176   - }
1177   -});
1178   -
1179   -Ajax.Request = Class.create(Ajax.Base, {
1180   - _complete: false,
1181   -
1182   - initialize: function($super, url, options) {
1183   - $super(options);
1184   - this.transport = Ajax.getTransport();
1185   - this.request(url);
1186   - },
1187   -
1188   - request: function(url) {
1189   - this.url = url;
1190   - this.method = this.options.method;
1191   - var params = Object.clone(this.options.parameters);
1192   -
1193   - if (!['get', 'post'].include(this.method)) {
1194   - // simulate other verbs over post
1195   - params['_method'] = this.method;
1196   - this.method = 'post';
1197   - }
1198   -
1199   - this.parameters = params;
1200   -
1201   - if (params = Object.toQueryString(params)) {
1202   - // when GET, append parameters to URL
1203   - if (this.method == 'get')
1204   - this.url += (this.url.include('?') ? '&' : '?') + params;
1205   - else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
1206   - params += '&_=';
1207   - }
1208   -
1209   - try {
1210   - var response = new Ajax.Response(this);
1211   - if (this.options.onCreate) this.options.onCreate(response);
1212   - Ajax.Responders.dispatch('onCreate', this, response);
1213   -
1214   - this.transport.open(this.method.toUpperCase(), this.url,
1215   - this.options.asynchronous);
1216   -
1217   - if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
1218   -
1219   - this.transport.onreadystatechange = this.onStateChange.bind(this);
1220   - this.setRequestHeaders();
1221   -
1222   - this.body = this.method == 'post' ? (this.options.postBody || params) : null;
1223   - this.transport.send(this.body);
1224   -
1225   - /* Force Firefox to handle ready state 4 for synchronous requests */
1226   - if (!this.options.asynchronous && this.transport.overrideMimeType)
1227   - this.onStateChange();
1228   -
1229   - }
1230   - catch (e) {
1231   - this.dispatchException(e);
1232   - }
1233   - },
1234   -
1235   - onStateChange: function() {
1236   - var readyState = this.transport.readyState;
1237   - if (readyState > 1 && !((readyState == 4) && this._complete))
1238   - this.respondToReadyState(this.transport.readyState);
1239   - },
1240   -
1241   - setRequestHeaders: function() {
1242   - var headers = {
1243   - 'X-Requested-With': 'XMLHttpRequest',
1244   - 'X-Prototype-Version': Prototype.Version,
1245   - 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
1246   - };
1247   -
1248   - if (this.method == 'post') {
1249   - headers['Content-type'] = this.options.contentType +
1250   - (this.options.encoding ? '; charset=' + this.options.encoding : '');
1251   -
1252   - /* Force "Connection: close" for older Mozilla browsers to work
1253   - * around a bug where XMLHttpRequest sends an incorrect
1254   - * Content-length header. See Mozilla Bugzilla #246651.
1255   - */
1256   - if (this.transport.overrideMimeType &&
1257   - (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
1258   - headers['Connection'] = 'close';
1259   - }
1260   -
1261   - // user-defined headers
1262   - if (typeof this.options.requestHeaders == 'object') {
1263   - var extras = this.options.requestHeaders;
1264   -
1265   - if (Object.isFunction(extras.push))
1266   - for (var i = 0, length = extras.length; i < length; i += 2)
1267   - headers[extras[i]] = extras[i+1];
1268   - else
1269   - $H(extras).each(function(pair) { headers[pair.key] = pair.value });
1270   - }
1271   -
1272   - for (var name in headers)
1273   - this.transport.setRequestHeader(name, headers[name]);
1274   - },
1275   -
1276   - success: function() {
1277   - var status = this.getStatus();
1278   - return !status || (status >= 200 && status < 300);
1279   - },
1280   -
1281   - getStatus: function() {
1282   - try {
1283   - return this.transport.status || 0;
1284   - } catch (e) { return 0 }
1285   - },
1286   -
1287   - respondToReadyState: function(readyState) {
1288   - var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
1289   -
1290   - if (state == 'Complete') {
1291   - try {
1292   - this._complete = true;
1293   - (this.options['on' + response.status]
1294   - || this.options['on' + (this.success() ? 'Success' : 'Failure')]
1295   - || Prototype.emptyFunction)(response, response.headerJSON);
1296   - } catch (e) {
1297   - this.dispatchException(e);
1298   - }
1299   -
1300   - var contentType = response.getHeader('Content-type');
1301   - if (this.options.evalJS == 'force'
1302   - || (this.options.evalJS && this.isSameOrigin() && contentType
1303   - && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
1304   - this.evalResponse();
1305   - }
1306   -
1307   - try {
1308   - (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
1309   - Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
1310   - } catch (e) {
1311   - this.dispatchException(e);
1312   - }
1313   -
1314   - if (state == 'Complete') {
1315   - // avoid memory leak in MSIE: clean up
1316   - this.transport.onreadystatechange = Prototype.emptyFunction;
1317   - }
1318   - },
1319   -
1320   - isSameOrigin: function() {
1321   - var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
1322   - return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
1323   - protocol: location.protocol,
1324   - domain: document.domain,
1325   - port: location.port ? ':' + location.port : ''
1326   - }));
1327   - },
1328   -
1329   - getHeader: function(name) {
1330   - try {
1331   - return this.transport.getResponseHeader(name) || null;
1332   - } catch (e) { return null }
1333   - },
1334   -
1335   - evalResponse: function() {
1336   - try {
1337   - return eval((this.transport.responseText || '').unfilterJSON());
1338   - } catch (e) {
1339   - this.dispatchException(e);
1340   - }
1341   - },
1342   -
1343   - dispatchException: function(exception) {
1344   - (this.options.onException || Prototype.emptyFunction)(this, exception);
1345   - Ajax.Responders.dispatch('onException', this, exception);
1346   - }
1347   -});
1348   -
1349   -Ajax.Request.Events =
1350   - ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
1351   -
1352   -Ajax.Response = Class.create({
1353   - initialize: function(request){
1354   - this.request = request;
1355   - var transport = this.transport = request.transport,
1356   - readyState = this.readyState = transport.readyState;
1357   -
1358   - if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
1359   - this.status = this.getStatus();
1360   - this.statusText = this.getStatusText();
1361   - this.responseText = String.interpret(transport.responseText);
1362   - this.headerJSON = this._getHeaderJSON();
1363   - }
1364   -
1365   - if(readyState == 4) {
1366   - var xml = transport.responseXML;
1367   - this.responseXML = Object.isUndefined(xml) ? null : xml;
1368   - this.responseJSON = this._getResponseJSON();
1369   - }
1370   - },
1371   -
1372   - status: 0,
1373   - statusText: '',
1374   -
1375   - getStatus: Ajax.Request.prototype.getStatus,
1376   -
1377   - getStatusText: function() {
1378   - try {
1379   - return this.transport.statusText || '';
1380   - } catch (e) { return '' }
1381   - },
1382   -
1383   - getHeader: Ajax.Request.prototype.getHeader,
1384   -
1385   - getAllHeaders: function() {
1386   - try {
1387   - return this.getAllResponseHeaders();
1388   - } catch (e) { return null }
1389   - },
1390   -
1391   - getResponseHeader: function(name) {
1392   - return this.transport.getResponseHeader(name);
1393   - },
1394   -
1395   - getAllResponseHeaders: function() {
1396   - return this.transport.getAllResponseHeaders();
1397   - },
1398   -
1399   - _getHeaderJSON: function() {
1400   - var json = this.getHeader('X-JSON');
1401   - if (!json) return null;
1402   - json = decodeURIComponent(escape(json));
1403   - try {
1404   - return json.evalJSON(this.request.options.sanitizeJSON ||
1405   - !this.request.isSameOrigin());
1406   - } catch (e) {
1407   - this.request.dispatchException(e);
1408   - }
1409   - },
1410   -
1411   - _getResponseJSON: function() {
1412   - var options = this.request.options;
1413   - if (!options.evalJSON || (options.evalJSON != 'force' &&
1414   - !(this.getHeader('Content-type') || '').include('application/json')) ||
1415   - this.responseText.blank())
1416   - return null;
1417   - try {
1418   - return this.responseText.evalJSON(options.sanitizeJSON ||
1419   - !this.request.isSameOrigin());
1420   - } catch (e) {
1421   - this.request.dispatchException(e);
1422   - }
1423   - }
1424   -});
1425   -
1426   -Ajax.Updater = Class.create(Ajax.Request, {
1427   - initialize: function($super, container, url, options) {
1428   - this.container = {
1429   - success: (container.success || container),
1430   - failure: (container.failure || (container.success ? null : container))
1431   - };
1432   -
1433   - options = Object.clone(options);
1434   - var onComplete = options.onComplete;
1435   - options.onComplete = (function(response, json) {
1436   - this.updateContent(response.responseText);
1437   - if (Object.isFunction(onComplete)) onComplete(response, json);
1438   - }).bind(this);
1439   -
1440   - $super(url, options);
1441   - },
1442   -
1443   - updateContent: function(responseText) {
1444   - var receiver = this.container[this.success() ? 'success' : 'failure'],
1445   - options = this.options;
1446   -
1447   - if (!options.evalScripts) responseText = responseText.stripScripts();
1448   -
1449   - if (receiver = $(receiver)) {
1450   - if (options.insertion) {
1451   - if (Object.isString(options.insertion)) {
1452   - var insertion = { }; insertion[options.insertion] = responseText;
1453   - receiver.insert(insertion);
1454   - }
1455   - else options.insertion(receiver, responseText);
1456   - }
1457   - else receiver.update(responseText);
1458   - }
1459   - }
1460   -});
1461   -
1462   -Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
1463   - initialize: function($super, container, url, options) {
1464   - $super(options);
1465   - this.onComplete = this.options.onComplete;
1466   -
1467   - this.frequency = (this.options.frequency || 2);
1468   - this.decay = (this.options.decay || 1);
1469   -
1470   - this.updater = { };
1471   - this.container = container;
1472   - this.url = url;
1473   -
1474   - this.start();
1475   - },
1476   -
1477   - start: function() {
1478   - this.options.onComplete = this.updateComplete.bind(this);
1479   - this.onTimerEvent();
1480   - },
1481   -
1482   - stop: function() {
1483   - this.updater.options.onComplete = undefined;
1484   - clearTimeout(this.timer);
1485   - (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
1486   - },
1487   -
1488   - updateComplete: function(response) {
1489   - if (this.options.decay) {
1490   - this.decay = (response.responseText == this.lastText ?
1491   - this.decay * this.options.decay : 1);
1492   -
1493   - this.lastText = response.responseText;
1494   - }
1495   - this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
1496   - },
1497   -
1498   - onTimerEvent: function() {
1499   - this.updater = new Ajax.Updater(this.container, this.url, this.options);
1500   - }
1501   -});
1502   -function $(element) {
1503   - if (arguments.length > 1) {
1504   - for (var i = 0, elements = [], length = arguments.length; i < length; i++)
1505   - elements.push($(arguments[i]));
1506   - return elements;
1507   - }
1508   - if (Object.isString(element))
1509   - element = document.getElementById(element);
1510   - return Element.extend(element);
1511   -}
1512   -
1513   -if (Prototype.BrowserFeatures.XPath) {
1514   - document._getElementsByXPath = function(expression, parentElement) {
1515   - var results = [];
1516   - var query = document.evaluate(expression, $(parentElement) || document,
1517   - null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
1518   - for (var i = 0, length = query.snapshotLength; i < length; i++)
1519   - results.push(Element.extend(query.snapshotItem(i)));
1520   - return results;
1521   - };
1522   -}
1523   -
1524   -/*--------------------------------------------------------------------------*/
1525   -
1526   -if (!window.Node) var Node = { };
1527   -
1528   -if (!Node.ELEMENT_NODE) {
1529   - // DOM level 2 ECMAScript Language Binding
1530   - Object.extend(Node, {
1531   - ELEMENT_NODE: 1,
1532   - ATTRIBUTE_NODE: 2,
1533   - TEXT_NODE: 3,
1534   - CDATA_SECTION_NODE: 4,
1535   - ENTITY_REFERENCE_NODE: 5,
1536   - ENTITY_NODE: 6,
1537   - PROCESSING_INSTRUCTION_NODE: 7,
1538   - COMMENT_NODE: 8,
1539   - DOCUMENT_NODE: 9,
1540   - DOCUMENT_TYPE_NODE: 10,
1541   - DOCUMENT_FRAGMENT_NODE: 11,
1542   - NOTATION_NODE: 12
1543   - });
1544   -}
1545   -
1546   -(function() {
1547   - var element = this.Element;
1548   - this.Element = function(tagName, attributes) {
1549   - attributes = attributes || { };
1550   - tagName = tagName.toLowerCase();
1551   - var cache = Element.cache;
1552   - if (Prototype.Browser.IE && attributes.name) {
1553   - tagName = '<' + tagName + ' name="' + attributes.name + '">';
1554   - delete attributes.name;
1555   - return Element.writeAttribute(document.createElement(tagName), attributes);
1556   - }
1557   - if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
1558   - return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
1559   - };
1560   - Object.extend(this.Element, element || { });
1561   -}).call(window);
1562   -
1563   -Element.cache = { };
1564   -
1565   -Element.Methods = {
1566   - visible: function(element) {
1567   - return $(element).style.display != 'none';
1568   - },
1569   -
1570   - toggle: function(element) {
1571   - element = $(element);
1572   - Element[Element.visible(element) ? 'hide' : 'show'](element);
1573   - return element;
1574   - },
1575   -
1576   - hide: function(element) {
1577   - $(element).style.display = 'none';
1578   - return element;
1579   - },
1580   -
1581   - show: function(element) {
1582   - $(element).style.display = '';
1583   - return element;
1584   - },
1585   -
1586   - remove: function(element) {
1587   - element = $(element);
1588   - element.parentNode.removeChild(element);
1589   - return element;
1590   - },
1591   -
1592   - update: function(element, content) {
1593   - element = $(element);
1594   - if (content && content.toElement) content = content.toElement();
1595   - if (Object.isElement(content)) return element.update().insert(content);
1596   - content = Object.toHTML(content);
1597   - element.innerHTML = content.stripScripts();
1598   - content.evalScripts.bind(content).defer();
1599   - return element;
1600   - },
1601   -
1602   - replace: function(element, content) {
1603   - element = $(element);
1604   - if (content && content.toElement) content = content.toElement();
1605   - else if (!Object.isElement(content)) {
1606   - content = Object.toHTML(content);
1607   - var range = element.ownerDocument.createRange();
1608   - range.selectNode(element);
1609   - content.evalScripts.bind(content).defer();
1610   - content = range.createContextualFragment(content.stripScripts());
1611   - }
1612   - element.parentNode.replaceChild(content, element);
1613   - return element;
1614   - },
1615   -
1616   - insert: function(element, insertions) {
1617   - element = $(element);
1618   -
1619   - if (Object.isString(insertions) || Object.isNumber(insertions) ||
1620   - Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
1621   - insertions = {bottom:insertions};
1622   -
1623   - var content, insert, tagName, childNodes;
1624   -
1625   - for (var position in insertions) {
1626   - content = insertions[position];
1627   - position = position.toLowerCase();
1628   - insert = Element._insertionTranslations[position];
1629   -
1630   - if (content && content.toElement) content = content.toElement();
1631   - if (Object.isElement(content)) {
1632   - insert(element, content);
1633   - continue;
1634   - }
1635   -
1636   - content = Object.toHTML(content);
1637   -
1638   - tagName = ((position == 'before' || position == 'after')
1639   - ? element.parentNode : element).tagName.toUpperCase();
1640   -
1641   - childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
1642   -
1643   - if (position == 'top' || position == 'after') childNodes.reverse();
1644   - childNodes.each(insert.curry(element));
1645   -
1646   - content.evalScripts.bind(content).defer();
1647   - }
1648   -
1649   - return element;
1650   - },
1651   -
1652   - wrap: function(element, wrapper, attributes) {
1653   - element = $(element);
1654   - if (Object.isElement(wrapper))
1655   - $(wrapper).writeAttribute(attributes || { });
1656   - else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
1657   - else wrapper = new Element('div', wrapper);
1658   - if (element.parentNode)
1659   - element.parentNode.replaceChild(wrapper, element);
1660   - wrapper.appendChild(element);
1661   - return wrapper;
1662   - },
1663   -
1664   - inspect: function(element) {
1665   - element = $(element);
1666   - var result = '<' + element.tagName.toLowerCase();
1667   - $H({'id': 'id', 'className': 'class'}).each(function(pair) {
1668   - var property = pair.first(), attribute = pair.last();
1669   - var value = (element[property] || '').toString();
1670   - if (value) result += ' ' + attribute + '=' + value.inspect(true);
1671   - });
1672   - return result + '>';
1673   - },
1674   -
1675   - recursivelyCollect: function(element, property) {
1676   - element = $(element);
1677   - var elements = [];
1678   - while (element = element[property])
1679   - if (element.nodeType == 1)
1680   - elements.push(Element.extend(element));
1681   - return elements;
1682   - },
1683   -
1684   - ancestors: function(element) {
1685   - return $(element).recursivelyCollect('parentNode');
1686   - },
1687   -
1688   - descendants: function(element) {
1689   - return $(element).select("*");
1690   - },
1691   -
1692   - firstDescendant: function(element) {
1693   - element = $(element).firstChild;
1694   - while (element && element.nodeType != 1) element = element.nextSibling;
1695   - return $(element);
1696   - },
1697   -
1698   - immediateDescendants: function(element) {
1699   - if (!(element = $(element).firstChild)) return [];
1700   - while (element && element.nodeType != 1) element = element.nextSibling;
1701   - if (element) return [element].concat($(element).nextSiblings());
1702   - return [];
1703   - },
1704   -
1705   - previousSiblings: function(element) {
1706   - return $(element).recursivelyCollect('previousSibling');
1707   - },
1708   -
1709   - nextSiblings: function(element) {
1710   - return $(element).recursivelyCollect('nextSibling');
1711   - },
1712   -
1713   - siblings: function(element) {
1714   - element = $(element);
1715   - return element.previousSiblings().reverse().concat(element.nextSiblings());
1716   - },
1717   -
1718   - match: function(element, selector) {
1719   - if (Object.isString(selector))
1720   - selector = new Selector(selector);
1721   - return selector.match($(element));
1722   - },
1723   -
1724   - up: function(element, expression, index) {
1725   - element = $(element);
1726   - if (arguments.length == 1) return $(element.parentNode);
1727   - var ancestors = element.ancestors();
1728   - return Object.isNumber(expression) ? ancestors[expression] :
1729   - Selector.findElement(ancestors, expression, index);
1730   - },
1731   -
1732   - down: function(element, expression, index) {
1733   - element = $(element);
1734   - if (arguments.length == 1) return element.firstDescendant();
1735   - return Object.isNumber(expression) ? element.descendants()[expression] :
1736   - element.select(expression)[index || 0];
1737   - },
1738   -
1739   - previous: function(element, expression, index) {
1740   - element = $(element);
1741   - if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
1742   - var previousSiblings = element.previousSiblings();
1743   - return Object.isNumber(expression) ? previousSiblings[expression] :
1744   - Selector.findElement(previousSiblings, expression, index);
1745   - },
1746   -
1747   - next: function(element, expression, index) {
1748   - element = $(element);
1749   - if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
1750   - var nextSiblings = element.nextSiblings();
1751   - return Object.isNumber(expression) ? nextSiblings[expression] :
1752   - Selector.findElement(nextSiblings, expression, index);
1753   - },
1754   -
1755   - select: function() {
1756   - var args = $A(arguments), element = $(args.shift());
1757   - return Selector.findChildElements(element, args);
1758   - },
1759   -
1760   - adjacent: function() {
1761   - var args = $A(arguments), element = $(args.shift());
1762   - return Selector.findChildElements(element.parentNode, args).without(element);
1763   - },
1764   -
1765   - identify: function(element) {
1766   - element = $(element);
1767   - var id = element.readAttribute('id'), self = arguments.callee;
1768   - if (id) return id;
1769   - do { id = 'anonymous_element_' + self.counter++ } while ($(id));
1770   - element.writeAttribute('id', id);
1771   - return id;
1772   - },
1773   -
1774   - readAttribute: function(element, name) {
1775   - element = $(element);
1776   - if (Prototype.Browser.IE) {
1777   - var t = Element._attributeTranslations.read;
1778   - if (t.values[name]) return t.values[name](element, name);
1779   - if (t.names[name]) name = t.names[name];
1780   - if (name.include(':')) {
1781   - return (!element.attributes || !element.attributes[name]) ? null :
1782   - element.attributes[name].value;
1783   - }
1784   - }
1785   - return element.getAttribute(name);
1786   - },
1787   -
1788   - writeAttribute: function(element, name, value) {
1789   - element = $(element);
1790   - var attributes = { }, t = Element._attributeTranslations.write;
1791   -
1792   - if (typeof name == 'object') attributes = name;
1793   - else attributes[name] = Object.isUndefined(value) ? true : value;
1794   -
1795   - for (var attr in attributes) {
1796   - name = t.names[attr] || attr;
1797   - value = attributes[attr];
1798   - if (t.values[attr]) name = t.values[attr](element, value);
1799   - if (value === false || value === null)
1800   - element.removeAttribute(name);
1801   - else if (value === true)
1802   - element.setAttribute(name, name);
1803   - else element.setAttribute(name, value);
1804   - }
1805   - return element;
1806   - },
1807   -
1808   - getHeight: function(element) {
1809   - return $(element).getDimensions().height;
1810   - },
1811   -
1812   - getWidth: function(element) {
1813   - return $(element).getDimensions().width;
1814   - },
1815   -
1816   - classNames: function(element) {
1817   - return new Element.ClassNames(element);
1818   - },
1819   -
1820   - hasClassName: function(element, className) {
1821   - if (!(element = $(element))) return;
1822   - var elementClassName = element.className;
1823   - return (elementClassName.length > 0 && (elementClassName == className ||
1824   - new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
1825   - },
1826   -
1827   - addClassName: function(element, className) {
1828   - if (!(element = $(element))) return;
1829   - if (!element.hasClassName(className))
1830   - element.className += (element.className ? ' ' : '') + className;
1831   - return element;
1832   - },
1833   -
1834   - removeClassName: function(element, className) {
1835   - if (!(element = $(element))) return;
1836   - element.className = element.className.replace(
1837   - new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
1838   - return element;
1839   - },
1840   -
1841   - toggleClassName: function(element, className) {
1842   - if (!(element = $(element))) return;
1843   - return element[element.hasClassName(className) ?
1844   - 'removeClassName' : 'addClassName'](className);
1845   - },
1846   -
1847   - // removes whitespace-only text node children
1848   - cleanWhitespace: function(element) {
1849   - element = $(element);
1850   - var node = element.firstChild;
1851   - while (node) {
1852   - var nextNode = node.nextSibling;
1853   - if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
1854   - element.removeChild(node);
1855   - node = nextNode;
1856   - }
1857   - return element;
1858   - },
1859   -
1860   - empty: function(element) {
1861   - return $(element).innerHTML.blank();
1862   - },
1863   -
1864   - descendantOf: function(element, ancestor) {
1865   - element = $(element), ancestor = $(ancestor);
1866   - var originalAncestor = ancestor;
1867   -
1868   - if (element.compareDocumentPosition)
1869   - return (element.compareDocumentPosition(ancestor) & 8) === 8;
1870   -
1871   - if (element.sourceIndex && !Prototype.Browser.Opera) {
1872   - var e = element.sourceIndex, a = ancestor.sourceIndex,
1873   - nextAncestor = ancestor.nextSibling;
1874   - if (!nextAncestor) {
1875   - do { ancestor = ancestor.parentNode; }
1876   - while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);
1877   - }
1878   - if (nextAncestor && nextAncestor.sourceIndex)
1879   - return (e > a && e < nextAncestor.sourceIndex);
1880   - }
1881   -
1882   - while (element = element.parentNode)
1883   - if (element == originalAncestor) return true;
1884   - return false;
1885   - },
1886   -
1887   - scrollTo: function(element) {
1888   - element = $(element);
1889   - var pos = element.cumulativeOffset();
1890   - window.scrollTo(pos[0], pos[1]);
1891   - return element;
1892   - },
1893   -
1894   - getStyle: function(element, style) {
1895   - element = $(element);
1896   - style = style == 'float' ? 'cssFloat' : style.camelize();
1897   - var value = element.style[style];
1898   - if (!value) {
1899   - var css = document.defaultView.getComputedStyle(element, null);
1900   - value = css ? css[style] : null;
1901   - }
1902   - if (style == 'opacity') return value ? parseFloat(value) : 1.0;
1903   - return value == 'auto' ? null : value;
1904   - },
1905   -
1906   - getOpacity: function(element) {
1907   - return $(element).getStyle('opacity');
1908   - },
1909   -
1910   - setStyle: function(element, styles) {
1911   - element = $(element);
1912   - var elementStyle = element.style, match;
1913   - if (Object.isString(styles)) {
1914   - element.style.cssText += ';' + styles;
1915   - return styles.include('opacity') ?
1916   - element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
1917   - }
1918   - for (var property in styles)
1919   - if (property == 'opacity') element.setOpacity(styles[property]);
1920   - else
1921   - elementStyle[(property == 'float' || property == 'cssFloat') ?
1922   - (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
1923   - property] = styles[property];
1924   -
1925   - return element;
1926   - },
1927   -
1928   - setOpacity: function(element, value) {
1929   - element = $(element);
1930   - element.style.opacity = (value == 1 || value === '') ? '' :
1931   - (value < 0.00001) ? 0 : value;
1932   - return element;
1933   - },
1934   -
1935   - getDimensions: function(element) {
1936   - element = $(element);
1937   - var display = $(element).getStyle('display');
1938   - if (display != 'none' && display != null) // Safari bug
1939   - return {width: element.offsetWidth, height: element.offsetHeight};
1940   -
1941   - // All *Width and *Height properties give 0 on elements with display none,
1942   - // so enable the element temporarily
1943   - var els = element.style;
1944   - var originalVisibility = els.visibility;
1945   - var originalPosition = els.position;
1946   - var originalDisplay = els.display;
1947   - els.visibility = 'hidden';
1948   - els.position = 'absolute';
1949   - els.display = 'block';
1950   - var originalWidth = element.clientWidth;
1951   - var originalHeight = element.clientHeight;
1952   - els.display = originalDisplay;
1953   - els.position = originalPosition;
1954   - els.visibility = originalVisibility;
1955   - return {width: originalWidth, height: originalHeight};
1956   - },
1957   -
1958   - makePositioned: function(element) {
1959   - element = $(element);
1960   - var pos = Element.getStyle(element, 'position');
1961   - if (pos == 'static' || !pos) {
1962   - element._madePositioned = true;
1963   - element.style.position = 'relative';
1964   - // Opera returns the offset relative to the positioning context, when an
1965   - // element is position relative but top and left have not been defined
1966   - if (window.opera) {
1967   - element.style.top = 0;
1968   - element.style.left = 0;
1969   - }
1970   - }
1971   - return element;
1972   - },
1973   -
1974   - undoPositioned: function(element) {
1975   - element = $(element);
1976   - if (element._madePositioned) {
1977   - element._madePositioned = undefined;
1978   - element.style.position =
1979   - element.style.top =
1980   - element.style.left =
1981   - element.style.bottom =
1982   - element.style.right = '';
1983   - }
1984   - return element;
1985   - },
1986   -
1987   - makeClipping: function(element) {
1988   - element = $(element);
1989   - if (element._overflow) return element;
1990   - element._overflow = Element.getStyle(element, 'overflow') || 'auto';
1991   - if (element._overflow !== 'hidden')
1992   - element.style.overflow = 'hidden';
1993   - return element;
1994   - },
1995   -
1996   - undoClipping: function(element) {
1997   - element = $(element);
1998   - if (!element._overflow) return element;
1999   - element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
2000   - element._overflow = null;
2001   - return element;
2002   - },
2003   -
2004   - cumulativeOffset: function(element) {
2005   - var valueT = 0, valueL = 0;
2006   - do {
2007   - valueT += element.offsetTop || 0;
2008   - valueL += element.offsetLeft || 0;
2009   - element = element.offsetParent;
2010   - } while (element);
2011   - return Element._returnOffset(valueL, valueT);
2012   - },
2013   -
2014   - positionedOffset: function(element) {
2015   - var valueT = 0, valueL = 0;
2016   - do {
2017   - valueT += element.offsetTop || 0;
2018   - valueL += element.offsetLeft || 0;
2019   - element = element.offsetParent;
2020   - if (element) {
2021   - if (element.tagName == 'BODY') break;
2022   - var p = Element.getStyle(element, 'position');
2023   - if (p !== 'static') break;
2024   - }
2025   - } while (element);
2026   - return Element._returnOffset(valueL, valueT);
2027   - },
2028   -
2029   - absolutize: function(element) {
2030   - element = $(element);
2031   - if (element.getStyle('position') == 'absolute') return;
2032   - // Position.prepare(); // To be done manually by Scripty when it needs it.
2033   -
2034   - var offsets = element.positionedOffset();
2035   - var top = offsets[1];
2036   - var left = offsets[0];
2037   - var width = element.clientWidth;
2038   - var height = element.clientHeight;
2039   -
2040   - element._originalLeft = left - parseFloat(element.style.left || 0);
2041   - element._originalTop = top - parseFloat(element.style.top || 0);
2042   - element._originalWidth = element.style.width;
2043   - element._originalHeight = element.style.height;
2044   -
2045   - element.style.position = 'absolute';
2046   - element.style.top = top + 'px';
2047   - element.style.left = left + 'px';
2048   - element.style.width = width + 'px';
2049   - element.style.height = height + 'px';
2050   - return element;
2051   - },
2052   -
2053   - relativize: function(element) {
2054   - element = $(element);
2055   - if (element.getStyle('position') == 'relative') return;
2056   - // Position.prepare(); // To be done manually by Scripty when it needs it.
2057   -
2058   - element.style.position = 'relative';
2059   - var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
2060   - var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
2061   -
2062   - element.style.top = top + 'px';
2063   - element.style.left = left + 'px';
2064   - element.style.height = element._originalHeight;
2065   - element.style.width = element._originalWidth;
2066   - return element;
2067   - },
2068   -
2069   - cumulativeScrollOffset: function(element) {
2070   - var valueT = 0, valueL = 0;
2071   - do {
2072   - valueT += element.scrollTop || 0;
2073   - valueL += element.scrollLeft || 0;
2074   - element = element.parentNode;
2075   - } while (element);
2076   - return Element._returnOffset(valueL, valueT);
2077   - },
2078   -
2079   - getOffsetParent: function(element) {
2080   - if (element.offsetParent) return $(element.offsetParent);
2081   - if (element == document.body) return $(element);
2082   -
2083   - while ((element = element.parentNode) && element != document.body)
2084   - if (Element.getStyle(element, 'position') != 'static')
2085   - return $(element);
2086   -
2087   - return $(document.body);
2088   - },
2089   -
2090   - viewportOffset: function(forElement) {
2091   - var valueT = 0, valueL = 0;
2092   -
2093   - var element = forElement;
2094   - do {
2095   - valueT += element.offsetTop || 0;
2096   - valueL += element.offsetLeft || 0;
2097   -
2098   - // Safari fix
2099   - if (element.offsetParent == document.body &&
2100   - Element.getStyle(element, 'position') == 'absolute') break;
2101   -
2102   - } while (element = element.offsetParent);
2103   -
2104   - element = forElement;
2105   - do {
2106   - if (!Prototype.Browser.Opera || element.tagName == 'BODY') {
2107   - valueT -= element.scrollTop || 0;
2108   - valueL -= element.scrollLeft || 0;
2109   - }
2110   - } while (element = element.parentNode);
2111   -
2112   - return Element._returnOffset(valueL, valueT);
2113   - },
2114   -
2115   - clonePosition: function(element, source) {
2116   - var options = Object.extend({
2117   - setLeft: true,
2118   - setTop: true,
2119   - setWidth: true,
2120   - setHeight: true,
2121   - offsetTop: 0,
2122   - offsetLeft: 0
2123   - }, arguments[2] || { });
2124   -
2125   - // find page position of source
2126   - source = $(source);
2127   - var p = source.viewportOffset();
2128   -
2129   - // find coordinate system to use
2130   - element = $(element);
2131   - var delta = [0, 0];
2132   - var parent = null;
2133   - // delta [0,0] will do fine with position: fixed elements,
2134   - // position:absolute needs offsetParent deltas
2135   - if (Element.getStyle(element, 'position') == 'absolute') {
2136   - parent = element.getOffsetParent();
2137   - delta = parent.viewportOffset();
2138   - }
2139   -
2140   - // correct by body offsets (fixes Safari)
2141   - if (parent == document.body) {
2142   - delta[0] -= document.body.offsetLeft;
2143   - delta[1] -= document.body.offsetTop;
2144   - }
2145   -
2146   - // set position
2147   - if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
2148   - if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
2149   - if (options.setWidth) element.style.width = source.offsetWidth + 'px';
2150   - if (options.setHeight) element.style.height = source.offsetHeight + 'px';
2151   - return element;
2152   - }
2153   -};
2154   -
2155   -Element.Methods.identify.counter = 1;
2156   -
2157   -Object.extend(Element.Methods, {
2158   - getElementsBySelector: Element.Methods.select,
2159   - childElements: Element.Methods.immediateDescendants
2160   -});
2161   -
2162   -Element._attributeTranslations = {
2163   - write: {
2164   - names: {
2165   - className: 'class',
2166   - htmlFor: 'for'
2167   - },
2168   - values: { }
2169   - }
2170   -};
2171   -
2172   -if (Prototype.Browser.Opera) {
2173   - Element.Methods.getStyle = Element.Methods.getStyle.wrap(
2174   - function(proceed, element, style) {
2175   - switch (style) {
2176   - case 'left': case 'top': case 'right': case 'bottom':
2177   - if (proceed(element, 'position') === 'static') return null;
2178   - case 'height': case 'width':
2179   - // returns '0px' for hidden elements; we want it to return null
2180   - if (!Element.visible(element)) return null;
2181   -
2182   - // returns the border-box dimensions rather than the content-box
2183   - // dimensions, so we subtract padding and borders from the value
2184   - var dim = parseInt(proceed(element, style), 10);
2185   -
2186   - if (dim !== element['offset' + style.capitalize()])
2187   - return dim + 'px';
2188   -
2189   - var properties;
2190   - if (style === 'height') {
2191   - properties = ['border-top-width', 'padding-top',
2192   - 'padding-bottom', 'border-bottom-width'];
2193   - }
2194   - else {
2195   - properties = ['border-left-width', 'padding-left',
2196   - 'padding-right', 'border-right-width'];
2197   - }
2198   - return properties.inject(dim, function(memo, property) {
2199   - var val = proceed(element, property);
2200   - return val === null ? memo : memo - parseInt(val, 10);
2201   - }) + 'px';
2202   - default: return proceed(element, style);
2203   - }
2204   - }
2205   - );
2206   -
2207   - Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
2208   - function(proceed, element, attribute) {
2209   - if (attribute === 'title') return element.title;
2210   - return proceed(element, attribute);
2211   - }
2212   - );
2213   -}
2214   -
2215   -else if (Prototype.Browser.IE) {
2216   - // IE doesn't report offsets correctly for static elements, so we change them
2217   - // to "relative" to get the values, then change them back.
2218   - Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
2219   - function(proceed, element) {
2220   - element = $(element);
2221   - var position = element.getStyle('position');
2222   - if (position !== 'static') return proceed(element);
2223   - element.setStyle({ position: 'relative' });
2224   - var value = proceed(element);
2225   - element.setStyle({ position: position });
2226   - return value;
2227   - }
2228   - );
2229   -
2230   - $w('positionedOffset viewportOffset').each(function(method) {
2231   - Element.Methods[method] = Element.Methods[method].wrap(
2232   - function(proceed, element) {
2233   - element = $(element);
2234   - var position = element.getStyle('position');
2235   - if (position !== 'static') return proceed(element);
2236   - // Trigger hasLayout on the offset parent so that IE6 reports
2237   - // accurate offsetTop and offsetLeft values for position: fixed.
2238   - var offsetParent = element.getOffsetParent();
2239   - if (offsetParent && offsetParent.getStyle('position') === 'fixed')
2240   - offsetParent.setStyle({ zoom: 1 });
2241   - element.setStyle({ position: 'relative' });
2242   - var value = proceed(element);
2243   - element.setStyle({ position: position });
2244   - return value;
2245   - }
2246   - );
2247   - });
2248   -
2249   - Element.Methods.getStyle = function(element, style) {
2250   - element = $(element);
2251   - style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
2252   - var value = element.style[style];
2253   - if (!value && element.currentStyle) value = element.currentStyle[style];
2254   -
2255   - if (style == 'opacity') {
2256   - if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
2257   - if (value[1]) return parseFloat(value[1]) / 100;
2258   - return 1.0;
2259   - }
2260   -
2261   - if (value == 'auto') {
2262   - if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
2263   - return element['offset' + style.capitalize()] + 'px';
2264   - return null;
2265   - }
2266   - return value;
2267   - };
2268   -
2269   - Element.Methods.setOpacity = function(element, value) {
2270   - function stripAlpha(filter){
2271   - return filter.replace(/alpha\([^\)]*\)/gi,'');
2272   - }
2273   - element = $(element);
2274   - var currentStyle = element.currentStyle;
2275   - if ((currentStyle && !currentStyle.hasLayout) ||
2276   - (!currentStyle && element.style.zoom == 'normal'))
2277   - element.style.zoom = 1;
2278   -
2279   - var filter = element.getStyle('filter'), style = element.style;
2280   - if (value == 1 || value === '') {
2281   - (filter = stripAlpha(filter)) ?
2282   - style.filter = filter : style.removeAttribute('filter');
2283   - return element;
2284   - } else if (value < 0.00001) value = 0;
2285   - style.filter = stripAlpha(filter) +
2286   - 'alpha(opacity=' + (value * 100) + ')';
2287   - return element;
2288   - };
2289   -
2290   - Element._attributeTranslations = {
2291   - read: {
2292   - names: {
2293   - 'class': 'className',
2294   - 'for': 'htmlFor'
2295   - },
2296   - values: {
2297   - _getAttr: function(element, attribute) {
2298   - return element.getAttribute(attribute, 2);
2299   - },
2300   - _getAttrNode: function(element, attribute) {
2301   - var node = element.getAttributeNode(attribute);
2302   - return node ? node.value : "";
2303   - },
2304   - _getEv: function(element, attribute) {
2305   - attribute = element.getAttribute(attribute);
2306   - return attribute ? attribute.toString().slice(23, -2) : null;
2307   - },
2308   - _flag: function(element, attribute) {
2309   - return $(element).hasAttribute(attribute) ? attribute : null;
2310   - },
2311   - style: function(element) {
2312   - return element.style.cssText.toLowerCase();
2313   - },
2314   - title: function(element) {
2315   - return element.title;
2316   - }
2317   - }
2318   - }
2319   - };
2320   -
2321   - Element._attributeTranslations.write = {
2322   - names: Object.extend({
2323   - cellpadding: 'cellPadding',
2324   - cellspacing: 'cellSpacing'
2325   - }, Element._attributeTranslations.read.names),
2326   - values: {
2327   - checked: function(element, value) {
2328   - element.checked = !!value;
2329   - },
2330   -
2331   - style: function(element, value) {
2332   - element.style.cssText = value ? value : '';
2333   - }
2334   - }
2335   - };
2336   -
2337   - Element._attributeTranslations.has = {};
2338   -
2339   - $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
2340   - 'encType maxLength readOnly longDesc').each(function(attr) {
2341   - Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
2342   - Element._attributeTranslations.has[attr.toLowerCase()] = attr;
2343   - });
2344   -
2345   - (function(v) {
2346   - Object.extend(v, {
2347   - href: v._getAttr,
2348   - src: v._getAttr,
2349   - type: v._getAttr,
2350   - action: v._getAttrNode,
2351   - disabled: v._flag,
2352   - checked: v._flag,
2353   - readonly: v._flag,
2354   - multiple: v._flag,
2355   - onload: v._getEv,
2356   - onunload: v._getEv,
2357   - onclick: v._getEv,
2358   - ondblclick: v._getEv,
2359   - onmousedown: v._getEv,
2360   - onmouseup: v._getEv,
2361   - onmouseover: v._getEv,
2362   - onmousemove: v._getEv,
2363   - onmouseout: v._getEv,
2364   - onfocus: v._getEv,
2365   - onblur: v._getEv,
2366   - onkeypress: v._getEv,
2367   - onkeydown: v._getEv,
2368   - onkeyup: v._getEv,
2369   - onsubmit: v._getEv,
2370   - onreset: v._getEv,
2371   - onselect: v._getEv,
2372   - onchange: v._getEv
2373   - });
2374   - })(Element._attributeTranslations.read.values);
2375   -}
2376   -
2377   -else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
2378   - Element.Methods.setOpacity = function(element, value) {
2379   - element = $(element);
2380   - element.style.opacity = (value == 1) ? 0.999999 :
2381   - (value === '') ? '' : (value < 0.00001) ? 0 : value;
2382   - return element;
2383   - };
2384   -}
2385   -
2386   -else if (Prototype.Browser.WebKit) {
2387   - Element.Methods.setOpacity = function(element, value) {
2388   - element = $(element);
2389   - element.style.opacity = (value == 1 || value === '') ? '' :
2390   - (value < 0.00001) ? 0 : value;
2391   -
2392   - if (value == 1)
2393   - if(element.tagName == 'IMG' && element.width) {
2394   - element.width++; element.width--;
2395   - } else try {
2396   - var n = document.createTextNode(' ');
2397   - element.appendChild(n);
2398   - element.removeChild(n);
2399   - } catch (e) { }
2400   -
2401   - return element;
2402   - };
2403   -
2404   - // Safari returns margins on body which is incorrect if the child is absolutely
2405   - // positioned. For performance reasons, redefine Element#cumulativeOffset for
2406   - // KHTML/WebKit only.
2407   - Element.Methods.cumulativeOffset = function(element) {
2408   - var valueT = 0, valueL = 0;
2409   - do {
2410   - valueT += element.offsetTop || 0;
2411   - valueL += element.offsetLeft || 0;
2412   - if (element.offsetParent == document.body)
2413   - if (Element.getStyle(element, 'position') == 'absolute') break;
2414   -
2415   - element = element.offsetParent;
2416   - } while (element);
2417   -
2418   - return Element._returnOffset(valueL, valueT);
2419   - };
2420   -}
2421   -
2422   -if (Prototype.Browser.IE || Prototype.Browser.Opera) {
2423   - // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements
2424   - Element.Methods.update = function(element, content) {
2425   - element = $(element);
2426   -
2427   - if (content && content.toElement) content = content.toElement();
2428   - if (Object.isElement(content)) return element.update().insert(content);
2429   -
2430   - content = Object.toHTML(content);
2431   - var tagName = element.tagName.toUpperCase();
2432   -
2433   - if (tagName in Element._insertionTranslations.tags) {
2434   - $A(element.childNodes).each(function(node) { element.removeChild(node) });
2435   - Element._getContentFromAnonymousElement(tagName, content.stripScripts())
2436   - .each(function(node) { element.appendChild(node) });
2437   - }
2438   - else element.innerHTML = content.stripScripts();
2439   -
2440   - content.evalScripts.bind(content).defer();
2441   - return element;
2442   - };
2443   -}
2444   -
2445   -if ('outerHTML' in document.createElement('div')) {
2446   - Element.Methods.replace = function(element, content) {
2447   - element = $(element);
2448   -
2449   - if (content && content.toElement) content = content.toElement();
2450   - if (Object.isElement(content)) {
2451   - element.parentNode.replaceChild(content, element);
2452   - return element;
2453   - }
2454   -
2455   - content = Object.toHTML(content);
2456   - var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
2457   -
2458   - if (Element._insertionTranslations.tags[tagName]) {
2459   - var nextSibling = element.next();
2460   - var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
2461   - parent.removeChild(element);
2462   - if (nextSibling)
2463   - fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
2464   - else
2465   - fragments.each(function(node) { parent.appendChild(node) });
2466   - }
2467   - else element.outerHTML = content.stripScripts();
2468   -
2469   - content.evalScripts.bind(content).defer();
2470   - return element;
2471   - };
2472   -}
2473   -
2474   -Element._returnOffset = function(l, t) {
2475   - var result = [l, t];
2476   - result.left = l;
2477   - result.top = t;
2478   - return result;
2479   -};
2480   -
2481   -Element._getContentFromAnonymousElement = function(tagName, html) {
2482   - var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
2483   - if (t) {
2484   - div.innerHTML = t[0] + html + t[1];
2485   - t[2].times(function() { div = div.firstChild });
2486   - } else div.innerHTML = html;
2487   - return $A(div.childNodes);
2488   -};
2489   -
2490   -Element._insertionTranslations = {
2491   - before: function(element, node) {
2492   - element.parentNode.insertBefore(node, element);
2493   - },
2494   - top: function(element, node) {
2495   - element.insertBefore(node, element.firstChild);
2496   - },
2497   - bottom: function(element, node) {
2498   - element.appendChild(node);
2499   - },
2500   - after: function(element, node) {
2501   - element.parentNode.insertBefore(node, element.nextSibling);
2502   - },
2503   - tags: {
2504   - TABLE: ['<table>', '</table>', 1],
2505   - TBODY: ['<table><tbody>', '</tbody></table>', 2],
2506   - TR: ['<table><tbody><tr>', '</tr></tbody></table>', 3],
2507   - TD: ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
2508   - SELECT: ['<select>', '</select>', 1]
2509   - }
2510   -};
2511   -
2512   -(function() {
2513   - Object.extend(this.tags, {
2514   - THEAD: this.tags.TBODY,
2515   - TFOOT: this.tags.TBODY,
2516   - TH: this.tags.TD
2517   - });
2518   -}).call(Element._insertionTranslations);
2519   -
2520   -Element.Methods.Simulated = {
2521   - hasAttribute: function(element, attribute) {
2522   - attribute = Element._attributeTranslations.has[attribute] || attribute;
2523   - var node = $(element).getAttributeNode(attribute);
2524   - return node && node.specified;
2525   - }
2526   -};
2527   -
2528   -Element.Methods.ByTag = { };
2529   -
2530   -Object.extend(Element, Element.Methods);
2531   -
2532   -if (!Prototype.BrowserFeatures.ElementExtensions &&
2533   - document.createElement('div').__proto__) {
2534   - window.HTMLElement = { };
2535   - window.HTMLElement.prototype = document.createElement('div').__proto__;
2536   - Prototype.BrowserFeatures.ElementExtensions = true;
2537   -}
2538   -
2539   -Element.extend = (function() {
2540   - if (Prototype.BrowserFeatures.SpecificElementExtensions)
2541   - return Prototype.K;
2542   -
2543   - var Methods = { }, ByTag = Element.Methods.ByTag;
2544   -
2545   - var extend = Object.extend(function(element) {
2546   - if (!element || element._extendedByPrototype ||
2547   - element.nodeType != 1 || element == window) return element;
2548   -
2549   - var methods = Object.clone(Methods),
2550   - tagName = element.tagName, property, value;
2551   -
2552   - // extend methods for specific tags
2553   - if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
2554   -
2555   - for (property in methods) {
2556   - value = methods[property];
2557   - if (Object.isFunction(value) && !(property in element))
2558   - element[property] = value.methodize();
2559   - }
2560   -
2561   - element._extendedByPrototype = Prototype.emptyFunction;
2562   - return element;
2563   -
2564   - }, {
2565   - refresh: function() {
2566   - // extend methods for all tags (Safari doesn't need this)
2567   - if (!Prototype.BrowserFeatures.ElementExtensions) {
2568   - Object.extend(Methods, Element.Methods);
2569   - Object.extend(Methods, Element.Methods.Simulated);
2570   - }
2571   - }
2572   - });
2573   -
2574   - extend.refresh();
2575   - return extend;
2576   -})();
2577   -
2578   -Element.hasAttribute = function(element, attribute) {
2579   - if (element.hasAttribute) return element.hasAttribute(attribute);
2580   - return Element.Methods.Simulated.hasAttribute(element, attribute);
2581   -};
2582   -
2583   -Element.addMethods = function(methods) {
2584   - var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
2585   -
2586   - if (!methods) {
2587   - Object.extend(Form, Form.Methods);
2588   - Object.extend(Form.Element, Form.Element.Methods);
2589   - Object.extend(Element.Methods.ByTag, {
2590   - "FORM": Object.clone(Form.Methods),
2591   - "INPUT": Object.clone(Form.Element.Methods),
2592   - "SELECT": Object.clone(Form.Element.Methods),
2593   - "TEXTAREA": Object.clone(Form.Element.Methods)
2594   - });
2595   - }
2596   -
2597   - if (arguments.length == 2) {
2598   - var tagName = methods;
2599   - methods = arguments[1];
2600   - }
2601   -
2602   - if (!tagName) Object.extend(Element.Methods, methods || { });
2603   - else {
2604   - if (Object.isArray(tagName)) tagName.each(extend);
2605   - else extend(tagName);
2606   - }
2607   -
2608   - function extend(tagName) {
2609   - tagName = tagName.toUpperCase();
2610   - if (!Element.Methods.ByTag[tagName])
2611   - Element.Methods.ByTag[tagName] = { };
2612   - Object.extend(Element.Methods.ByTag[tagName], methods);
2613   - }
2614   -
2615   - function copy(methods, destination, onlyIfAbsent) {
2616   - onlyIfAbsent = onlyIfAbsent || false;
2617   - for (var property in methods) {
2618   - var value = methods[property];
2619   - if (!Object.isFunction(value)) continue;
2620   - if (!onlyIfAbsent || !(property in destination))
2621   - destination[property] = value.methodize();
2622   - }
2623   - }
2624   -
2625   - function findDOMClass(tagName) {
2626   - var klass;
2627   - var trans = {
2628   - "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
2629   - "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
2630   - "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
2631   - "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
2632   - "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
2633   - "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
2634   - "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
2635   - "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
2636   - "FrameSet", "IFRAME": "IFrame"
2637   - };
2638   - if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
2639   - if (window[klass]) return window[klass];
2640   - klass = 'HTML' + tagName + 'Element';
2641   - if (window[klass]) return window[klass];
2642   - klass = 'HTML' + tagName.capitalize() + 'Element';
2643   - if (window[klass]) return window[klass];
2644   -
2645   - window[klass] = { };
2646   - window[klass].prototype = document.createElement(tagName).__proto__;
2647   - return window[klass];
2648   - }
2649   -
2650   - if (F.ElementExtensions) {
2651   - copy(Element.Methods, HTMLElement.prototype);
2652   - copy(Element.Methods.Simulated, HTMLElement.prototype, true);
2653   - }
2654   -
2655   - if (F.SpecificElementExtensions) {
2656   - for (var tag in Element.Methods.ByTag) {
2657   - var klass = findDOMClass(tag);
2658   - if (Object.isUndefined(klass)) continue;
2659   - copy(T[tag], klass.prototype);
2660   - }
2661   - }
2662   -
2663   - Object.extend(Element, Element.Methods);
2664   - delete Element.ByTag;
2665   -
2666   - if (Element.extend.refresh) Element.extend.refresh();
2667   - Element.cache = { };
2668   -};
2669   -
2670   -document.viewport = {
2671   - getDimensions: function() {
2672   - var dimensions = { };
2673   - var B = Prototype.Browser;
2674   - $w('width height').each(function(d) {
2675   - var D = d.capitalize();
2676   - dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] :
2677   - (B.Opera) ? document.body['client' + D] : document.documentElement['client' + D];
2678   - });
2679   - return dimensions;
2680   - },
2681   -
2682   - getWidth: function() {
2683   - return this.getDimensions().width;
2684   - },
2685   -
2686   - getHeight: function() {
2687   - return this.getDimensions().height;
2688   - },
2689   -
2690   - getScrollOffsets: function() {
2691   - return Element._returnOffset(
2692   - window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
2693   - window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
2694   - }
2695   -};
2696   -/* Portions of the Selector class are derived from Jack Slocum’s DomQuery,
2697   - * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
2698   - * license. Please see http://www.yui-ext.com/ for more information. */
2699   -
2700   -var Selector = Class.create({
2701   - initialize: function(expression) {
2702   - this.expression = expression.strip();
2703   - this.compileMatcher();
2704   - },
2705   -
2706   - shouldUseXPath: function() {
2707   - if (!Prototype.BrowserFeatures.XPath) return false;
2708   -
2709   - var e = this.expression;
2710   -
2711   - // Safari 3 chokes on :*-of-type and :empty
2712   - if (Prototype.Browser.WebKit &&
2713   - (e.include("-of-type") || e.include(":empty")))
2714   - return false;
2715   -
2716   - // XPath can't do namespaced attributes, nor can it read
2717   - // the "checked" property from DOM nodes
2718   - if ((/(\[[\w-]*?:|:checked)/).test(this.expression))
2719   - return false;
2720   -
2721   - return true;
2722   - },
2723   -
2724   - compileMatcher: function() {
2725   - if (this.shouldUseXPath())
2726   - return this.compileXPathMatcher();
2727   -
2728   - var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
2729   - c = Selector.criteria, le, p, m;
2730   -
2731   - if (Selector._cache[e]) {
2732   - this.matcher = Selector._cache[e];
2733   - return;
2734   - }
2735   -
2736   - this.matcher = ["this.matcher = function(root) {",
2737   - "var r = root, h = Selector.handlers, c = false, n;"];
2738   -
2739   - while (e && le != e && (/\S/).test(e)) {
2740   - le = e;
2741   - for (var i in ps) {
2742   - p = ps[i];
2743   - if (m = e.match(p)) {
2744   - this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
2745   - new Template(c[i]).evaluate(m));
2746   - e = e.replace(m[0], '');
2747   - break;
2748   - }
2749   - }
2750   - }
2751   -
2752   - this.matcher.push("return h.unique(n);\n}");
2753   - eval(this.matcher.join('\n'));
2754   - Selector._cache[this.expression] = this.matcher;
2755   - },
2756   -
2757   - compileXPathMatcher: function() {
2758   - var e = this.expression, ps = Selector.patterns,
2759   - x = Selector.xpath, le, m;
2760   -
2761   - if (Selector._cache[e]) {
2762   - this.xpath = Selector._cache[e]; return;
2763   - }
2764   -
2765   - this.matcher = ['.//*'];
2766   - while (e && le != e && (/\S/).test(e)) {
2767   - le = e;
2768   - for (var i in ps) {
2769   - if (m = e.match(ps[i])) {
2770   - this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :
2771   - new Template(x[i]).evaluate(m));
2772   - e = e.replace(m[0], '');
2773   - break;
2774   - }
2775   - }
2776   - }
2777   -
2778   - this.xpath = this.matcher.join('');
2779   - Selector._cache[this.expression] = this.xpath;
2780   - },
2781   -
2782   - findElements: function(root) {
2783   - root = root || document;
2784   - if (this.xpath) return document._getElementsByXPath(this.xpath, root);
2785   - return this.matcher(root);
2786   - },
2787   -
2788   - match: function(element) {
2789   - this.tokens = [];
2790   -
2791   - var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
2792   - var le, p, m;
2793   -
2794   - while (e && le !== e && (/\S/).test(e)) {
2795   - le = e;
2796   - for (var i in ps) {
2797   - p = ps[i];
2798   - if (m = e.match(p)) {
2799   - // use the Selector.assertions methods unless the selector
2800   - // is too complex.
2801   - if (as[i]) {
2802   - this.tokens.push([i, Object.clone(m)]);
2803   - e = e.replace(m[0], '');
2804   - } else {
2805   - // reluctantly do a document-wide search
2806   - // and look for a match in the array
2807   - return this.findElements(document).include(element);
2808   - }
2809   - }
2810   - }
2811   - }
2812   -
2813   - var match = true, name, matches;
2814   - for (var i = 0, token; token = this.tokens[i]; i++) {
2815   - name = token[0], matches = token[1];
2816   - if (!Selector.assertions[name](element, matches)) {
2817   - match = false; break;
2818   - }
2819   - }
2820   -
2821   - return match;
2822   - },
2823   -
2824   - toString: function() {
2825   - return this.expression;
2826   - },
2827   -
2828   - inspect: function() {
2829   - return "#<Selector:" + this.expression.inspect() + ">";
2830   - }
2831   -});
2832   -
2833   -Object.extend(Selector, {
2834   - _cache: { },
2835   -
2836   - xpath: {
2837   - descendant: "//*",
2838   - child: "/*",
2839   - adjacent: "/following-sibling::*[1]",
2840   - laterSibling: '/following-sibling::*',
2841   - tagName: function(m) {
2842   - if (m[1] == '*') return '';
2843   - return "[local-name()='" + m[1].toLowerCase() +
2844   - "' or local-name()='" + m[1].toUpperCase() + "']";
2845   - },
2846   - className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
2847   - id: "[@id='#{1}']",
2848   - attrPresence: function(m) {
2849   - m[1] = m[1].toLowerCase();
2850   - return new Template("[@#{1}]").evaluate(m);
2851   - },
2852   - attr: function(m) {
2853   - m[1] = m[1].toLowerCase();
2854   - m[3] = m[5] || m[6];
2855   - return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
2856   - },
2857   - pseudo: function(m) {
2858   - var h = Selector.xpath.pseudos[m[1]];
2859   - if (!h) return '';
2860   - if (Object.isFunction(h)) return h(m);
2861   - return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
2862   - },
2863   - operators: {
2864   - '=': "[@#{1}='#{3}']",
2865   - '!=': "[@#{1}!='#{3}']",
2866   - '^=': "[starts-with(@#{1}, '#{3}')]",
2867   - '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
2868   - '*=': "[contains(@#{1}, '#{3}')]",
2869   - '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
2870   - '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
2871   - },
2872   - pseudos: {
2873   - 'first-child': '[not(preceding-sibling::*)]',
2874   - 'last-child': '[not(following-sibling::*)]',
2875   - 'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
2876   - 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
2877   - 'checked': "[@checked]",
2878   - 'disabled': "[@disabled]",
2879   - 'enabled': "[not(@disabled)]",
2880   - 'not': function(m) {
2881   - var e = m[6], p = Selector.patterns,
2882   - x = Selector.xpath, le, v;
2883   -
2884   - var exclusion = [];
2885   - while (e && le != e && (/\S/).test(e)) {
2886   - le = e;
2887   - for (var i in p) {
2888   - if (m = e.match(p[i])) {
2889   - v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);
2890   - exclusion.push("(" + v.substring(1, v.length - 1) + ")");
2891   - e = e.replace(m[0], '');
2892   - break;
2893   - }
2894   - }
2895   - }
2896   - return "[not(" + exclusion.join(" and ") + ")]";
2897   - },
2898   - 'nth-child': function(m) {
2899   - return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
2900   - },
2901   - 'nth-last-child': function(m) {
2902   - return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
2903   - },
2904   - 'nth-of-type': function(m) {
2905   - return Selector.xpath.pseudos.nth("position() ", m);
2906   - },
2907   - 'nth-last-of-type': function(m) {
2908   - return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
2909   - },
2910   - 'first-of-type': function(m) {
2911   - m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
2912   - },
2913   - 'last-of-type': function(m) {
2914   - m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
2915   - },
2916   - 'only-of-type': function(m) {
2917   - var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
2918   - },
2919   - nth: function(fragment, m) {
2920   - var mm, formula = m[6], predicate;
2921   - if (formula == 'even') formula = '2n+0';
2922   - if (formula == 'odd') formula = '2n+1';
2923   - if (mm = formula.match(/^(\d+)$/)) // digit only
2924   - return '[' + fragment + "= " + mm[1] + ']';
2925   - if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
2926   - if (mm[1] == "-") mm[1] = -1;
2927   - var a = mm[1] ? Number(mm[1]) : 1;
2928   - var b = mm[2] ? Number(mm[2]) : 0;
2929   - predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
2930   - "((#{fragment} - #{b}) div #{a} >= 0)]";
2931   - return new Template(predicate).evaluate({
2932   - fragment: fragment, a: a, b: b });
2933   - }
2934   - }
2935   - }
2936   - },
2937   -
2938   - criteria: {
2939   - tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
2940   - className: 'n = h.className(n, r, "#{1}", c); c = false;',
2941   - id: 'n = h.id(n, r, "#{1}", c); c = false;',
2942   - attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;',
2943   - attr: function(m) {
2944   - m[3] = (m[5] || m[6]);
2945   - return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);
2946   - },
2947   - pseudo: function(m) {
2948   - if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
2949   - return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
2950   - },
2951   - descendant: 'c = "descendant";',
2952   - child: 'c = "child";',
2953   - adjacent: 'c = "adjacent";',
2954   - laterSibling: 'c = "laterSibling";'
2955   - },
2956   -
2957   - patterns: {
2958   - // combinators must be listed first
2959   - // (and descendant needs to be last combinator)
2960   - laterSibling: /^\s*~\s*/,
2961   - child: /^\s*>\s*/,
2962   - adjacent: /^\s*\+\s*/,
2963   - descendant: /^\s/,
2964   -
2965   - // selectors follow
2966   - tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
2967   - id: /^#([\w\-\*]+)(\b|$)/,
2968   - className: /^\.([\w\-\*]+)(\b|$)/,
2969   - pseudo:
2970   -/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,
2971   - attrPresence: /^\[([\w]+)\]/,
2972   - attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
2973   - },
2974   -
2975   - // for Selector.match and Element#match
2976   - assertions: {
2977   - tagName: function(element, matches) {
2978   - return matches[1].toUpperCase() == element.tagName.toUpperCase();
2979   - },
2980   -
2981   - className: function(element, matches) {
2982   - return Element.hasClassName(element, matches[1]);
2983   - },
2984   -
2985   - id: function(element, matches) {
2986   - return element.id === matches[1];
2987   - },
2988   -
2989   - attrPresence: function(element, matches) {
2990   - return Element.hasAttribute(element, matches[1]);
2991   - },
2992   -
2993   - attr: function(element, matches) {
2994   - var nodeValue = Element.readAttribute(element, matches[1]);
2995   - return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);
2996   - }
2997   - },
2998   -
2999   - handlers: {
3000   - // UTILITY FUNCTIONS
3001   - // joins two collections
3002   - concat: function(a, b) {
3003   - for (var i = 0, node; node = b[i]; i++)
3004   - a.push(node);
3005   - return a;
3006   - },
3007   -
3008   - // marks an array of nodes for counting
3009   - mark: function(nodes) {
3010   - var _true = Prototype.emptyFunction;
3011   - for (var i = 0, node; node = nodes[i]; i++)
3012   - node._countedByPrototype = _true;
3013   - return nodes;
3014   - },
3015   -
3016   - unmark: function(nodes) {
3017   - for (var i = 0, node; node = nodes[i]; i++)
3018   - node._countedByPrototype = undefined;
3019   - return nodes;
3020   - },
3021   -
3022   - // mark each child node with its position (for nth calls)
3023   - // "ofType" flag indicates whether we're indexing for nth-of-type
3024   - // rather than nth-child
3025   - index: function(parentNode, reverse, ofType) {
3026   - parentNode._countedByPrototype = Prototype.emptyFunction;
3027   - if (reverse) {
3028   - for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
3029   - var node = nodes[i];
3030   - if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
3031   - }
3032   - } else {
3033   - for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
3034   - if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
3035   - }
3036   - },
3037   -
3038   - // filters out duplicates and extends all nodes
3039   - unique: function(nodes) {
3040   - if (nodes.length == 0) return nodes;
3041   - var results = [], n;
3042   - for (var i = 0, l = nodes.length; i < l; i++)
3043   - if (!(n = nodes[i])._countedByPrototype) {
3044   - n._countedByPrototype = Prototype.emptyFunction;
3045   - results.push(Element.extend(n));
3046   - }
3047   - return Selector.handlers.unmark(results);
3048   - },
3049   -
3050   - // COMBINATOR FUNCTIONS
3051   - descendant: function(nodes) {
3052   - var h = Selector.handlers;
3053   - for (var i = 0, results = [], node; node = nodes[i]; i++)
3054   - h.concat(results, node.getElementsByTagName('*'));
3055   - return results;
3056   - },
3057   -
3058   - child: function(nodes) {
3059   - var h = Selector.handlers;
3060   - for (var i = 0, results = [], node; node = nodes[i]; i++) {
3061   - for (var j = 0, child; child = node.childNodes[j]; j++)
3062   - if (child.nodeType == 1 && child.tagName != '!') results.push(child);
3063   - }
3064   - return results;
3065   - },
3066   -
3067   - adjacent: function(nodes) {
3068   - for (var i = 0, results = [], node; node = nodes[i]; i++) {
3069   - var next = this.nextElementSibling(node);
3070   - if (next) results.push(next);
3071   - }
3072   - return results;
3073   - },
3074   -
3075   - laterSibling: function(nodes) {
3076   - var h = Selector.handlers;
3077   - for (var i = 0, results = [], node; node = nodes[i]; i++)
3078   - h.concat(results, Element.nextSiblings(node));
3079   - return results;
3080   - },
3081   -
3082   - nextElementSibling: function(node) {
3083   - while (node = node.nextSibling)
3084   - if (node.nodeType == 1) return node;
3085   - return null;
3086   - },
3087   -
3088   - previousElementSibling: function(node) {
3089   - while (node = node.previousSibling)
3090   - if (node.nodeType == 1) return node;
3091   - return null;
3092   - },
3093   -
3094   - // TOKEN FUNCTIONS
3095   - tagName: function(nodes, root, tagName, combinator) {
3096   - var uTagName = tagName.toUpperCase();
3097   - var results = [], h = Selector.handlers;
3098   - if (nodes) {
3099   - if (combinator) {
3100   - // fastlane for ordinary descendant combinators
3101   - if (combinator == "descendant") {
3102   - for (var i = 0, node; node = nodes[i]; i++)
3103   - h.concat(results, node.getElementsByTagName(tagName));
3104   - return results;
3105   - } else nodes = this[combinator](nodes);
3106   - if (tagName == "*") return nodes;
3107   - }
3108   - for (var i = 0, node; node = nodes[i]; i++)
3109   - if (node.tagName.toUpperCase() === uTagName) results.push(node);
3110   - return results;
3111   - } else return root.getElementsByTagName(tagName);
3112   - },
3113   -
3114   - id: function(nodes, root, id, combinator) {
3115   - var targetNode = $(id), h = Selector.handlers;
3116   - if (!targetNode) return [];
3117   - if (!nodes && root == document) return [targetNode];
3118   - if (nodes) {
3119   - if (combinator) {
3120   - if (combinator == 'child') {
3121   - for (var i = 0, node; node = nodes[i]; i++)
3122   - if (targetNode.parentNode == node) return [targetNode];
3123   - } else if (combinator == 'descendant') {
3124   - for (var i = 0, node; node = nodes[i]; i++)
3125   - if (Element.descendantOf(targetNode, node)) return [targetNode];
3126   - } else if (combinator == 'adjacent') {
3127   - for (var i = 0, node; node = nodes[i]; i++)
3128   - if (Selector.handlers.previousElementSibling(targetNode) == node)
3129   - return [targetNode];
3130   - } else nodes = h[combinator](nodes);
3131   - }
3132   - for (var i = 0, node; node = nodes[i]; i++)
3133   - if (node == targetNode) return [targetNode];
3134   - return [];
3135   - }
3136   - return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
3137   - },
3138   -
3139   - className: function(nodes, root, className, combinator) {
3140   - if (nodes && combinator) nodes = this[combinator](nodes);
3141   - return Selector.handlers.byClassName(nodes, root, className);
3142   - },
3143   -
3144   - byClassName: function(nodes, root, className) {
3145   - if (!nodes) nodes = Selector.handlers.descendant([root]);
3146   - var needle = ' ' + className + ' ';
3147   - for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
3148   - nodeClassName = node.className;
3149   - if (nodeClassName.length == 0) continue;
3150   - if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
3151   - results.push(node);
3152   - }
3153   - return results;
3154   - },
3155   -
3156   - attrPresence: function(nodes, root, attr, combinator) {
3157   - if (!nodes) nodes = root.getElementsByTagName("*");
3158   - if (nodes && combinator) nodes = this[combinator](nodes);
3159   - var results = [];
3160   - for (var i = 0, node; node = nodes[i]; i++)
3161   - if (Element.hasAttribute(node, attr)) results.push(node);
3162   - return results;
3163   - },
3164   -
3165   - attr: function(nodes, root, attr, value, operator, combinator) {
3166   - if (!nodes) nodes = root.getElementsByTagName("*");
3167   - if (nodes && combinator) nodes = this[combinator](nodes);
3168   - var handler = Selector.operators[operator], results = [];
3169   - for (var i = 0, node; node = nodes[i]; i++) {
3170   - var nodeValue = Element.readAttribute(node, attr);
3171   - if (nodeValue === null) continue;
3172   - if (handler(nodeValue, value)) results.push(node);
3173   - }
3174   - return results;
3175   - },
3176   -
3177   - pseudo: function(nodes, name, value, root, combinator) {
3178   - if (nodes && combinator) nodes = this[combinator](nodes);
3179   - if (!nodes) nodes = root.getElementsByTagName("*");
3180   - return Selector.pseudos[name](nodes, value, root);
3181   - }
3182   - },
3183   -
3184   - pseudos: {
3185   - 'first-child': function(nodes, value, root) {
3186   - for (var i = 0, results = [], node; node = nodes[i]; i++) {
3187   - if (Selector.handlers.previousElementSibling(node)) continue;
3188   - results.push(node);
3189   - }
3190   - return results;
3191   - },
3192   - 'last-child': function(nodes, value, root) {
3193   - for (var i = 0, results = [], node; node = nodes[i]; i++) {
3194   - if (Selector.handlers.nextElementSibling(node)) continue;
3195   - results.push(node);
3196   - }
3197   - return results;
3198   - },
3199   - 'only-child': function(nodes, value, root) {
3200   - var h = Selector.handlers;
3201   - for (var i = 0, results = [], node; node = nodes[i]; i++)
3202   - if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
3203   - results.push(node);
3204   - return results;
3205   - },
3206   - 'nth-child': function(nodes, formula, root) {
3207   - return Selector.pseudos.nth(nodes, formula, root);
3208   - },
3209   - 'nth-last-child': function(nodes, formula, root) {
3210   - return Selector.pseudos.nth(nodes, formula, root, true);
3211   - },
3212   - 'nth-of-type': function(nodes, formula, root) {
3213   - return Selector.pseudos.nth(nodes, formula, root, false, true);
3214   - },
3215   - 'nth-last-of-type': function(nodes, formula, root) {
3216   - return Selector.pseudos.nth(nodes, formula, root, true, true);
3217   - },
3218   - 'first-of-type': function(nodes, formula, root) {
3219   - return Selector.pseudos.nth(nodes, "1", root, false, true);
3220   - },
3221   - 'last-of-type': function(nodes, formula, root) {
3222   - return Selector.pseudos.nth(nodes, "1", root, true, true);
3223   - },
3224   - 'only-of-type': function(nodes, formula, root) {
3225   - var p = Selector.pseudos;
3226   - return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
3227   - },
3228   -
3229   - // handles the an+b logic
3230   - getIndices: function(a, b, total) {
3231   - if (a == 0) return b > 0 ? [b] : [];
3232   - return $R(1, total).inject([], function(memo, i) {
3233   - if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
3234   - return memo;
3235   - });
3236   - },
3237   -
3238   - // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
3239   - nth: function(nodes, formula, root, reverse, ofType) {
3240   - if (nodes.length == 0) return [];
3241   - if (formula == 'even') formula = '2n+0';
3242   - if (formula == 'odd') formula = '2n+1';
3243   - var h = Selector.handlers, results = [], indexed = [], m;
3244   - h.mark(nodes);
3245   - for (var i = 0, node; node = nodes[i]; i++) {
3246   - if (!node.parentNode._countedByPrototype) {
3247   - h.index(node.parentNode, reverse, ofType);
3248   - indexed.push(node.parentNode);
3249   - }
3250   - }
3251   - if (formula.match(/^\d+$/)) { // just a number
3252   - formula = Number(formula);
3253   - for (var i = 0, node; node = nodes[i]; i++)
3254   - if (node.nodeIndex == formula) results.push(node);
3255   - } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
3256   - if (m[1] == "-") m[1] = -1;
3257   - var a = m[1] ? Number(m[1]) : 1;
3258   - var b = m[2] ? Number(m[2]) : 0;
3259   - var indices = Selector.pseudos.getIndices(a, b, nodes.length);
3260   - for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
3261   - for (var j = 0; j < l; j++)
3262   - if (node.nodeIndex == indices[j]) results.push(node);
3263   - }
3264   - }
3265   - h.unmark(nodes);
3266   - h.unmark(indexed);
3267   - return results;
3268   - },
3269   -
3270   - 'empty': function(nodes, value, root) {
3271   - for (var i = 0, results = [], node; node = nodes[i]; i++) {
3272   - // IE treats comments as element nodes
3273   - if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
3274   - results.push(node);
3275   - }
3276   - return results;
3277   - },
3278   -
3279   - 'not': function(nodes, selector, root) {
3280   - var h = Selector.handlers, selectorType, m;
3281   - var exclusions = new Selector(selector).findElements(root);
3282   - h.mark(exclusions);
3283   - for (var i = 0, results = [], node; node = nodes[i]; i++)
3284   - if (!node._countedByPrototype) results.push(node);
3285   - h.unmark(exclusions);
3286   - return results;
3287   - },
3288   -
3289   - 'enabled': function(nodes, value, root) {
3290   - for (var i = 0, results = [], node; node = nodes[i]; i++)
3291   - if (!node.disabled) results.push(node);
3292   - return results;
3293   - },
3294   -
3295   - 'disabled': function(nodes, value, root) {
3296   - for (var i = 0, results = [], node; node = nodes[i]; i++)
3297   - if (node.disabled) results.push(node);
3298   - return results;
3299   - },
3300   -
3301   - 'checked': function(nodes, value, root) {
3302   - for (var i = 0, results = [], node; node = nodes[i]; i++)
3303   - if (node.checked) results.push(node);
3304   - return results;
3305   - }
3306   - },
3307   -
3308   - operators: {
3309   - '=': function(nv, v) { return nv == v; },
3310   - '!=': function(nv, v) { return nv != v; },
3311   - '^=': function(nv, v) { return nv.startsWith(v); },
3312   - '$=': function(nv, v) { return nv.endsWith(v); },
3313   - '*=': function(nv, v) { return nv.include(v); },
3314   - '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
3315   - '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
3316   - },
3317   -
3318   - split: function(expression) {
3319   - var expressions = [];
3320   - expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
3321   - expressions.push(m[1].strip());
3322   - });
3323   - return expressions;
3324   - },
3325   -
3326   - matchElements: function(elements, expression) {
3327   - var matches = $$(expression), h = Selector.handlers;
3328   - h.mark(matches);
3329   - for (var i = 0, results = [], element; element = elements[i]; i++)
3330   - if (element._countedByPrototype) results.push(element);
3331   - h.unmark(matches);
3332   - return results;
3333   - },
3334   -
3335   - findElement: function(elements, expression, index) {
3336   - if (Object.isNumber(expression)) {
3337   - index = expression; expression = false;
3338   - }
3339   - return Selector.matchElements(elements, expression || '*')[index || 0];
3340   - },
3341   -
3342   - findChildElements: function(element, expressions) {
3343   - expressions = Selector.split(expressions.join(','));
3344   - var results = [], h = Selector.handlers;
3345   - for (var i = 0, l = expressions.length, selector; i < l; i++) {
3346   - selector = new Selector(expressions[i].strip());
3347   - h.concat(results, selector.findElements(element));
3348   - }
3349   - return (l > 1) ? h.unique(results) : results;
3350   - }
3351   -});
3352   -
3353   -if (Prototype.Browser.IE) {
3354   - Object.extend(Selector.handlers, {
3355   - // IE returns comment nodes on getElementsByTagName("*").
3356   - // Filter them out.
3357   - concat: function(a, b) {
3358   - for (var i = 0, node; node = b[i]; i++)
3359   - if (node.tagName !== "!") a.push(node);
3360   - return a;
3361   - },
3362   -
3363   - // IE improperly serializes _countedByPrototype in (inner|outer)HTML.
3364   - unmark: function(nodes) {
3365   - for (var i = 0, node; node = nodes[i]; i++)
3366   - node.removeAttribute('_countedByPrototype');
3367   - return nodes;
3368   - }
3369   - });
3370   -}
3371   -
3372   -function $$() {
3373   - return Selector.findChildElements(document, $A(arguments));
3374   -}
3375   -var Form = {
3376   - reset: function(form) {
3377   - $(form).reset();
3378   - return form;
3379   - },
3380   -
3381   - serializeElements: function(elements, options) {
3382   - if (typeof options != 'object') options = { hash: !!options };
3383   - else if (Object.isUndefined(options.hash)) options.hash = true;
3384   - var key, value, submitted = false, submit = options.submit;
3385   -
3386   - var data = elements.inject({ }, function(result, element) {
3387   - if (!element.disabled && element.name) {
3388   - key = element.name; value = $(element).getValue();
3389   - if (value != null && (element.type != 'submit' || (!submitted &&
3390   - submit !== false && (!submit || key == submit) && (submitted = true)))) {
3391   - if (key in result) {
3392   - // a key is already present; construct an array of values
3393   - if (!Object.isArray(result[key])) result[key] = [result[key]];
3394   - result[key].push(value);
3395   - }
3396   - else result[key] = value;
3397   - }
3398   - }
3399   - return result;
3400   - });
3401   -
3402   - return options.hash ? data : Object.toQueryString(data);
3403   - }
3404   -};
3405   -
3406   -Form.Methods = {
3407   - serialize: function(form, options) {
3408   - return Form.serializeElements(Form.getElements(form), options);
3409   - },
3410   -
3411   - getElements: function(form) {
3412   - return $A($(form).getElementsByTagName('*')).inject([],
3413   - function(elements, child) {
3414   - if (Form.Element.Serializers[child.tagName.toLowerCase()])
3415   - elements.push(Element.extend(child));
3416   - return elements;
3417   - }
3418   - );
3419   - },
3420   -
3421   - getInputs: function(form, typeName, name) {
3422   - form = $(form);
3423   - var inputs = form.getElementsByTagName('input');
3424   -
3425   - if (!typeName && !name) return $A(inputs).map(Element.extend);
3426   -
3427   - for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
3428   - var input = inputs[i];
3429   - if ((typeName && input.type != typeName) || (name && input.name != name))
3430   - continue;
3431   - matchingInputs.push(Element.extend(input));
3432   - }
3433   -
3434   - return matchingInputs;
3435   - },
3436   -
3437   - disable: function(form) {
3438   - form = $(form);
3439   - Form.getElements(form).invoke('disable');
3440   - return form;
3441   - },
3442   -
3443   - enable: function(form) {
3444   - form = $(form);
3445   - Form.getElements(form).invoke('enable');
3446   - return form;
3447   - },
3448   -
3449   - findFirstElement: function(form) {
3450   - var elements = $(form).getElements().findAll(function(element) {
3451   - return 'hidden' != element.type && !element.disabled;
3452   - });
3453   - var firstByIndex = elements.findAll(function(element) {
3454   - return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
3455   - }).sortBy(function(element) { return element.tabIndex }).first();
3456   -
3457   - return firstByIndex ? firstByIndex : elements.find(function(element) {
3458   - return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
3459   - });
3460   - },
3461   -
3462   - focusFirstElement: function(form) {
3463   - form = $(form);
3464   - form.findFirstElement().activate();
3465   - return form;
3466   - },
3467   -
3468   - request: function(form, options) {
3469   - form = $(form), options = Object.clone(options || { });
3470   -
3471   - var params = options.parameters, action = form.readAttribute('action') || '';
3472   - if (action.blank()) action = window.location.href;
3473   - options.parameters = form.serialize(true);
3474   -
3475   - if (params) {
3476   - if (Object.isString(params)) params = params.toQueryParams();
3477   - Object.extend(options.parameters, params);
3478   - }
3479   -
3480   - if (form.hasAttribute('method') && !options.method)
3481   - options.method = form.method;
3482   -
3483   - return new Ajax.Request(action, options);
3484   - }
3485   -};
3486   -
3487   -/*--------------------------------------------------------------------------*/
3488   -
3489   -Form.Element = {
3490   - focus: function(element) {
3491   - $(element).focus();
3492   - return element;
3493   - },
3494   -
3495   - select: function(element) {
3496   - $(element).select();
3497   - return element;
3498   - }
3499   -};
3500   -
3501   -Form.Element.Methods = {
3502   - serialize: function(element) {
3503   - element = $(element);
3504   - if (!element.disabled && element.name) {
3505   - var value = element.getValue();
3506   - if (value != undefined) {
3507   - var pair = { };
3508   - pair[element.name] = value;
3509   - return Object.toQueryString(pair);
3510   - }
3511   - }
3512   - return '';
3513   - },
3514   -
3515   - getValue: function(element) {
3516   - element = $(element);
3517   - var method = element.tagName.toLowerCase();
3518   - return Form.Element.Serializers[method](element);
3519   - },
3520   -
3521   - setValue: function(element, value) {
3522   - element = $(element);
3523   - var method = element.tagName.toLowerCase();
3524   - Form.Element.Serializers[method](element, value);
3525   - return element;
3526   - },
3527   -
3528   - clear: function(element) {
3529   - $(element).value = '';
3530   - return element;
3531   - },
3532   -
3533   - present: function(element) {
3534   - return $(element).value != '';
3535   - },
3536   -
3537   - activate: function(element) {
3538   - element = $(element);
3539   - try {
3540   - element.focus();
3541   - if (element.select && (element.tagName.toLowerCase() != 'input' ||
3542   - !['button', 'reset', 'submit'].include(element.type)))
3543   - element.select();
3544   - } catch (e) { }
3545   - return element;
3546   - },
3547   -
3548   - disable: function(element) {
3549   - element = $(element);
3550   - element.blur();
3551   - element.disabled = true;
3552   - return element;
3553   - },
3554   -
3555   - enable: function(element) {
3556   - element = $(element);
3557   - element.disabled = false;
3558   - return element;
3559   - }
3560   -};
3561   -
3562   -/*--------------------------------------------------------------------------*/
3563   -
3564   -var Field = Form.Element;
3565   -var $F = Form.Element.Methods.getValue;
3566   -
3567   -/*--------------------------------------------------------------------------*/
3568   -
3569   -Form.Element.Serializers = {
3570   - input: function(element, value) {
3571   - switch (element.type.toLowerCase()) {
3572   - case 'checkbox':
3573   - case 'radio':
3574   - return Form.Element.Serializers.inputSelector(element, value);
3575   - default:
3576   - return Form.Element.Serializers.textarea(element, value);
3577   - }
3578   - },
3579   -
3580   - inputSelector: function(element, value) {
3581   - if (Object.isUndefined(value)) return element.checked ? element.value : null;
3582   - else element.checked = !!value;
3583   - },
3584   -
3585   - textarea: function(element, value) {
3586   - if (Object.isUndefined(value)) return element.value;
3587   - else element.value = value;
3588   - },
3589   -
3590   - select: function(element, index) {
3591   - if (Object.isUndefined(index))
3592   - return this[element.type == 'select-one' ?
3593   - 'selectOne' : 'selectMany'](element);
3594   - else {
3595   - var opt, value, single = !Object.isArray(index);
3596   - for (var i = 0, length = element.length; i < length; i++) {
3597   - opt = element.options[i];
3598   - value = this.optionValue(opt);
3599   - if (single) {
3600   - if (value == index) {
3601   - opt.selected = true;
3602   - return;
3603   - }
3604   - }
3605   - else opt.selected = index.include(value);
3606   - }
3607   - }
3608   - },
3609   -
3610   - selectOne: function(element) {
3611   - var index = element.selectedIndex;
3612   - return index >= 0 ? this.optionValue(element.options[index]) : null;
3613   - },
3614   -
3615   - selectMany: function(element) {
3616   - var values, length = element.length;
3617   - if (!length) return null;
3618   -
3619   - for (var i = 0, values = []; i < length; i++) {
3620   - var opt = element.options[i];
3621   - if (opt.selected) values.push(this.optionValue(opt));
3622   - }
3623   - return values;
3624   - },
3625   -
3626   - optionValue: function(opt) {
3627   - // extend element because hasAttribute may not be native
3628   - return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
3629   - }
3630   -};
3631   -
3632   -/*--------------------------------------------------------------------------*/
3633   -
3634   -Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
3635   - initialize: function($super, element, frequency, callback) {
3636   - $super(callback, frequency);
3637   - this.element = $(element);
3638   - this.lastValue = this.getValue();
3639   - },
3640   -
3641   - execute: function() {
3642   - var value = this.getValue();
3643   - if (Object.isString(this.lastValue) && Object.isString(value) ?
3644   - this.lastValue != value : String(this.lastValue) != String(value)) {
3645   - this.callback(this.element, value);
3646   - this.lastValue = value;
3647   - }
3648   - }
3649   -});
3650   -
3651   -Form.Element.Observer = Class.create(Abstract.TimedObserver, {
3652   - getValue: function() {
3653   - return Form.Element.getValue(this.element);
3654   - }
3655   -});
3656   -
3657   -Form.Observer = Class.create(Abstract.TimedObserver, {
3658   - getValue: function() {
3659   - return Form.serialize(this.element);
3660   - }
3661   -});
3662   -
3663   -/*--------------------------------------------------------------------------*/
3664   -
3665   -Abstract.EventObserver = Class.create({
3666   - initialize: function(element, callback) {
3667   - this.element = $(element);
3668   - this.callback = callback;
3669   -
3670   - this.lastValue = this.getValue();
3671   - if (this.element.tagName.toLowerCase() == 'form')
3672   - this.registerFormCallbacks();
3673   - else
3674   - this.registerCallback(this.element);
3675   - },
3676   -
3677   - onElementEvent: function() {
3678   - var value = this.getValue();
3679   - if (this.lastValue != value) {
3680   - this.callback(this.element, value);
3681   - this.lastValue = value;
3682   - }
3683   - },
3684   -
3685   - registerFormCallbacks: function() {
3686   - Form.getElements(this.element).each(this.registerCallback, this);
3687   - },
3688   -
3689   - registerCallback: function(element) {
3690   - if (element.type) {
3691   - switch (element.type.toLowerCase()) {
3692   - case 'checkbox':
3693   - case 'radio':
3694   - Event.observe(element, 'click', this.onElementEvent.bind(this));
3695   - break;
3696   - default:
3697   - Event.observe(element, 'change', this.onElementEvent.bind(this));
3698   - break;
3699   - }
3700   - }
3701   - }
3702   -});
3703   -
3704   -Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
3705   - getValue: function() {
3706   - return Form.Element.getValue(this.element);
3707   - }
3708   -});
3709   -
3710   -Form.EventObserver = Class.create(Abstract.EventObserver, {
3711   - getValue: function() {
3712   - return Form.serialize(this.element);
3713   - }
3714   -});
3715   -if (!window.Event) var Event = { };
3716   -
3717   -Object.extend(Event, {
3718   - KEY_BACKSPACE: 8,
3719   - KEY_TAB: 9,
3720   - KEY_RETURN: 13,
3721   - KEY_ESC: 27,
3722   - KEY_LEFT: 37,
3723   - KEY_UP: 38,
3724   - KEY_RIGHT: 39,
3725   - KEY_DOWN: 40,
3726   - KEY_DELETE: 46,
3727   - KEY_HOME: 36,
3728   - KEY_END: 35,
3729   - KEY_PAGEUP: 33,
3730   - KEY_PAGEDOWN: 34,
3731   - KEY_INSERT: 45,
3732   -
3733   - cache: { },
3734   -
3735   - relatedTarget: function(event) {
3736   - var element;
3737   - switch(event.type) {
3738   - case 'mouseover': element = event.fromElement; break;
3739   - case 'mouseout': element = event.toElement; break;
3740   - default: return null;
3741   - }
3742   - return Element.extend(element);
3743   - }
3744   -});
3745   -
3746   -Event.Methods = (function() {
3747   - var isButton;
3748   -
3749   - if (Prototype.Browser.IE) {
3750   - var buttonMap = { 0: 1, 1: 4, 2: 2 };
3751   - isButton = function(event, code) {
3752   - return event.button == buttonMap[code];
3753   - };
3754   -
3755   - } else if (Prototype.Browser.WebKit) {
3756   - isButton = function(event, code) {
3757   - switch (code) {
3758   - case 0: return event.which == 1 && !event.metaKey;
3759   - case 1: return event.which == 1 && event.metaKey;
3760   - default: return false;
3761   - }
3762   - };
3763   -
3764   - } else {
3765   - isButton = function(event, code) {
3766   - return event.which ? (event.which === code + 1) : (event.button === code);
3767   - };
3768   - }
3769   -
3770   - return {
3771   - isLeftClick: function(event) { return isButton(event, 0) },
3772   - isMiddleClick: function(event) { return isButton(event, 1) },
3773   - isRightClick: function(event) { return isButton(event, 2) },
3774   -
3775   - element: function(event) {
3776   - var node = Event.extend(event).target;
3777   - return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node);
3778   - },
3779   -
3780   - findElement: function(event, expression) {
3781   - var element = Event.element(event);
3782   - if (!expression) return element;
3783   - var elements = [element].concat(element.ancestors());
3784   - return Selector.findElement(elements, expression, 0);
3785   - },
3786   -
3787   - pointer: function(event) {
3788   - return {
3789   - x: event.pageX || (event.clientX +
3790   - (document.documentElement.scrollLeft || document.body.scrollLeft)),
3791   - y: event.pageY || (event.clientY +
3792   - (document.documentElement.scrollTop || document.body.scrollTop))
3793   - };
3794   - },
3795   -
3796   - pointerX: function(event) { return Event.pointer(event).x },
3797   - pointerY: function(event) { return Event.pointer(event).y },
3798   -
3799   - stop: function(event) {
3800   - Event.extend(event);
3801   - event.preventDefault();
3802   - event.stopPropagation();
3803   - event.stopped = true;
3804   - }
3805   - };
3806   -})();
3807   -
3808   -Event.extend = (function() {
3809   - var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
3810   - m[name] = Event.Methods[name].methodize();
3811   - return m;
3812   - });
3813   -
3814   - if (Prototype.Browser.IE) {
3815   - Object.extend(methods, {
3816   - stopPropagation: function() { this.cancelBubble = true },
3817   - preventDefault: function() { this.returnValue = false },
3818   - inspect: function() { return "[object Event]" }
3819   - });
3820   -
3821   - return function(event) {
3822   - if (!event) return false;
3823   - if (event._extendedByPrototype) return event;
3824   -
3825   - event._extendedByPrototype = Prototype.emptyFunction;
3826   - var pointer = Event.pointer(event);
3827   - Object.extend(event, {
3828   - target: event.srcElement,
3829   - relatedTarget: Event.relatedTarget(event),
3830   - pageX: pointer.x,
3831   - pageY: pointer.y
3832   - });
3833   - return Object.extend(event, methods);
3834   - };
3835   -
3836   - } else {
3837   - Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__;
3838   - Object.extend(Event.prototype, methods);
3839   - return Prototype.K;
3840   - }
3841   -})();
3842   -
3843   -Object.extend(Event, (function() {
3844   - var cache = Event.cache;
3845   -
3846   - function getEventID(element) {
3847   - if (element._prototypeEventID) return element._prototypeEventID[0];
3848   - arguments.callee.id = arguments.callee.id || 1;
3849   - return element._prototypeEventID = [++arguments.callee.id];
3850   - }
3851   -
3852   - function getDOMEventName(eventName) {
3853   - if (eventName && eventName.include(':')) return "dataavailable";
3854   - return eventName;
3855   - }
3856   -
3857   - function getCacheForID(id) {
3858   - return cache[id] = cache[id] || { };
3859   - }
3860   -
3861   - function getWrappersForEventName(id, eventName) {
3862   - var c = getCacheForID(id);
3863   - return c[eventName] = c[eventName] || [];
3864   - }
3865   -
3866   - function createWrapper(element, eventName, handler) {
3867   - var id = getEventID(element);
3868   - var c = getWrappersForEventName(id, eventName);
3869   - if (c.pluck("handler").include(handler)) return false;
3870   -
3871   - var wrapper = function(event) {
3872   - if (!Event || !Event.extend ||
3873   - (event.eventName && event.eventName != eventName))
3874   - return false;
3875   -
3876   - Event.extend(event);
3877   - handler.call(element, event);
3878   - };
3879   -
3880   - wrapper.handler = handler;
3881   - c.push(wrapper);
3882   - return wrapper;
3883   - }
3884   -
3885   - function findWrapper(id, eventName, handler) {
3886   - var c = getWrappersForEventName(id, eventName);
3887   - return c.find(function(wrapper) { return wrapper.handler == handler });
3888   - }
3889   -
3890   - function destroyWrapper(id, eventName, handler) {
3891   - var c = getCacheForID(id);
3892   - if (!c[eventName]) return false;
3893   - c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
3894   - }
3895   -
3896   - function destroyCache() {
3897   - for (var id in cache)
3898   - for (var eventName in cache[id])
3899   - cache[id][eventName] = null;
3900   - }
3901   -
3902   - if (window.attachEvent) {
3903   - window.attachEvent("onunload", destroyCache);
3904   - }
3905   -
3906   - return {
3907   - observe: function(element, eventName, handler) {
3908   - element = $(element);
3909   - var name = getDOMEventName(eventName);
3910   -
3911   - var wrapper = createWrapper(element, eventName, handler);
3912   - if (!wrapper) return element;
3913   -
3914   - if (element.addEventListener) {
3915   - element.addEventListener(name, wrapper, false);
3916   - } else {
3917   - element.attachEvent("on" + name, wrapper);
3918   - }
3919   -
3920   - return element;
3921   - },
3922   -
3923   - stopObserving: function(element, eventName, handler) {
3924   - element = $(element);
3925   - var id = getEventID(element), name = getDOMEventName(eventName);
3926   -
3927   - if (!handler && eventName) {
3928   - getWrappersForEventName(id, eventName).each(function(wrapper) {
3929   - element.stopObserving(eventName, wrapper.handler);
3930   - });
3931   - return element;
3932   -
3933   - } else if (!eventName) {
3934   - Object.keys(getCacheForID(id)).each(function(eventName) {
3935   - element.stopObserving(eventName);
3936   - });
3937   - return element;
3938   - }
3939   -
3940   - var wrapper = findWrapper(id, eventName, handler);
3941   - if (!wrapper) return element;
3942   -
3943   - if (element.removeEventListener) {
3944   - element.removeEventListener(name, wrapper, false);
3945   - } else {
3946   - element.detachEvent("on" + name, wrapper);
3947   - }
3948   -
3949   - destroyWrapper(id, eventName, handler);
3950   -
3951   - return element;
3952   - },
3953   -
3954   - fire: function(element, eventName, memo) {
3955   - element = $(element);
3956   - if (element == document && document.createEvent && !element.dispatchEvent)
3957   - element = document.documentElement;
3958   -
3959   - var event;
3960   - if (document.createEvent) {
3961   - event = document.createEvent("HTMLEvents");
3962   - event.initEvent("dataavailable", true, true);
3963   - } else {
3964   - event = document.createEventObject();
3965   - event.eventType = "ondataavailable";
3966   - }
3967   -
3968   - event.eventName = eventName;
3969   - event.memo = memo || { };
3970   -
3971   - if (document.createEvent) {
3972   - element.dispatchEvent(event);
3973   - } else {
3974   - element.fireEvent(event.eventType, event);
3975   - }
3976   -
3977   - return Event.extend(event);
3978   - }
3979   - };
3980   -})());
3981   -
3982   -Object.extend(Event, Event.Methods);
3983   -
3984   -Element.addMethods({
3985   - fire: Event.fire,
3986   - observe: Event.observe,
3987   - stopObserving: Event.stopObserving
3988   -});
3989   -
3990   -Object.extend(document, {
3991   - fire: Element.Methods.fire.methodize(),
3992   - observe: Element.Methods.observe.methodize(),
3993   - stopObserving: Element.Methods.stopObserving.methodize(),
3994   - loaded: false
3995   -});
3996   -
3997   -(function() {
3998   - /* Support for the DOMContentLoaded event is based on work by Dan Webb,
3999   - Matthias Miller, Dean Edwards and John Resig. */
4000   -
4001   - var timer;
4002   -
4003   - function fireContentLoadedEvent() {
4004   - if (document.loaded) return;
4005   - if (timer) window.clearInterval(timer);
4006   - document.fire("dom:loaded");
4007   - document.loaded = true;
4008   - }
4009   -
4010   - if (document.addEventListener) {
4011   - if (Prototype.Browser.WebKit) {
4012   - timer = window.setInterval(function() {
4013   - if (/loaded|complete/.test(document.readyState))
4014   - fireContentLoadedEvent();
4015   - }, 0);
4016   -
4017   - Event.observe(window, "load", fireContentLoadedEvent);
4018   -
4019   - } else {
4020   - document.addEventListener("DOMContentLoaded",
4021   - fireContentLoadedEvent, false);
4022   - }
4023   -
4024   - } else {
4025   - document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>");
4026   - $("__onDOMContentLoaded").onreadystatechange = function() {
4027   - if (this.readyState == "complete") {
4028   - this.onreadystatechange = null;
4029   - fireContentLoadedEvent();
4030   - }
4031   - };
4032   - }
4033   -})();
4034   -/*------------------------------- DEPRECATED -------------------------------*/
4035   -
4036   -Hash.toQueryString = Object.toQueryString;
4037   -
4038   -var Toggle = { display: Element.toggle };
4039   -
4040   -Element.Methods.childOf = Element.Methods.descendantOf;
4041   -
4042   -var Insertion = {
4043   - Before: function(element, content) {
4044   - return Element.insert(element, {before:content});
4045   - },
4046   -
4047   - Top: function(element, content) {
4048   - return Element.insert(element, {top:content});
4049   - },
4050   -
4051   - Bottom: function(element, content) {
4052   - return Element.insert(element, {bottom:content});
4053   - },
4054   -
4055   - After: function(element, content) {
4056   - return Element.insert(element, {after:content});
4057   - }
4058   -};
4059   -
4060   -var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
4061   -
4062   -// This should be moved to script.aculo.us; notice the deprecated methods
4063   -// further below, that map to the newer Element methods.
4064   -var Position = {
4065   - // set to true if needed, warning: firefox performance problems
4066   - // NOT neeeded for page scrolling, only if draggable contained in
4067   - // scrollable elements
4068   - includeScrollOffsets: false,
4069   -
4070   - // must be called before calling withinIncludingScrolloffset, every time the
4071   - // page is scrolled
4072   - prepare: function() {
4073   - this.deltaX = window.pageXOffset
4074   - || document.documentElement.scrollLeft
4075   - || document.body.scrollLeft
4076   - || 0;
4077   - this.deltaY = window.pageYOffset
4078   - || document.documentElement.scrollTop
4079   - || document.body.scrollTop
4080   - || 0;
4081   - },
4082   -
4083   - // caches x/y coordinate pair to use with overlap
4084   - within: function(element, x, y) {
4085   - if (this.includeScrollOffsets)
4086   - return this.withinIncludingScrolloffsets(element, x, y);
4087   - this.xcomp = x;
4088   - this.ycomp = y;
4089   - this.offset = Element.cumulativeOffset(element);
4090   -
4091   - return (y >= this.offset[1] &&
4092   - y < this.offset[1] + element.offsetHeight &&
4093   - x >= this.offset[0] &&
4094   - x < this.offset[0] + element.offsetWidth);
4095   - },
4096   -
4097   - withinIncludingScrolloffsets: function(element, x, y) {
4098   - var offsetcache = Element.cumulativeScrollOffset(element);
4099   -
4100   - this.xcomp = x + offsetcache[0] - this.deltaX;
4101   - this.ycomp = y + offsetcache[1] - this.deltaY;
4102   - this.offset = Element.cumulativeOffset(element);
4103   -
4104   - return (this.ycomp >= this.offset[1] &&
4105   - this.ycomp < this.offset[1] + element.offsetHeight &&
4106   - this.xcomp >= this.offset[0] &&
4107   - this.xcomp < this.offset[0] + element.offsetWidth);
4108   - },
4109   -
4110   - // within must be called directly before
4111   - overlap: function(mode, element) {
4112   - if (!mode) return 0;
4113   - if (mode == 'vertical')
4114   - return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
4115   - element.offsetHeight;
4116   - if (mode == 'horizontal')
4117   - return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
4118   - element.offsetWidth;
4119   - },
4120   -
4121   - // Deprecation layer -- use newer Element methods now (1.5.2).
4122   -
4123   - cumulativeOffset: Element.Methods.cumulativeOffset,
4124   -
4125   - positionedOffset: Element.Methods.positionedOffset,
4126   -
4127   - absolutize: function(element) {
4128   - Position.prepare();
4129   - return Element.absolutize(element);
4130   - },
4131   -
4132   - relativize: function(element) {
4133   - Position.prepare();
4134   - return Element.relativize(element);
4135   - },
4136   -
4137   - realOffset: Element.Methods.cumulativeScrollOffset,
4138   -
4139   - offsetParent: Element.Methods.getOffsetParent,
4140   -
4141   - page: Element.Methods.viewportOffset,
4142   -
4143   - clone: function(source, target, options) {
4144   - options = options || { };
4145   - return Element.clonePosition(target, source, options);
4146   - }
4147   -};
4148   -
4149   -/*--------------------------------------------------------------------------*/
4150   -
4151   -if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
4152   - function iter(name) {
4153   - return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
4154   - }
4155   -
4156   - instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
4157   - function(element, className) {
4158   - className = className.toString().strip();
4159   - var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
4160   - return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
4161   - } : function(element, className) {
4162   - className = className.toString().strip();
4163   - var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
4164   - if (!classNames && !className) return elements;
4165   -
4166   - var nodes = $(element).getElementsByTagName('*');
4167   - className = ' ' + className + ' ';
4168   -
4169   - for (var i = 0, child, cn; child = nodes[i]; i++) {
4170   - if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
4171   - (classNames && classNames.all(function(name) {
4172   - return !name.toString().blank() && cn.include(' ' + name + ' ');
4173   - }))))
4174   - elements.push(Element.extend(child));
4175   - }
4176   - return elements;
4177   - };
4178   -
4179   - return function(className, parentElement) {
4180   - return $(parentElement || document.body).getElementsByClassName(className);
4181   - };
4182   -}(Element.Methods);
4183   -
4184   -/*--------------------------------------------------------------------------*/
4185   -
4186   -Element.ClassNames = Class.create();
4187   -Element.ClassNames.prototype = {
4188   - initialize: function(element) {
4189   - this.element = $(element);
4190   - },
4191   -
4192   - _each: function(iterator) {
4193   - this.element.className.split(/\s+/).select(function(name) {
4194   - return name.length > 0;
4195   - })._each(iterator);
4196   - },
4197   -
4198   - set: function(className) {
4199   - this.element.className = className;
4200   - },
4201   -
4202   - add: function(classNameToAdd) {
4203   - if (this.include(classNameToAdd)) return;
4204   - this.set($A(this).concat(classNameToAdd).join(' '));
4205   - },
4206   -
4207   - remove: function(classNameToRemove) {
4208   - if (!this.include(classNameToRemove)) return;
4209   - this.set($A(this).without(classNameToRemove).join(' '));
4210   - },
4211   -
4212   - toString: function() {
4213   - return $A(this).join(' ');
4214   - }
4215   -};
4216   -
4217   -Object.extend(Element.ClassNames.prototype, Enumerable);
4218   -
4219   -/*--------------------------------------------------------------------------*/
4220   -
4221   -Element.addMethods();
4222 0 \ No newline at end of file
public/javascripts/strophejs-1.1.3/examples/attach/__init__.py
public/javascripts/strophejs-1.1.3/examples/attach/attacher/__init__.py
test/test_helper.rb
... ... @@ -140,9 +140,18 @@ class ActiveSupport::TestCase
140 140 end
141 141  
142 142 # For models that render views (blocks, articles, ...)
143   - def render(*args)
144   - view_paths = @explicit_view_paths || ActionController::Base.view_paths
145   - ActionView::Base.new(view_paths, {}).render(*args)
  143 + def self.action_view
  144 + @action_view ||= begin
  145 + view_paths = ActionController::Base.view_paths
  146 + action_view = ActionView::Base.new view_paths, {}
  147 + # for using Noosfero helpers inside render calls
  148 + action_view.extend ApplicationHelper
  149 + action_view
  150 + end
  151 + end
  152 +
  153 + def render *args
  154 + self.class.action_view.render(*args)
146 155 end
147 156  
148 157 private
... ...