From 6d4a2181b79a18caa352a25edc9b965a3e1ec68b Mon Sep 17 00:00:00 2001 From: Ed Wildgoose Date: Tue, 28 Oct 2008 19:10:38 +0000 Subject: [PATCH] fix line endings --- .../default/javascripts/form_enhancements.js | 176 +++---- .../default/stylesheets/stylesheet-ie.css | 68 +-- .../default/views/_form_association.rhtml | 32 +- .../views/_form_association_header.rhtml | 18 +- .../views/_form_association_record.rhtml | 44 +- frontends/default/views/_list_actions.rhtml | 24 +- frontends/default/views/_list_header.rhtml | 22 +- frontends/default/views/_live_search.rhtml | 50 +- frontends/default/views/_search.rhtml | 40 +- frontends/default/views/show.rhtml | 8 +- install.rb | 78 ++-- install_assets.rb | 70 +-- lib/actions/nested.rb | 434 +++++++++--------- lib/active_scaffold.rb | 264 +++++------ .../calendar_date_select/lib/as_cds_bridge.rb | 106 ++--- .../file_column/lib/as_file_column_bridge.rb | 94 ++-- .../test/functional/file_column_keep_test.rb | 84 ++-- lib/bridges/file_column/test/mock_model.rb | 16 +- lib/bridges/file_column/test/test_helper.rb | 30 +- lib/extensions/reverse_associations.rb | 110 ++--- lib/helpers/id_helpers.rb | 250 +++++----- lib/helpers/view_helpers.rb | 412 ++++++++--------- test/config/update_test.rb | 32 +- 23 files changed, 1231 insertions(+), 1231 deletions(-) diff --git a/frontends/default/javascripts/form_enhancements.js b/frontends/default/javascripts/form_enhancements.js index 9c96685..d739556 100644 --- a/frontends/default/javascripts/form_enhancements.js +++ b/frontends/default/javascripts/form_enhancements.js @@ -1,89 +1,89 @@ - -// TODO Change to dropping the name property off the input element when in example mode -TextFieldWithExample = Class.create(); -TextFieldWithExample.prototype = { - initialize: function(inputElementId, defaultText, options) { - this.setOptions(options); - - this.input = $(inputElementId); - this.name = this.input.name; - this.defaultText = defaultText; - this.createHiddenInput(); - - this.checkAndShowExample(); - - Event.observe(this.input, "blur", this.onBlur.bindAsEventListener(this)); - Event.observe(this.input, "focus", this.onFocus.bindAsEventListener(this)); - Event.observe(this.input, "select", this.onFocus.bindAsEventListener(this)); - Event.observe(this.input, "keydown", this.onKeyPress.bindAsEventListener(this)); - Event.observe(this.input, "click", this.onClick.bindAsEventListener(this)); - }, - createHiddenInput: function() { - this.hiddenInput = document.createElement("input"); - this.hiddenInput.type = "hidden"; - this.hiddenInput.value = ""; - this.input.parentNode.appendChild(this.hiddenInput); - }, - setOptions: function(options) { - this.options = { exampleClassName: 'example' }; - Object.extend(this.options, options || {}); - }, - onKeyPress: function(event) { - if (!event) var event = window.event; - var code = (event.which) ? event.which : event.keyCode - if (this.isAlphanumeric(code)) { - this.removeExample(); - } - }, - onBlur: function(event) { - this.checkAndShowExample(); - }, - onFocus: function(event) { - if (this.exampleShown()) { - this.removeExample(); - } - }, - onClick: function(event) { - this.removeExample(); - }, - isAlphanumeric: function(keyCode) { - return keyCode >= 40 && keyCode <= 90; - }, - checkAndShowExample: function() { - if (this.input.value == '') { - this.input.value = this.defaultText; - this.input.name = null; - this.hiddenInput.name = this.name; - Element.addClassName(this.input, this.options.exampleClassName); - } - }, - removeExample: function() { - if (this.exampleShown()) { - this.input.value = ''; - this.input.name = this.name; - this.hiddenInput.name = null; - Element.removeClassName(this.input, this.options.exampleClassName); - } - }, - exampleShown: function() { - return Element.hasClassName(this.input, this.options.exampleClassName); - } -} - -Form.disable = function(form) { - var elements = this.getElements(form); - for (var i = 0; i < elements.length; i++) { - var element = elements[i]; - try { element.blur(); } catch (e) {} - element.disabled = 'disabled'; - Element.addClassName(element, 'disabled'); - } - } -Form.enable = function(form) { - var elements = this.getElements(form); - for (var i = 0; i < elements.length; i++) { - var element = elements[i]; - element.disabled = ''; - Element.removeClassName(element, 'disabled'); - } + +// TODO Change to dropping the name property off the input element when in example mode +TextFieldWithExample = Class.create(); +TextFieldWithExample.prototype = { + initialize: function(inputElementId, defaultText, options) { + this.setOptions(options); + + this.input = $(inputElementId); + this.name = this.input.name; + this.defaultText = defaultText; + this.createHiddenInput(); + + this.checkAndShowExample(); + + Event.observe(this.input, "blur", this.onBlur.bindAsEventListener(this)); + Event.observe(this.input, "focus", this.onFocus.bindAsEventListener(this)); + Event.observe(this.input, "select", this.onFocus.bindAsEventListener(this)); + Event.observe(this.input, "keydown", this.onKeyPress.bindAsEventListener(this)); + Event.observe(this.input, "click", this.onClick.bindAsEventListener(this)); + }, + createHiddenInput: function() { + this.hiddenInput = document.createElement("input"); + this.hiddenInput.type = "hidden"; + this.hiddenInput.value = ""; + this.input.parentNode.appendChild(this.hiddenInput); + }, + setOptions: function(options) { + this.options = { exampleClassName: 'example' }; + Object.extend(this.options, options || {}); + }, + onKeyPress: function(event) { + if (!event) var event = window.event; + var code = (event.which) ? event.which : event.keyCode + if (this.isAlphanumeric(code)) { + this.removeExample(); + } + }, + onBlur: function(event) { + this.checkAndShowExample(); + }, + onFocus: function(event) { + if (this.exampleShown()) { + this.removeExample(); + } + }, + onClick: function(event) { + this.removeExample(); + }, + isAlphanumeric: function(keyCode) { + return keyCode >= 40 && keyCode <= 90; + }, + checkAndShowExample: function() { + if (this.input.value == '') { + this.input.value = this.defaultText; + this.input.name = null; + this.hiddenInput.name = this.name; + Element.addClassName(this.input, this.options.exampleClassName); + } + }, + removeExample: function() { + if (this.exampleShown()) { + this.input.value = ''; + this.input.name = this.name; + this.hiddenInput.name = null; + Element.removeClassName(this.input, this.options.exampleClassName); + } + }, + exampleShown: function() { + return Element.hasClassName(this.input, this.options.exampleClassName); + } +} + +Form.disable = function(form) { + var elements = this.getElements(form); + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + try { element.blur(); } catch (e) {} + element.disabled = 'disabled'; + Element.addClassName(element, 'disabled'); + } + } +Form.enable = function(form) { + var elements = this.getElements(form); + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + element.disabled = ''; + Element.removeClassName(element, 'disabled'); + } } \ No newline at end of file diff --git a/frontends/default/stylesheets/stylesheet-ie.css b/frontends/default/stylesheets/stylesheet-ie.css index d89b15a..d8759cf 100644 --- a/frontends/default/stylesheets/stylesheet-ie.css +++ b/frontends/default/stylesheets/stylesheet-ie.css @@ -1,35 +1,35 @@ -/* IE hacks - ==================================== */ - -* html .active-scaffold-header, -.active-scaffold li.form-element, -.active-scaffold li.sub-section { -zoom: 1; -} - -* html .active-scaffold td .messages-container { -border-top: solid 1px #DAFFCD; -} - -.active-scaffold-header div.actions a.show_search { -background-image: none; -filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/active_scaffold/default/magnifier.png', sizingMethod='crop'); -} - -.active-scaffold .sub-form .association-record a.destroy { -background-image: none; -filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/active_scaffold/default/cross.png', sizingMethod='crop'); -} - -.active-scaffold-header div.actions a.disabled { -filter: alpha(opacity=50); -} - -.active-scaffold .show-view dd, -.active-scaffold li.form-element dd { -float: none; -} - -.active-scaffold li.form-element dt { -padding: 4px 0; +/* IE hacks + ==================================== */ + +* html .active-scaffold-header, +.active-scaffold li.form-element, +.active-scaffold li.sub-section { +zoom: 1; +} + +* html .active-scaffold td .messages-container { +border-top: solid 1px #DAFFCD; +} + +.active-scaffold-header div.actions a.show_search { +background-image: none; +filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/active_scaffold/default/magnifier.png', sizingMethod='crop'); +} + +.active-scaffold .sub-form .association-record a.destroy { +background-image: none; +filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/active_scaffold/default/cross.png', sizingMethod='crop'); +} + +.active-scaffold-header div.actions a.disabled { +filter: alpha(opacity=50); +} + +.active-scaffold .show-view dd, +.active-scaffold li.form-element dd { +float: none; +} + +.active-scaffold li.form-element dt { +padding: 4px 0; } \ No newline at end of file diff --git a/frontends/default/views/_form_association.rhtml b/frontends/default/views/_form_association.rhtml index 5f64b73..aa61060 100644 --- a/frontends/default/views/_form_association.rhtml +++ b/frontends/default/views/_form_association.rhtml @@ -1,16 +1,16 @@ -<% -parent_record = @record -associated = column.singular_association? ? [parent_record.send(column.name)].compact : parent_record.send(column.name) -associated = associated.sort_by {|r| r.new_record? ? 99999999999 : r.id} unless column.association.options.has_key?(:order) - -show_blank_record = (column.plural_association? or (column.singular_association? and associated.empty?)) -show_blank_record = false if column.through_association? -show_blank_record = false unless column.association.klass.authorized_for?(:action => :create) - -associated << column.association.klass.new if show_blank_record --%> -
<%= column.label -%> (<%= link_to_visibility_toggle(:default_visible => !column.collapsed) -%>)
-
> -<%= render :partial => subform_partial_for_column(column), :locals => {:column => column, :scope => column_scope(column), :parent_record => parent_record, :associated => associated} %> -
-<% @record = parent_record -%> +<% +parent_record = @record +associated = column.singular_association? ? [parent_record.send(column.name)].compact : parent_record.send(column.name) +associated = associated.sort_by {|r| r.new_record? ? 99999999999 : r.id} unless column.association.options.has_key?(:order) + +show_blank_record = (column.plural_association? or (column.singular_association? and associated.empty?)) +show_blank_record = false if column.through_association? +show_blank_record = false unless column.association.klass.authorized_for?(:action => :create) + +associated << column.association.klass.new if show_blank_record +-%> +
<%= column.label -%> (<%= link_to_visibility_toggle(:default_visible => !column.collapsed) -%>)
+
> +<%= render :partial => subform_partial_for_column(column), :locals => {:column => column, :scope => column_scope(column), :parent_record => parent_record, :associated => associated} %> +
+<% @record = parent_record -%> diff --git a/frontends/default/views/_form_association_header.rhtml b/frontends/default/views/_form_association_header.rhtml index 454d8c0..e1760b5 100644 --- a/frontends/default/views/_form_association_header.rhtml +++ b/frontends/default/views/_form_association_header.rhtml @@ -1,10 +1,10 @@ - - - <% - active_scaffold_config_for(@record.class).subform.columns.each :for => @record, :flatten => true do |column| - next unless in_subform?(column, parent_record) and column_renders_as(column) != :hidden - -%> - <%= column.label %> - <% end -%> - + + + <% + active_scaffold_config_for(@record.class).subform.columns.each :for => @record, :flatten => true do |column| + next unless in_subform?(column, parent_record) and column_renders_as(column) != :hidden + -%> + <%= column.label %> + <% end -%> + \ No newline at end of file diff --git a/frontends/default/views/_form_association_record.rhtml b/frontends/default/views/_form_association_record.rhtml index ab328e0..592366d 100644 --- a/frontends/default/views/_form_association_record.rhtml +++ b/frontends/default/views/_form_association_record.rhtml @@ -1,22 +1,22 @@ -<% readonly = (@record.readonly? or not @record.authorized_for?(:action => :update)) -%> -<% active_scaffold_config_for(@record.class).subform.columns.each :for => @record, :flatten => true do |column| %> - <% - next unless in_subform?(column, parent_record) - column = column.clone - column.form_ui ||= :select if column.association - -%> - - <% unless readonly -%> - <%= render :partial => form_partial_for_column(column), :locals => { :column => column, :scope => scope } -%> - <% else -%> -

<%= h @record.send(column.name) -%>

- <% end -%> - -<% end -%> - - <%= link_to_function as_('Remove'), '$(this).up(".association-record").remove()', { :class => "destroy" } -%> - <% unless @record.new_record? %> - " value="<%= @record.id -%>" /> - <% end -%> - - +<% readonly = (@record.readonly? or not @record.authorized_for?(:action => :update)) -%> +<% active_scaffold_config_for(@record.class).subform.columns.each :for => @record, :flatten => true do |column| %> + <% + next unless in_subform?(column, parent_record) + column = column.clone + column.form_ui ||= :select if column.association + -%> + + <% unless readonly -%> + <%= render :partial => form_partial_for_column(column), :locals => { :column => column, :scope => scope } -%> + <% else -%> +

<%= h @record.send(column.name) -%>

+ <% end -%> + +<% end -%> + + <%= link_to_function as_('Remove'), '$(this).up(".association-record").remove()', { :class => "destroy" } -%> + <% unless @record.new_record? %> + " value="<%= @record.id -%>" /> + <% end -%> + + diff --git a/frontends/default/views/_list_actions.rhtml b/frontends/default/views/_list_actions.rhtml index 499c05d..90d0279 100644 --- a/frontends/default/views/_list_actions.rhtml +++ b/frontends/default/views/_list_actions.rhtml @@ -1,13 +1,13 @@ - - - - <% active_scaffold_config.action_links.each :record do |link| -%> - <% next if controller.respond_to? link.security_method and !controller.send(link.security_method) -%> - - <% end -%> - +
- <%= loading_indicator_tag(:action => :record, :id => record.id) %> - - <%= record.authorized_for?(:action => link.crud_type) ? render_action_link(link, url_options) : "#{link.label}" -%> -
+ + + <% active_scaffold_config.action_links.each :record do |link| -%> + <% next if controller.respond_to? link.security_method and !controller.send(link.security_method) -%> + + <% end -%> +
+ <%= loading_indicator_tag(:action => :record, :id => record.id) %> + + <%= record.authorized_for?(:action => link.crud_type) ? render_action_link(link, url_options) : "#{link.label}" -%> +
\ No newline at end of file diff --git a/frontends/default/views/_list_header.rhtml b/frontends/default/views/_list_header.rhtml index 30488e0..3ac3f17 100644 --- a/frontends/default/views/_list_header.rhtml +++ b/frontends/default/views/_list_header.rhtml @@ -1,12 +1,12 @@ -<% if active_scaffold_config.action_links.any? { |link| link.type == :table } -%> -
- <% new_params = params_for(:action => :table) %> - <% active_scaffold_config.action_links.each :table do |link| -%> - <% next if controller.respond_to? link.security_method and !controller.send(link.security_method) -%> - <%= render_action_link(link, new_params) -%> - <% end -%> - - <%= loading_indicator_tag(:action => :table) %> -
-<% end %> +<% if active_scaffold_config.action_links.any? { |link| link.type == :table } -%> +
+ <% new_params = params_for(:action => :table) %> + <% active_scaffold_config.action_links.each :table do |link| -%> + <% next if controller.respond_to? link.security_method and !controller.send(link.security_method) -%> + <%= render_action_link(link, new_params) -%> + <% end -%> + + <%= loading_indicator_tag(:action => :table) %> +
+<% end %>

<%= active_scaffold_config.list.user.label %>

\ No newline at end of file diff --git a/frontends/default/views/_live_search.rhtml b/frontends/default/views/_live_search.rhtml index 41290fb..71901f4 100644 --- a/frontends/default/views/_live_search.rhtml +++ b/frontends/default/views/_live_search.rhtml @@ -1,25 +1,25 @@ -<% href = url_for(params_for(:action => :update_table, :escape => false).delete_if{|k,v| k == 'search'}) -%> -<%= form_remote_tag :url => href, - :method => :get, - :before => "addActiveScaffoldPageToHistory('#{href}', '#{params[:controller]}')", - :after => "$('#{loading_indicator_id(:action => :search, :id => params[:id])}').style.visibility = 'visible';", - :complete => "$('#{loading_indicator_id(:action => :search, :id => params[:id])}').style.visibility = 'hidden';", - :failure => "ActiveScaffold.report_500_response('#{active_scaffold_id}')", - :update => active_scaffold_content_id, - :html => { :href => href, :id => search_form_id, :class => 'search' } %> - - <%= as_('Reset') -%> - <%= loading_indicator_tag(:action => :search) %> - - - +<% href = url_for(params_for(:action => :update_table, :escape => false).delete_if{|k,v| k == 'search'}) -%> +<%= form_remote_tag :url => href, + :method => :get, + :before => "addActiveScaffoldPageToHistory('#{href}', '#{params[:controller]}')", + :after => "$('#{loading_indicator_id(:action => :search, :id => params[:id])}').style.visibility = 'visible';", + :complete => "$('#{loading_indicator_id(:action => :search, :id => params[:id])}').style.visibility = 'hidden';", + :failure => "ActiveScaffold.report_500_response('#{active_scaffold_id}')", + :update => active_scaffold_content_id, + :html => { :href => href, :id => search_form_id, :class => 'search' } %> + + <%= as_('Reset') -%> + <%= loading_indicator_tag(:action => :search) %> + + + diff --git a/frontends/default/views/_search.rhtml b/frontends/default/views/_search.rhtml index 5c86b21..c8a9444 100644 --- a/frontends/default/views/_search.rhtml +++ b/frontends/default/views/_search.rhtml @@ -1,21 +1,21 @@ -<% href = url_for(params_for(:action => :update_table, :escape => false).delete_if{|k,v| k == 'search'}) -%> -<%= form_remote_tag :url => href, - :method => :get, - :before => "addActiveScaffoldPageToHistory('#{href}', '#{params[:controller]}')", - :after => "$('#{loading_indicator_id(:action => :search, :id => params[:id])}').style.visibility = 'visible'; Form.disable('#{search_form_id}');", - :complete => "$('#{loading_indicator_id(:action => :search, :id => params[:id])}').style.visibility = 'hidden'; Form.enable('#{search_form_id}');", - :failure => "ActiveScaffold.report_500_response('#{active_scaffold_id}')", - :update => active_scaffold_content_id, - :html => { :href => href, :id => search_form_id, :class => 'search' } %> - - <%= submit_tag as_('Search'), :class => "submit" %> - <%= as_('Reset') -%> - <%= loading_indicator_tag(:action => :search) %> - - - \ No newline at end of file diff --git a/frontends/default/views/show.rhtml b/frontends/default/views/show.rhtml index 0dab6aa..0b36a91 100644 --- a/frontends/default/views/show.rhtml +++ b/frontends/default/views/show.rhtml @@ -1,5 +1,5 @@ -
-
view"> - <%= render :partial => 'show' -%> -
+
+
view"> + <%= render :partial => 'show' -%> +
\ No newline at end of file diff --git a/install.rb b/install.rb index 1910d1b..6d2e4d1 100644 --- a/install.rb +++ b/install.rb @@ -1,40 +1,40 @@ -## -## Install ActiveScaffold assets into /public -## - -require File.dirname(__FILE__) + '/install_assets' - -## -## Install Counter -## -# -# What's going on here? -# We're incrementing a web counter so we can track SVN installs of ActiveScaffold -# -# How? -# We're making a GET request to errcount.com to update a simple counter. No data is transmitted. -# -# Why? -# So we can know how many people are using ActiveScaffold and modulate our level of effort accordingly. -# Despite numerous pleas our Googly overlords still only provide us with download stats for the zip distro. -# -# *Thanks for your understanding* -# - -class ErrCounter # using errcount.com - require "net/http" - - @@ACCOUNT_ID = 341 - @@SITE_DOMAIN = 'installs.activescaffold.com' - - def self.increment - @http = Net::HTTP.new("errcount.com") - resp, data = @http.get2("/ctr/#{@@ACCOUNT_ID}.js", {'Referer' => @@SITE_DOMAIN}) - puts resp.body - end -end - -begin - ErrCounter.increment -rescue +## +## Install ActiveScaffold assets into /public +## + +require File.dirname(__FILE__) + '/install_assets' + +## +## Install Counter +## +# +# What's going on here? +# We're incrementing a web counter so we can track SVN installs of ActiveScaffold +# +# How? +# We're making a GET request to errcount.com to update a simple counter. No data is transmitted. +# +# Why? +# So we can know how many people are using ActiveScaffold and modulate our level of effort accordingly. +# Despite numerous pleas our Googly overlords still only provide us with download stats for the zip distro. +# +# *Thanks for your understanding* +# + +class ErrCounter # using errcount.com + require "net/http" + + @@ACCOUNT_ID = 341 + @@SITE_DOMAIN = 'installs.activescaffold.com' + + def self.increment + @http = Net::HTTP.new("errcount.com") + resp, data = @http.get2("/ctr/#{@@ACCOUNT_ID}.js", {'Referer' => @@SITE_DOMAIN}) + puts resp.body + end +end + +begin + ErrCounter.increment +rescue end \ No newline at end of file diff --git a/install_assets.rb b/install_assets.rb index fb8c32e..37b3006 100755 --- a/install_assets.rb +++ b/install_assets.rb @@ -1,36 +1,36 @@ -# Workaround a problem with script/plugin and http-based repos. -# See http://dev.rubyonrails.org/ticket/8189 -Dir.chdir(Dir.getwd.sub(/vendor.*/, '')) do - -## -## Copy over asset files (javascript/css/images) from the plugin directory to public/ -## - -def copy_files(source_path, destination_path, directory) - source, destination = File.join(directory, source_path), File.join(Rails.root, destination_path) - FileUtils.mkdir(destination) unless File.exist?(destination) - FileUtils.cp_r(Dir.glob(source+'/*.*'), destination) -end - -directory = File.dirname(__FILE__) - -copy_files("/public", "/public", directory) - -available_frontends = Dir[File.join(directory, 'frontends', '*')].collect { |d| File.basename d } -[ :stylesheets, :javascripts, :images].each do |asset_type| - path = "/public/#{asset_type}/active_scaffold" - copy_files(path, path, directory) - - File.open(File.join(Rails.root, path, 'DO_NOT_EDIT'), 'w') do |f| - f.puts "Any changes made to files in sub-folders will be lost." - f.puts "See http://activescaffold.com/tutorials/faq#custom-css." - end - - available_frontends.each do |frontend| - source = "/frontends/#{frontend}/#{asset_type}/" - destination = "/public/#{asset_type}/active_scaffold/#{frontend}" - copy_files(source, destination, directory) - end -end - +# Workaround a problem with script/plugin and http-based repos. +# See http://dev.rubyonrails.org/ticket/8189 +Dir.chdir(Dir.getwd.sub(/vendor.*/, '')) do + +## +## Copy over asset files (javascript/css/images) from the plugin directory to public/ +## + +def copy_files(source_path, destination_path, directory) + source, destination = File.join(directory, source_path), File.join(Rails.root, destination_path) + FileUtils.mkdir(destination) unless File.exist?(destination) + FileUtils.cp_r(Dir.glob(source+'/*.*'), destination) +end + +directory = File.dirname(__FILE__) + +copy_files("/public", "/public", directory) + +available_frontends = Dir[File.join(directory, 'frontends', '*')].collect { |d| File.basename d } +[ :stylesheets, :javascripts, :images].each do |asset_type| + path = "/public/#{asset_type}/active_scaffold" + copy_files(path, path, directory) + + File.open(File.join(Rails.root, path, 'DO_NOT_EDIT'), 'w') do |f| + f.puts "Any changes made to files in sub-folders will be lost." + f.puts "See http://activescaffold.com/tutorials/faq#custom-css." + end + + available_frontends.each do |frontend| + source = "/frontends/#{frontend}/#{asset_type}/" + destination = "/public/#{asset_type}/active_scaffold/#{frontend}" + copy_files(source, destination, directory) + end +end + end \ No newline at end of file diff --git a/lib/actions/nested.rb b/lib/actions/nested.rb index a6aaa1e..072827f 100644 --- a/lib/actions/nested.rb +++ b/lib/actions/nested.rb @@ -1,217 +1,217 @@ -module ActiveScaffold::Actions - # The Nested module basically handles automatically linking controllers together. It does this by creating column links with the right parameters, and by providing any supporting systems (like a /:controller/nested action for returning associated scaffolds). - module Nested - - def self.included(base) - super - base.before_filter :include_habtm_actions - # TODO: it's a bit wasteful to run this routine every page load. - base.before_filter :links_for_associations - end - - def nested - do_nested - - respond_to do |type| - type.html { render :partial => 'nested', :layout => true } - type.js { render :partial => 'nested', :layout => false } - end - end - - protected - - # A simple method to find the record we'll be nesting *from* - # May be overridden to customize the behavior - def do_nested - @record = find_if_allowed(params[:id], :read) - end - - # Create the automatic column links. Note that this has to happen when configuration is *done*, because otherwise the Nested module could be disabled. Actually, it could still be disabled later, couldn't it? - # TODO: This should really be a post-config routine, instead of a before_filter. - def links_for_associations - active_scaffold_config.list.columns.each do |column| - # if column.link == false we won't create a link. that's how a dev can suppress the auto links. - if column.association and column.link.nil? - if column.plural_association? - # note: we can't create nested scaffolds on :through associations because there's no reverse association. - column.set_link('nested', :parameters => {:associations => column.name.to_sym}) #unless column.through_association? - elsif not column.polymorphic_association? - model = column.association.klass - begin - controller = self.class.active_scaffold_controller_for(model) - rescue ActiveScaffold::ControllerNotFound - next - end - - actions = controller.active_scaffold_config.actions - action = nil - if actions.include? :update and model.authorized_for? :action => :update - action = 'edit' - elsif actions.include? :show and model.authorized_for? :action => :read - action = 'show' - end - column.set_link(action, :controller => controller.controller_path, :parameters => {:parent_controller => params[:controller]}) if action - end - end - end - end - - def include_habtm_actions - if nested_habtm? - # Production mode is ok with adding a link everytime the scaffold is nested - we ar not ok with that. - active_scaffold_config.action_links.add('new_existing', :label => 'Add Existing', :type => :table, :security_method => :add_existing_authorized?) unless active_scaffold_config.action_links['new_existing'] - if active_scaffold_config.nested.shallow_delete - active_scaffold_config.action_links.add('destroy_existing', :label => 'Remove', :type => :record, :confirm => 'Are you sure?', :method => :delete, :position => false, :security_method => :delete_existing_authorized?) unless active_scaffold_config.action_links['destroy_existing'] - active_scaffold_config.action_links.delete("destroy") if active_scaffold_config.action_links['destroy'] - end - - self.class.module_eval do - include ActiveScaffold::Actions::Nested::ChildMethods - # we need specifically to tell action_controller to add these public methods as action_methods - ActiveScaffold::Actions::Nested::ChildMethods.public_instance_methods.each{|m| self.action_methods.add m } - end unless self.class.included_modules.include?(ActiveScaffold::Actions::Nested::ChildMethods) - else - # Production mode is caching this link into a non nested scaffold - active_scaffold_config.action_links.delete('new_existing') if active_scaffold_config.action_links['new_existing'] - - if active_scaffold_config.nested.shallow_delete - active_scaffold_config.action_links.delete("destroy_existing") if active_scaffold_config.action_links['destroy_existing'] - active_scaffold_config.action_links.add('destroy', :label => 'Delete', :type => :record, :confirm => 'Are you sure?', :method => :delete, :position => false, :security_method => :delete_existing_authorized?) unless active_scaffold_config.action_links['destroy'] - end - - end - end - - def nested? - !params[:nested].nil? - end - - def nested_habtm? - begin - a = active_scaffold_config.columns[nested_association] - return a.association.macro == :has_and_belongs_to_many if a and nested? - false - rescue - raise ActiveScaffold::MalformedConstraint, constraint_error(active_scaffold_config.model, nested_association), caller - end - end - - def nested_association - return active_scaffold_constraints.keys.to_s.to_sym if nested? - nil - end - - def nested_parent_id - return active_scaffold_constraints.values.to_s if nested? - nil - end - - end -end - -module ActiveScaffold::Actions::Nested - module ChildMethods - - def self.included(base) - super - # This .verify method call is clashing with other non .add_existing actions. How do we do this correctly? Can we make it action specific. - # base.verify :method => :post, - # :only => :add_existing, - # :redirect_to => { :action => :index } - end - - def new_existing - do_new - - respond_to do |type| - type.html do - if successful? - render(:action => 'add_existing_form', :layout => true) - else - return_to_main - end - end - type.js do - render(:partial => 'add_existing_form', :layout => false) - end - end - end - - def add_existing - do_add_existing - - respond_to do |type| - type.html do - if successful? - flash[:info] = as_('Created %s', @record.to_label) - return_to_main - else - render(:action => 'add_existing_form', :layout => true) - end - end - type.js do - if successful? - render :action => 'add_existing', :layout => false - else - render :action => 'form_messages.rjs', :layout => false - end - end - type.xml { render :xml => response_object.to_xml, :content_type => Mime::XML, :status => response_status } - type.json { render :text => response_object.to_json, :content_type => Mime::JSON, :status => response_status } - type.yaml { render :text => response_object.to_yaml, :content_type => Mime::YAML, :status => response_status } - end - end - - def destroy_existing - return redirect_to(params.merge(:action => :delete)) if request.get? - - do_destroy_existing - - respond_to do |type| - type.html do - flash[:info] = as_('Deleted %s', @record.to_label) - return_to_main - end - type.js { render(:action => 'destroy.rjs', :layout => false) } - type.xml { render :xml => successful? ? "" : response_object.to_xml, :content_type => Mime::XML, :status => response_status } - type.json { render :text => successful? ? "" : response_object.to_json, :content_type => Mime::JSON, :status => response_status } - type.yaml { render :text => successful? ? "" : response_object.to_yaml, :content_type => Mime::YAML, :status => response_status } - end - end - - protected - - def after_create_save(record) - if params[:association_macro] == :has_and_belongs_to_many - params[:associated_id] = record - do_add_existing - end - end - - def nested_action_from_params - return params[:parent_model].constantize, nested_parent_id, params[:parent_column] - end - - # The actual "add_existing" algorithm - def do_add_existing - parent_model, id, association = nested_action_from_params - parent_record = find_if_allowed(id, :update, parent_model) - @record = active_scaffold_config.model.find(params[:associated_id]) - parent_record.send(association) << @record - parent_record.save - end - - def do_destroy_existing - if active_scaffold_config.nested.shallow_delete - parent_model, id, association = nested_action_from_params - @record = find_if_allowed(id, :update, parent_model) - collection = @record.send(association) - assoc_record = collection.find(params[:id]) - collection.delete(assoc_record) - else - do_destroy - end - end - - end -end +module ActiveScaffold::Actions + # The Nested module basically handles automatically linking controllers together. It does this by creating column links with the right parameters, and by providing any supporting systems (like a /:controller/nested action for returning associated scaffolds). + module Nested + + def self.included(base) + super + base.before_filter :include_habtm_actions + # TODO: it's a bit wasteful to run this routine every page load. + base.before_filter :links_for_associations + end + + def nested + do_nested + + respond_to do |type| + type.html { render :partial => 'nested', :layout => true } + type.js { render :partial => 'nested', :layout => false } + end + end + + protected + + # A simple method to find the record we'll be nesting *from* + # May be overridden to customize the behavior + def do_nested + @record = find_if_allowed(params[:id], :read) + end + + # Create the automatic column links. Note that this has to happen when configuration is *done*, because otherwise the Nested module could be disabled. Actually, it could still be disabled later, couldn't it? + # TODO: This should really be a post-config routine, instead of a before_filter. + def links_for_associations + active_scaffold_config.list.columns.each do |column| + # if column.link == false we won't create a link. that's how a dev can suppress the auto links. + if column.association and column.link.nil? + if column.plural_association? + # note: we can't create nested scaffolds on :through associations because there's no reverse association. + column.set_link('nested', :parameters => {:associations => column.name.to_sym}) #unless column.through_association? + elsif not column.polymorphic_association? + model = column.association.klass + begin + controller = self.class.active_scaffold_controller_for(model) + rescue ActiveScaffold::ControllerNotFound + next + end + + actions = controller.active_scaffold_config.actions + action = nil + if actions.include? :update and model.authorized_for? :action => :update + action = 'edit' + elsif actions.include? :show and model.authorized_for? :action => :read + action = 'show' + end + column.set_link(action, :controller => controller.controller_path, :parameters => {:parent_controller => params[:controller]}) if action + end + end + end + end + + def include_habtm_actions + if nested_habtm? + # Production mode is ok with adding a link everytime the scaffold is nested - we ar not ok with that. + active_scaffold_config.action_links.add('new_existing', :label => 'Add Existing', :type => :table, :security_method => :add_existing_authorized?) unless active_scaffold_config.action_links['new_existing'] + if active_scaffold_config.nested.shallow_delete + active_scaffold_config.action_links.add('destroy_existing', :label => 'Remove', :type => :record, :confirm => 'Are you sure?', :method => :delete, :position => false, :security_method => :delete_existing_authorized?) unless active_scaffold_config.action_links['destroy_existing'] + active_scaffold_config.action_links.delete("destroy") if active_scaffold_config.action_links['destroy'] + end + + self.class.module_eval do + include ActiveScaffold::Actions::Nested::ChildMethods + # we need specifically to tell action_controller to add these public methods as action_methods + ActiveScaffold::Actions::Nested::ChildMethods.public_instance_methods.each{|m| self.action_methods.add m } + end unless self.class.included_modules.include?(ActiveScaffold::Actions::Nested::ChildMethods) + else + # Production mode is caching this link into a non nested scaffold + active_scaffold_config.action_links.delete('new_existing') if active_scaffold_config.action_links['new_existing'] + + if active_scaffold_config.nested.shallow_delete + active_scaffold_config.action_links.delete("destroy_existing") if active_scaffold_config.action_links['destroy_existing'] + active_scaffold_config.action_links.add('destroy', :label => 'Delete', :type => :record, :confirm => 'Are you sure?', :method => :delete, :position => false, :security_method => :delete_existing_authorized?) unless active_scaffold_config.action_links['destroy'] + end + + end + end + + def nested? + !params[:nested].nil? + end + + def nested_habtm? + begin + a = active_scaffold_config.columns[nested_association] + return a.association.macro == :has_and_belongs_to_many if a and nested? + false + rescue + raise ActiveScaffold::MalformedConstraint, constraint_error(active_scaffold_config.model, nested_association), caller + end + end + + def nested_association + return active_scaffold_constraints.keys.to_s.to_sym if nested? + nil + end + + def nested_parent_id + return active_scaffold_constraints.values.to_s if nested? + nil + end + + end +end + +module ActiveScaffold::Actions::Nested + module ChildMethods + + def self.included(base) + super + # This .verify method call is clashing with other non .add_existing actions. How do we do this correctly? Can we make it action specific. + # base.verify :method => :post, + # :only => :add_existing, + # :redirect_to => { :action => :index } + end + + def new_existing + do_new + + respond_to do |type| + type.html do + if successful? + render(:action => 'add_existing_form', :layout => true) + else + return_to_main + end + end + type.js do + render(:partial => 'add_existing_form', :layout => false) + end + end + end + + def add_existing + do_add_existing + + respond_to do |type| + type.html do + if successful? + flash[:info] = as_('Created %s', @record.to_label) + return_to_main + else + render(:action => 'add_existing_form', :layout => true) + end + end + type.js do + if successful? + render :action => 'add_existing', :layout => false + else + render :action => 'form_messages.rjs', :layout => false + end + end + type.xml { render :xml => response_object.to_xml, :content_type => Mime::XML, :status => response_status } + type.json { render :text => response_object.to_json, :content_type => Mime::JSON, :status => response_status } + type.yaml { render :text => response_object.to_yaml, :content_type => Mime::YAML, :status => response_status } + end + end + + def destroy_existing + return redirect_to(params.merge(:action => :delete)) if request.get? + + do_destroy_existing + + respond_to do |type| + type.html do + flash[:info] = as_('Deleted %s', @record.to_label) + return_to_main + end + type.js { render(:action => 'destroy.rjs', :layout => false) } + type.xml { render :xml => successful? ? "" : response_object.to_xml, :content_type => Mime::XML, :status => response_status } + type.json { render :text => successful? ? "" : response_object.to_json, :content_type => Mime::JSON, :status => response_status } + type.yaml { render :text => successful? ? "" : response_object.to_yaml, :content_type => Mime::YAML, :status => response_status } + end + end + + protected + + def after_create_save(record) + if params[:association_macro] == :has_and_belongs_to_many + params[:associated_id] = record + do_add_existing + end + end + + def nested_action_from_params + return params[:parent_model].constantize, nested_parent_id, params[:parent_column] + end + + # The actual "add_existing" algorithm + def do_add_existing + parent_model, id, association = nested_action_from_params + parent_record = find_if_allowed(id, :update, parent_model) + @record = active_scaffold_config.model.find(params[:associated_id]) + parent_record.send(association) << @record + parent_record.save + end + + def do_destroy_existing + if active_scaffold_config.nested.shallow_delete + parent_model, id, association = nested_action_from_params + @record = find_if_allowed(id, :update, parent_model) + collection = @record.send(association) + assoc_record = collection.find(params[:id]) + collection.delete(assoc_record) + else + do_destroy + end + end + + end +end diff --git a/lib/active_scaffold.rb b/lib/active_scaffold.rb index 467794e..144eebb 100644 --- a/lib/active_scaffold.rb +++ b/lib/active_scaffold.rb @@ -1,132 +1,132 @@ -module ActiveScaffold - def self.included(base) - base.extend(ClassMethods) - base.module_eval do - # TODO: these should be in actions/core - before_filter :handle_user_settings - end - end - - def self.set_defaults(&block) - ActiveScaffold::Config::Core.configure &block - end - - def active_scaffold_config - self.class.active_scaffold_config - end - - def active_scaffold_config_for(klass) - self.class.active_scaffold_config_for(klass) - end - - def active_scaffold_session_storage - id = params[:eid] || params[:controller] - session_index = "as:#{id}" - session[session_index] ||= {} - session[session_index] - end - - # at some point we need to pass the session and params into config. we'll just take care of that before any particular action occurs by passing those hashes off to the UserSettings class of each action. - def handle_user_settings - if self.class.uses_active_scaffold? - active_scaffold_config.actions.each do |action_name| - conf_instance = active_scaffold_config.send(action_name) rescue next - next if conf_instance.class::UserSettings == ActiveScaffold::Config::Base::UserSettings # if it hasn't been extended, skip it - active_scaffold_session_storage[action_name] ||= {} - conf_instance.user = conf_instance.class::UserSettings.new(conf_instance, active_scaffold_session_storage[action_name], params) - end - end - end - - module ClassMethods - def active_scaffold(model_id = nil, &block) - # initialize bridges here - ActiveScaffold::Bridge.run_all - - # converts Foo::BarController to 'bar' and FooBarsController to 'foo_bar' and AddressController to 'address' - model_id = self.to_s.split('::').last.sub(/Controller$/, '').pluralize.singularize.underscore unless model_id - - # run the configuration - @active_scaffold_config = ActiveScaffold::Config::Core.new(model_id) - self.active_scaffold_config.configure &block if block_given? - self.active_scaffold_config._load_action_columns - - # defines the attribute read methods on the model, so record.send() doesn't find protected/private methods instead - klass = self.active_scaffold_config.model - klass.define_attribute_methods unless klass.generated_methods? - - # set up the generic_view_paths (Rails 2.x) - frontends_path = File.join(Rails.root, 'vendor', 'plugins', ActiveScaffold::Config::Core.plugin_directory, 'frontends') - - paths = self.active_scaffold_config.inherited_view_paths.clone - ActionController::Base.view_paths.each do |dir| - paths << File.join(dir,"active_scaffold_overrides") if File.exists?(File.join(dir,"active_scaffold_overrides")) - end - paths << File.join(frontends_path, active_scaffold_config.frontend, 'views') if active_scaffold_config.frontend.to_sym != :default - paths << File.join(frontends_path, 'default', 'views') - self.generic_view_paths = paths - - # include the rest of the code into the controller: the action core and the included actions - module_eval do - include ActiveScaffold::Finder - include ActiveScaffold::Constraints - include ActiveScaffold::AttributeParams - include ActiveScaffold::Actions::Core - active_scaffold_config.actions.each do |mod| - name = mod.to_s.camelize - include eval("ActiveScaffold::Actions::#{name}") if ActiveScaffold::Actions.const_defined? name - - # sneak the action links from the actions into the main set - if link = active_scaffold_config.send(mod).link rescue nil - active_scaffold_config.action_links << link - end - end - end - end - - def active_scaffold_config - @active_scaffold_config || self.superclass.instance_variable_get('@active_scaffold_config') - end - - def active_scaffold_config_for(klass) - begin - controller = active_scaffold_controller_for(klass) - rescue ActiveScaffold::ControllerNotFound - config = ActiveScaffold::Config::Core.new(klass) - config._load_action_columns - config - else - controller.active_scaffold_config - end - end - - # Tries to find a controller for the given ActiveRecord model. - # Searches in the namespace of the current controller for singular and plural versions of the conventional "#{model}Controller" syntax. - # You may override this method to customize the search routine. - def active_scaffold_controller_for(klass) - namespace = self.to_s.split('::')[0...-1].join('::') + '::' - error_message = [] - ["#{klass.to_s.underscore.pluralize}", "#{klass.to_s.underscore.pluralize.singularize}"].each do |controller_name| - begin - controller = "#{namespace}#{controller_name.camelize}Controller".constantize - rescue NameError => error - # Only rescue NameError associated with the controller constant not existing - not other compile errors - if error.message["uninitialized constant #{controller}"] - error_message << "#{namespace}#{controller_name.camelize}Controller" - next - else - raise - end - end - raise ActiveScaffold::ControllerNotFound, "#{controller} missing ActiveScaffold", caller unless controller.uses_active_scaffold? - raise ActiveScaffold::ControllerNotFound, "ActiveScaffold on #{controller} is not for #{klass} model.", caller unless controller.active_scaffold_config.model == klass - return controller - end - raise ActiveScaffold::ControllerNotFound, "Could not find " + error_message.join(" or "), caller - end - - def uses_active_scaffold? - !active_scaffold_config.nil? - end - end -end +module ActiveScaffold + def self.included(base) + base.extend(ClassMethods) + base.module_eval do + # TODO: these should be in actions/core + before_filter :handle_user_settings + end + end + + def self.set_defaults(&block) + ActiveScaffold::Config::Core.configure &block + end + + def active_scaffold_config + self.class.active_scaffold_config + end + + def active_scaffold_config_for(klass) + self.class.active_scaffold_config_for(klass) + end + + def active_scaffold_session_storage + id = params[:eid] || params[:controller] + session_index = "as:#{id}" + session[session_index] ||= {} + session[session_index] + end + + # at some point we need to pass the session and params into config. we'll just take care of that before any particular action occurs by passing those hashes off to the UserSettings class of each action. + def handle_user_settings + if self.class.uses_active_scaffold? + active_scaffold_config.actions.each do |action_name| + conf_instance = active_scaffold_config.send(action_name) rescue next + next if conf_instance.class::UserSettings == ActiveScaffold::Config::Base::UserSettings # if it hasn't been extended, skip it + active_scaffold_session_storage[action_name] ||= {} + conf_instance.user = conf_instance.class::UserSettings.new(conf_instance, active_scaffold_session_storage[action_name], params) + end + end + end + + module ClassMethods + def active_scaffold(model_id = nil, &block) + # initialize bridges here + ActiveScaffold::Bridge.run_all + + # converts Foo::BarController to 'bar' and FooBarsController to 'foo_bar' and AddressController to 'address' + model_id = self.to_s.split('::').last.sub(/Controller$/, '').pluralize.singularize.underscore unless model_id + + # run the configuration + @active_scaffold_config = ActiveScaffold::Config::Core.new(model_id) + self.active_scaffold_config.configure &block if block_given? + self.active_scaffold_config._load_action_columns + + # defines the attribute read methods on the model, so record.send() doesn't find protected/private methods instead + klass = self.active_scaffold_config.model + klass.define_attribute_methods unless klass.generated_methods? + + # set up the generic_view_paths (Rails 2.x) + frontends_path = File.join(Rails.root, 'vendor', 'plugins', ActiveScaffold::Config::Core.plugin_directory, 'frontends') + + paths = self.active_scaffold_config.inherited_view_paths.clone + ActionController::Base.view_paths.each do |dir| + paths << File.join(dir,"active_scaffold_overrides") if File.exists?(File.join(dir,"active_scaffold_overrides")) + end + paths << File.join(frontends_path, active_scaffold_config.frontend, 'views') if active_scaffold_config.frontend.to_sym != :default + paths << File.join(frontends_path, 'default', 'views') + self.generic_view_paths = paths + + # include the rest of the code into the controller: the action core and the included actions + module_eval do + include ActiveScaffold::Finder + include ActiveScaffold::Constraints + include ActiveScaffold::AttributeParams + include ActiveScaffold::Actions::Core + active_scaffold_config.actions.each do |mod| + name = mod.to_s.camelize + include eval("ActiveScaffold::Actions::#{name}") if ActiveScaffold::Actions.const_defined? name + + # sneak the action links from the actions into the main set + if link = active_scaffold_config.send(mod).link rescue nil + active_scaffold_config.action_links << link + end + end + end + end + + def active_scaffold_config + @active_scaffold_config || self.superclass.instance_variable_get('@active_scaffold_config') + end + + def active_scaffold_config_for(klass) + begin + controller = active_scaffold_controller_for(klass) + rescue ActiveScaffold::ControllerNotFound + config = ActiveScaffold::Config::Core.new(klass) + config._load_action_columns + config + else + controller.active_scaffold_config + end + end + + # Tries to find a controller for the given ActiveRecord model. + # Searches in the namespace of the current controller for singular and plural versions of the conventional "#{model}Controller" syntax. + # You may override this method to customize the search routine. + def active_scaffold_controller_for(klass) + namespace = self.to_s.split('::')[0...-1].join('::') + '::' + error_message = [] + ["#{klass.to_s.underscore.pluralize}", "#{klass.to_s.underscore.pluralize.singularize}"].each do |controller_name| + begin + controller = "#{namespace}#{controller_name.camelize}Controller".constantize + rescue NameError => error + # Only rescue NameError associated with the controller constant not existing - not other compile errors + if error.message["uninitialized constant #{controller}"] + error_message << "#{namespace}#{controller_name.camelize}Controller" + next + else + raise + end + end + raise ActiveScaffold::ControllerNotFound, "#{controller} missing ActiveScaffold", caller unless controller.uses_active_scaffold? + raise ActiveScaffold::ControllerNotFound, "ActiveScaffold on #{controller} is not for #{klass} model.", caller unless controller.active_scaffold_config.model == klass + return controller + end + raise ActiveScaffold::ControllerNotFound, "Could not find " + error_message.join(" or "), caller + end + + def uses_active_scaffold? + !active_scaffold_config.nil? + end + end +end diff --git a/lib/bridges/calendar_date_select/lib/as_cds_bridge.rb b/lib/bridges/calendar_date_select/lib/as_cds_bridge.rb index d6af447..a3b3407 100644 --- a/lib/bridges/calendar_date_select/lib/as_cds_bridge.rb +++ b/lib/bridges/calendar_date_select/lib/as_cds_bridge.rb @@ -1,53 +1,53 @@ -module ActiveScaffold::Config - class Core < Base - - def initialize_with_calendar_date_select(model_id) - initialize_without_calendar_date_select(model_id) - - calendar_date_select_fields = self.model.columns.collect{|c| c.name.to_sym if [:date, :datetime].include?(c.type) }.compact - # check to see if file column was used on the model - return if calendar_date_select_fields.empty? - - # automatically set the forum_ui to a file column - calendar_date_select_fields.each{|field| - self.columns[field].form_ui = :calendar_date_select - } - end - - alias_method_chain :initialize, :calendar_date_select - - end -end - - -module ActiveScaffold - module Helpers - # Helpers that assist with the rendering of a Form Column - module FormColumns - def active_scaffold_input_calendar_date_select(column, options) - options[:class] = "#{options[:class]} text-input".strip - calendar_date_select("record", column.name, options) - end - end - end -end - -module ActiveScaffold - module Helpers - module ViewHelpers - - # Provides stylesheets to include with +stylesheet_link_tag+ - def active_scaffold_stylesheets_with_calendar_date_select(frontend = :default) - active_scaffold_stylesheets_without_calendar_date_select.to_a << calendar_date_select_stylesheets - end - alias_method_chain :active_scaffold_stylesheets, :calendar_date_select - - # Provides stylesheets to include with +stylesheet_link_tag+ - def active_scaffold_javascripts_with_calendar_date_select(frontend = :default) - active_scaffold_javascripts_without_calendar_date_select.to_a << calendar_date_select_javascripts - end - alias_method_chain :active_scaffold_javascripts, :calendar_date_select - - end - end -end +module ActiveScaffold::Config + class Core < Base + + def initialize_with_calendar_date_select(model_id) + initialize_without_calendar_date_select(model_id) + + calendar_date_select_fields = self.model.columns.collect{|c| c.name.to_sym if [:date, :datetime].include?(c.type) }.compact + # check to see if file column was used on the model + return if calendar_date_select_fields.empty? + + # automatically set the forum_ui to a file column + calendar_date_select_fields.each{|field| + self.columns[field].form_ui = :calendar_date_select + } + end + + alias_method_chain :initialize, :calendar_date_select + + end +end + + +module ActiveScaffold + module Helpers + # Helpers that assist with the rendering of a Form Column + module FormColumns + def active_scaffold_input_calendar_date_select(column, options) + options[:class] = "#{options[:class]} text-input".strip + calendar_date_select("record", column.name, options) + end + end + end +end + +module ActiveScaffold + module Helpers + module ViewHelpers + + # Provides stylesheets to include with +stylesheet_link_tag+ + def active_scaffold_stylesheets_with_calendar_date_select(frontend = :default) + active_scaffold_stylesheets_without_calendar_date_select.to_a << calendar_date_select_stylesheets + end + alias_method_chain :active_scaffold_stylesheets, :calendar_date_select + + # Provides stylesheets to include with +stylesheet_link_tag+ + def active_scaffold_javascripts_with_calendar_date_select(frontend = :default) + active_scaffold_javascripts_without_calendar_date_select.to_a << calendar_date_select_javascripts + end + alias_method_chain :active_scaffold_javascripts, :calendar_date_select + + end + end +end diff --git a/lib/bridges/file_column/lib/as_file_column_bridge.rb b/lib/bridges/file_column/lib/as_file_column_bridge.rb index e6855fc..1fc555c 100644 --- a/lib/bridges/file_column/lib/as_file_column_bridge.rb +++ b/lib/bridges/file_column/lib/as_file_column_bridge.rb @@ -1,48 +1,48 @@ -module ActiveScaffold::DataStructures - class Column - attr_accessor :file_column_display - end -end - -module ActiveScaffold::Config - class Core < Base - attr_accessor :file_column_fields - def initialize_with_file_column(model_id) - initialize_without_file_column(model_id) - - return unless FileColumnHelpers.klass_has_file_column_fields?(self.model) - - self.model.send :extend, FileColumnHelpers - - # include the "delete" helpers for use with active scaffold, unless they are already included - self.model.generate_delete_helpers - - # switch on multipart - self.update.multipart = true - self.create.multipart = true - - self.model.file_column_fields.each{ |field| - configure_file_column_field(field) - } - end - - alias_method_chain :initialize, :file_column unless self.instance_methods.include?("initialize_without_file_column") - - def configure_file_column_field(field) - # set list_ui first because it gets its default value from form_ui - self.columns[field].list_ui ||= self.model.field_has_image_version?(field, "thumb") ? :thumbnail : :download_link_with_filename - self.columns[field].form_ui ||= :file_column - - # these 2 parameters are necessary helper attributes for the file column that must be allowed to be set to the model by active scaffold. - self.columns[field].params.add "#{field}_temp", "delete_#{field}" - - # set null to false so active_scaffold wont set it to null - # delete_file_column will take care of deleting a file or not. - self.model.columns_hash[field.to_s].instance_variable_set("@null", false) - - rescue - false - end - - end +module ActiveScaffold::DataStructures + class Column + attr_accessor :file_column_display + end +end + +module ActiveScaffold::Config + class Core < Base + attr_accessor :file_column_fields + def initialize_with_file_column(model_id) + initialize_without_file_column(model_id) + + return unless FileColumnHelpers.klass_has_file_column_fields?(self.model) + + self.model.send :extend, FileColumnHelpers + + # include the "delete" helpers for use with active scaffold, unless they are already included + self.model.generate_delete_helpers + + # switch on multipart + self.update.multipart = true + self.create.multipart = true + + self.model.file_column_fields.each{ |field| + configure_file_column_field(field) + } + end + + alias_method_chain :initialize, :file_column unless self.instance_methods.include?("initialize_without_file_column") + + def configure_file_column_field(field) + # set list_ui first because it gets its default value from form_ui + self.columns[field].list_ui ||= self.model.field_has_image_version?(field, "thumb") ? :thumbnail : :download_link_with_filename + self.columns[field].form_ui ||= :file_column + + # these 2 parameters are necessary helper attributes for the file column that must be allowed to be set to the model by active scaffold. + self.columns[field].params.add "#{field}_temp", "delete_#{field}" + + # set null to false so active_scaffold wont set it to null + # delete_file_column will take care of deleting a file or not. + self.model.columns_hash[field.to_s].instance_variable_set("@null", false) + + rescue + false + end + + end end \ No newline at end of file diff --git a/lib/bridges/file_column/test/functional/file_column_keep_test.rb b/lib/bridges/file_column/test/functional/file_column_keep_test.rb index 5729589..fa2aeec 100644 --- a/lib/bridges/file_column/test/functional/file_column_keep_test.rb +++ b/lib/bridges/file_column/test/functional/file_column_keep_test.rb @@ -1,43 +1,43 @@ -require File.join(File.dirname(__FILE__), "../test_helper.rb") - -class DeleteFileColumnTest < Test::Unit::TestCase - def setup - DeleteFileColumn.generate_delete_helpers(MockModel) - @model = MockModel.new - @model.band_image = "coolio.jpg" - end - - def test__file_column_fields - assert_equal(1, @model.file_column_fields.length) - end - - def test__delete_band_image__boolean__should_delete - @model.delete_band_image = true - assert_nil @model.band_image - end - - def test__delete_band_image__string__should_delete - @model.delete_band_image = "true" - assert_nil @model.band_image - end - - - def test__delete_band_image__boolean_false__shouldnt_delete - @model.delete_band_image = false - assert_not_nil @model.band_image - end - - def test__delete_band_image__string_false__shouldnt_delete - @model.delete_band_image = "false" - assert_not_nil @model.band_image - end - - - def test__just_uploaded__shouldnt_delete - @model.band_image_just_uploaded = true - @model.delete_band_image = "true" - assert_not_nil(@model.band_image) - end - - +require File.join(File.dirname(__FILE__), "../test_helper.rb") + +class DeleteFileColumnTest < Test::Unit::TestCase + def setup + DeleteFileColumn.generate_delete_helpers(MockModel) + @model = MockModel.new + @model.band_image = "coolio.jpg" + end + + def test__file_column_fields + assert_equal(1, @model.file_column_fields.length) + end + + def test__delete_band_image__boolean__should_delete + @model.delete_band_image = true + assert_nil @model.band_image + end + + def test__delete_band_image__string__should_delete + @model.delete_band_image = "true" + assert_nil @model.band_image + end + + + def test__delete_band_image__boolean_false__shouldnt_delete + @model.delete_band_image = false + assert_not_nil @model.band_image + end + + def test__delete_band_image__string_false__shouldnt_delete + @model.delete_band_image = "false" + assert_not_nil @model.band_image + end + + + def test__just_uploaded__shouldnt_delete + @model.band_image_just_uploaded = true + @model.delete_band_image = "true" + assert_not_nil(@model.band_image) + end + + end \ No newline at end of file diff --git a/lib/bridges/file_column/test/mock_model.rb b/lib/bridges/file_column/test/mock_model.rb index 63131ee..90fa827 100644 --- a/lib/bridges/file_column/test/mock_model.rb +++ b/lib/bridges/file_column/test/mock_model.rb @@ -1,9 +1,9 @@ -class MockModel - attr_accessor :name - attr_accessor :bio - - attr_accessor :band_image - attr_accessor :band_image_just_uploaded - def band_image_just_uploaded?; self.band_image_just_uploaded ? true : false; end - +class MockModel + attr_accessor :name + attr_accessor :bio + + attr_accessor :band_image + attr_accessor :band_image_just_uploaded + def band_image_just_uploaded?; self.band_image_just_uploaded ? true : false; end + end \ No newline at end of file diff --git a/lib/bridges/file_column/test/test_helper.rb b/lib/bridges/file_column/test/test_helper.rb index e3dcfe6..8d94577 100644 --- a/lib/bridges/file_column/test/test_helper.rb +++ b/lib/bridges/file_column/test/test_helper.rb @@ -1,15 +1,15 @@ -require 'test/unit' -require "rubygems" -require 'active_support' - -for file in ["../lib/delete_file_column.rb", "mock_model.rb"] - require File.expand_path(File.join(File.dirname(__FILE__), file)) -end - - - -def dbg - require 'ruby-debug' - Debugger.start - debugger -end +require 'test/unit' +require "rubygems" +require 'active_support' + +for file in ["../lib/delete_file_column.rb", "mock_model.rb"] + require File.expand_path(File.join(File.dirname(__FILE__), file)) +end + + + +def dbg + require 'ruby-debug' + Debugger.start + debugger +end diff --git a/lib/extensions/reverse_associations.rb b/lib/extensions/reverse_associations.rb index 4efd577..a82a484 100644 --- a/lib/extensions/reverse_associations.rb +++ b/lib/extensions/reverse_associations.rb @@ -1,56 +1,56 @@ -module ActiveRecord - module Reflection - class AssociationReflection #:nodoc: - def reverse_for?(klass) - reverse_matches_for(klass).empty? ? false : true - end - - attr_writer :reverse - def reverse - unless @reverse - reverse_matches = reverse_matches_for(self.class_name.constantize) - # grab first association, or make a wild guess - @reverse = reverse_matches.empty? ? self.active_record.to_s.pluralize.underscore : reverse_matches.first.name - end - @reverse - end - - protected - - def reverse_matches_for(klass) - reverse_matches = [] - - # stage 1 filter: collect associations that point back to this model and use the same primary_key_name - klass.reflect_on_all_associations.each do |assoc| - # skip over has_many :through associations - next if assoc.options[:through] - - next unless assoc.options[:polymorphic] or assoc.class_name.constantize == self.active_record - case [assoc.macro, self.macro].find_all{|m| m == :has_and_belongs_to_many}.length - # if both are a habtm, then match them based on the join table - when 2 - next unless assoc.options[:join_table] == self.options[:join_table] - - # if only one is a habtm, they do not match - when 1 - next - - # otherwise, match them based on the primary_key_name - when 0 - next unless assoc.primary_key_name.to_sym == self.primary_key_name.to_sym - end - - reverse_matches << assoc - end - - # stage 2 filter: name-based matching (association name vs self.active_record.to_s) - reverse_matches.find_all do |assoc| - self.active_record.to_s.underscore.include? assoc.name.to_s.pluralize.singularize - end if reverse_matches.length > 1 - - reverse_matches - end - - end - end +module ActiveRecord + module Reflection + class AssociationReflection #:nodoc: + def reverse_for?(klass) + reverse_matches_for(klass).empty? ? false : true + end + + attr_writer :reverse + def reverse + unless @reverse + reverse_matches = reverse_matches_for(self.class_name.constantize) + # grab first association, or make a wild guess + @reverse = reverse_matches.empty? ? self.active_record.to_s.pluralize.underscore : reverse_matches.first.name + end + @reverse + end + + protected + + def reverse_matches_for(klass) + reverse_matches = [] + + # stage 1 filter: collect associations that point back to this model and use the same primary_key_name + klass.reflect_on_all_associations.each do |assoc| + # skip over has_many :through associations + next if assoc.options[:through] + + next unless assoc.options[:polymorphic] or assoc.class_name.constantize == self.active_record + case [assoc.macro, self.macro].find_all{|m| m == :has_and_belongs_to_many}.length + # if both are a habtm, then match them based on the join table + when 2 + next unless assoc.options[:join_table] == self.options[:join_table] + + # if only one is a habtm, they do not match + when 1 + next + + # otherwise, match them based on the primary_key_name + when 0 + next unless assoc.primary_key_name.to_sym == self.primary_key_name.to_sym + end + + reverse_matches << assoc + end + + # stage 2 filter: name-based matching (association name vs self.active_record.to_s) + reverse_matches.find_all do |assoc| + self.active_record.to_s.underscore.include? assoc.name.to_s.pluralize.singularize + end if reverse_matches.length > 1 + + reverse_matches + end + + end + end end \ No newline at end of file diff --git a/lib/helpers/id_helpers.rb b/lib/helpers/id_helpers.rb index 26f27e0..d667686 100644 --- a/lib/helpers/id_helpers.rb +++ b/lib/helpers/id_helpers.rb @@ -1,125 +1,125 @@ -module ActiveScaffold - module Helpers - # A bunch of helper methods to produce the common view ids - module Ids - def controller_id - @controller_id ||= (params[:parent_controller] || params[:eid] || params[:controller]).gsub("/", "__") - end - - def active_scaffold_id - "#{controller_id}-active-scaffold" - end - - def active_scaffold_content_id - "#{controller_id}-content" - end - - def active_scaffold_tbody_id - "#{controller_id}-tbody" - end - - def active_scaffold_messages_id - "#{controller_id}-messages" - end - - def active_scaffold_calculations_id - "#{controller_id}-calculations" - end - - def empty_message_id - "#{controller_id}-empty-message" - end - - def before_header_id - "#{controller_id}-search-container" - end - - def search_form_id - "#{controller_id}-search-form" - end - - def search_input_id - "#{controller_id}-search-input" - end - - def table_action_id(name) - "#{controller_id}-action-table-#{name}" - end - - def action_link_id(link_action,link_id) - "#{controller_id}-#{link_action}-#{link_id}-link" - end - - def active_scaffold_column_header_id(column) - name = column.respond_to?(:name) ? column.name : column.to_s - clean_id "#{controller_id}-#{name}-column" - end - - def element_row_id(options = {}) - options[:action] ||= params[:action] - options[:id] ||= params[:id] - options[:id] ||= params[:parent_id] - clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-row" - end - - def element_cell_id(options = {}) - options[:action] ||= params[:action] - options[:id] ||= params[:id] - options[:id] ||= params[:parent_id] - options[:name] ||= params[:name] - clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-#{options[:name]}-cell" - end - - def element_form_id(options = {}) - options[:action] ||= params[:action] - options[:id] ||= params[:id] - options[:id] ||= params[:parent_id] - clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-form" - end - - def association_subform_id(column) - klass = column.association.klass.to_s.underscore - clean_id "#{controller_id}-associated-#{klass}" - end - - def loading_indicator_id(options = {}) - options[:action] ||= params[:action] - unless options[:id] - clean_id "#{controller_id}-#{options[:action]}-loading-indicator" - else - clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-loading-indicator" - end - end - - def sub_form_id(options = {}) - options[:id] ||= params[:id] - options[:id] ||= params[:parent_id] - clean_id "#{controller_id}-#{options[:id]}-#{options[:association]}-subform" - end - - def sub_form_list_id(options = {}) - options[:id] ||= params[:id] - options[:id] ||= params[:parent_id] - clean_id "#{controller_id}-#{options[:id]}-#{options[:association]}-subform-list" - end - - def element_messages_id(options = {}) - options[:action] ||= params[:action] - options[:id] ||= params[:id] - options[:id] ||= params[:parent_id] - clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-messages" - end - - def action_iframe_id(options) - "#{controller_id}-#{options[:action]}-#{options[:id]}-iframe" - end - - private - - # whitelists id-safe characters - def clean_id(val) - val.gsub /[^-_0-9a-zA-Z]/, '-' - end - end - end -end +module ActiveScaffold + module Helpers + # A bunch of helper methods to produce the common view ids + module Ids + def controller_id + @controller_id ||= (params[:parent_controller] || params[:eid] || params[:controller]).gsub("/", "__") + end + + def active_scaffold_id + "#{controller_id}-active-scaffold" + end + + def active_scaffold_content_id + "#{controller_id}-content" + end + + def active_scaffold_tbody_id + "#{controller_id}-tbody" + end + + def active_scaffold_messages_id + "#{controller_id}-messages" + end + + def active_scaffold_calculations_id + "#{controller_id}-calculations" + end + + def empty_message_id + "#{controller_id}-empty-message" + end + + def before_header_id + "#{controller_id}-search-container" + end + + def search_form_id + "#{controller_id}-search-form" + end + + def search_input_id + "#{controller_id}-search-input" + end + + def table_action_id(name) + "#{controller_id}-action-table-#{name}" + end + + def action_link_id(link_action,link_id) + "#{controller_id}-#{link_action}-#{link_id}-link" + end + + def active_scaffold_column_header_id(column) + name = column.respond_to?(:name) ? column.name : column.to_s + clean_id "#{controller_id}-#{name}-column" + end + + def element_row_id(options = {}) + options[:action] ||= params[:action] + options[:id] ||= params[:id] + options[:id] ||= params[:parent_id] + clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-row" + end + + def element_cell_id(options = {}) + options[:action] ||= params[:action] + options[:id] ||= params[:id] + options[:id] ||= params[:parent_id] + options[:name] ||= params[:name] + clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-#{options[:name]}-cell" + end + + def element_form_id(options = {}) + options[:action] ||= params[:action] + options[:id] ||= params[:id] + options[:id] ||= params[:parent_id] + clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-form" + end + + def association_subform_id(column) + klass = column.association.klass.to_s.underscore + clean_id "#{controller_id}-associated-#{klass}" + end + + def loading_indicator_id(options = {}) + options[:action] ||= params[:action] + unless options[:id] + clean_id "#{controller_id}-#{options[:action]}-loading-indicator" + else + clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-loading-indicator" + end + end + + def sub_form_id(options = {}) + options[:id] ||= params[:id] + options[:id] ||= params[:parent_id] + clean_id "#{controller_id}-#{options[:id]}-#{options[:association]}-subform" + end + + def sub_form_list_id(options = {}) + options[:id] ||= params[:id] + options[:id] ||= params[:parent_id] + clean_id "#{controller_id}-#{options[:id]}-#{options[:association]}-subform-list" + end + + def element_messages_id(options = {}) + options[:action] ||= params[:action] + options[:id] ||= params[:id] + options[:id] ||= params[:parent_id] + clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-messages" + end + + def action_iframe_id(options) + "#{controller_id}-#{options[:action]}-#{options[:id]}-iframe" + end + + private + + # whitelists id-safe characters + def clean_id(val) + val.gsub /[^-_0-9a-zA-Z]/, '-' + end + end + end +end diff --git a/lib/helpers/view_helpers.rb b/lib/helpers/view_helpers.rb index d7ad2a3..8c2f44e 100755 --- a/lib/helpers/view_helpers.rb +++ b/lib/helpers/view_helpers.rb @@ -1,206 +1,206 @@ -module ActiveScaffold - module Helpers - # All extra helpers that should be included in the View. - # Also a dumping ground for uncategorized helpers. - module ViewHelpers - include ActiveScaffold::Helpers::Ids - include ActiveScaffold::Helpers::Associations - include ActiveScaffold::Helpers::Pagination - include ActiveScaffold::Helpers::ListColumns - include ActiveScaffold::Helpers::FormColumns - - ## - ## Delegates - ## - - # access to the configuration variable - def active_scaffold_config - @controller.class.active_scaffold_config - end - - def active_scaffold_config_for(*args) - @controller.class.active_scaffold_config_for(*args) - end - - def active_scaffold_controller_for(*args) - @controller.class.active_scaffold_controller_for(*args) - end - - ## - ## Uncategorized - ## - - def generate_temporary_id - (Time.now.to_f*1000).to_i.to_s - end - - # Turns [[label, value]] into " : "" - end - end - - # Should this column be displayed in the subform? - def in_subform?(column, parent_record) - return true unless column.association - - # Polymorphic associations can't appear because they *might* be the reverse association, and because you generally don't assign an association from the polymorphic side ... I think. - return false if column.polymorphic_association? - - # We don't have the UI to currently handle habtm in subforms - return false if column.association.macro == :has_and_belongs_to_many - - # A column shouldn't be in the subform if it's the reverse association to the parent - return false if column.association.reverse_for?(parent_record.class) - #return false if column.association.klass == parent_record.class - - return true - end - - def form_remote_upload_tag(url_for_options = {}, options = {}) - onsubmits = options[:onsubmit] ? [ options[:onsubmit] ] : [ ] - # simulate a "loading". the setTimeout prevents the Form.disable from being called before the submit, so that data actually posts. - onsubmits << "setTimeout(function() { #{options[:loading]} }, 10); " - onsubmits << "return true" # make sure the form still submits - - options[:onsubmit] = onsubmits * ';' - options[:target] = action_iframe_id(url_for_options) - options[:multipart] = true - - output="" - output << "" - output << form_tag(url_for_options, options) - end - - # Provides list of javascripts to include with +javascript_include_tag+ - # You can use this with your javascripts like - # <%= javascript_include_tag :defaults, 'your_own_cool_script', active_scaffold_javascripts, :cache => true %> - def active_scaffold_javascripts(frontend = :default) - ActiveScaffold::Config::Core.javascripts(frontend).collect do |name| - ActiveScaffold::Config::Core.asset_path(name, frontend) - end - end - - # Provides stylesheets to include with +stylesheet_link_tag+ - def active_scaffold_stylesheets(frontend = :default) - ActiveScaffold::Config::Core.asset_path("stylesheet.css", frontend) - end - - # Provides stylesheets for IE to include with +stylesheet_link_tag+ - def active_scaffold_ie_stylesheets(frontend = :default) - ActiveScaffold::Config::Core.asset_path("stylesheet-ie.css", frontend) - end - - # easy way to include ActiveScaffold assets - def active_scaffold_includes(frontend = :default) - js = javascript_include_tag(*active_scaffold_javascripts(frontend)) - - css = stylesheet_link_tag(*active_scaffold_stylesheets(frontend)) - ie_css = stylesheet_link_tag(*active_scaffold_ie_stylesheets(frontend)) - - js + "\n" + css + "\n\n" - end - - # a general-use loading indicator (the "stuff is happening, please wait" feedback) - def loading_indicator_tag(options) - image_tag "/images/active_scaffold/default/indicator.gif", :style => "visibility:hidden;", :id => loading_indicator_id(options), :alt => "loading indicator", :class => "loading-indicator" - end - - def params_for(options = {}) - # :adapter and :position are one-use rendering arguments. they should not propagate. - # :sort, :sort_direction, and :page are arguments that stored in the session. they need not propagate. - # and wow. no we don't want to propagate :record. - # :commit is a special rails variable for form buttons - blacklist = [:adapter, :position, :sort, :sort_direction, :page, :record, :commit, :_method] - unless @params_for - @params_for = params.clone.delete_if { |key, value| blacklist.include? key.to_sym if key } - @params_for[:controller] = '/' + @params_for[:controller] unless @params_for[:controller].first(1) == '/' # for namespaced controllers - @params_for.delete(:id) if @params_for[:id].nil? - end - @params_for.merge(options) - end - - # Creates a javascript-based link that toggles the visibility of some element on the page. - # By default, it toggles the visibility of the sibling after the one it's nested in. You may pass custom javascript logic in options[:of] to change that, though. For example, you could say :of => '$("my_div_id")'. - # You may also flag whether the other element is visible by default or not, and the initial text will adjust accordingly. - def link_to_visibility_toggle(options = {}) - options[:of] ||= '$(this.parentNode).next()' - options[:default_visible] = true if options[:default_visible].nil? - - link_text = options[:default_visible] ? 'hide' : 'show' - link_to_function as_(link_text), "e = #{options[:of]}; e.toggle(); this.innerHTML = (e.style.display == 'none') ? '#{as_('show')}' : '#{as_('hide')}'", :class => 'visibility-toggle' - end - - def render_action_link(link, url_options) - url_options = url_options.clone - url_options[:action] = link.action - url_options[:controller] = link.controller if link.controller - url_options.delete(:search) if link.controller and link.controller.to_s != params[:controller] - url_options.merge! link.parameters if link.parameters - - html_options = link.html_options.merge({:class => link.action}) - if link.inline? - # NOTE this is in url_options instead of html_options on purpose. the reason is that the client-side - # action link javascript needs to submit the proper method, but the normal html_options[:method] - # argument leaves no way to extract the proper method from the rendered tag. - url_options[:_method] = link.method - - if link.method != :get and respond_to?(:protect_against_forgery?) and protect_against_forgery? - url_options[:authenticity_token] = form_authenticity_token - end - - # robd: protect against submitting get links as forms, since this causes annoying - # 'Do you wish to resubmit your form?' messages whenever you go back and forwards. - elsif link.method != :get - # Needs to be in html_options to as the adding _method to the url is no longer supported by Rails - html_options[:method] = link.method - end - - html_options[:confirm] = link.confirm if link.confirm? - html_options[:position] = link.position if link.position and link.inline? - html_options[:class] += ' action' if link.inline? - html_options[:popup] = true if link.popup? - html_options[:id] = action_link_id(url_options[:action],url_options[:id] || url_options[:parent_id]) - - if link.dhtml_confirm? - html_options[:class] += ' action' if !link.inline? - html_options[:page_link] = 'true' if !link.inline? - html_options[:dhtml_confirm] = link.dhtml_confirm.value - html_options[:onclick] = link.dhtml_confirm.onclick_function(controller,action_link_id(url_options[:action],url_options[:id] || url_options[:parent_id])) - end - html_options[:class] += " #{link.html_options[:class]}" unless link.html_options[:class].blank? - - # issue 260, use url_options[:link] if it exists. This prevents DB data from being localized. - label = url_options.delete(:link) || link.label - link_to label, url_options, html_options - end - - def column_class(column, column_value) - classes = [] - classes << "#{column.name}-column" - classes << column.css_class unless column.css_class.nil? - classes << 'empty' if column_empty? column_value - classes << 'sorted' if active_scaffold_config.list.user.sorting.sorts_on?(column) - classes << 'numeric' if column.column and [:decimal, :float, :integer].include?(column.column.type) - classes.join(' ') - end - - def column_empty?(column_value) - empty = column_value.nil? - empty ||= column_value.empty? if column_value.respond_to? :empty? - empty ||= (column_value == ' ') - empty ||= (column_value == active_scaffold_config.list.empty_field_text) - return empty - end - - def column_calculation(column) - calculation = active_scaffold_config.model.calculate(column.calculate, column.name, :conditions => controller.send(:all_conditions), - :joins => controller.send(:joins_for_collection), :include => controller.send(:active_scaffold_joins)) - end - end - end -end +module ActiveScaffold + module Helpers + # All extra helpers that should be included in the View. + # Also a dumping ground for uncategorized helpers. + module ViewHelpers + include ActiveScaffold::Helpers::Ids + include ActiveScaffold::Helpers::Associations + include ActiveScaffold::Helpers::Pagination + include ActiveScaffold::Helpers::ListColumns + include ActiveScaffold::Helpers::FormColumns + + ## + ## Delegates + ## + + # access to the configuration variable + def active_scaffold_config + @controller.class.active_scaffold_config + end + + def active_scaffold_config_for(*args) + @controller.class.active_scaffold_config_for(*args) + end + + def active_scaffold_controller_for(*args) + @controller.class.active_scaffold_controller_for(*args) + end + + ## + ## Uncategorized + ## + + def generate_temporary_id + (Time.now.to_f*1000).to_i.to_s + end + + # Turns [[label, value]] into " : "" + end + end + + # Should this column be displayed in the subform? + def in_subform?(column, parent_record) + return true unless column.association + + # Polymorphic associations can't appear because they *might* be the reverse association, and because you generally don't assign an association from the polymorphic side ... I think. + return false if column.polymorphic_association? + + # We don't have the UI to currently handle habtm in subforms + return false if column.association.macro == :has_and_belongs_to_many + + # A column shouldn't be in the subform if it's the reverse association to the parent + return false if column.association.reverse_for?(parent_record.class) + #return false if column.association.klass == parent_record.class + + return true + end + + def form_remote_upload_tag(url_for_options = {}, options = {}) + onsubmits = options[:onsubmit] ? [ options[:onsubmit] ] : [ ] + # simulate a "loading". the setTimeout prevents the Form.disable from being called before the submit, so that data actually posts. + onsubmits << "setTimeout(function() { #{options[:loading]} }, 10); " + onsubmits << "return true" # make sure the form still submits + + options[:onsubmit] = onsubmits * ';' + options[:target] = action_iframe_id(url_for_options) + options[:multipart] = true + + output="" + output << "" + output << form_tag(url_for_options, options) + end + + # Provides list of javascripts to include with +javascript_include_tag+ + # You can use this with your javascripts like + # <%= javascript_include_tag :defaults, 'your_own_cool_script', active_scaffold_javascripts, :cache => true %> + def active_scaffold_javascripts(frontend = :default) + ActiveScaffold::Config::Core.javascripts(frontend).collect do |name| + ActiveScaffold::Config::Core.asset_path(name, frontend) + end + end + + # Provides stylesheets to include with +stylesheet_link_tag+ + def active_scaffold_stylesheets(frontend = :default) + ActiveScaffold::Config::Core.asset_path("stylesheet.css", frontend) + end + + # Provides stylesheets for IE to include with +stylesheet_link_tag+ + def active_scaffold_ie_stylesheets(frontend = :default) + ActiveScaffold::Config::Core.asset_path("stylesheet-ie.css", frontend) + end + + # easy way to include ActiveScaffold assets + def active_scaffold_includes(frontend = :default) + js = javascript_include_tag(*active_scaffold_javascripts(frontend)) + + css = stylesheet_link_tag(*active_scaffold_stylesheets(frontend)) + ie_css = stylesheet_link_tag(*active_scaffold_ie_stylesheets(frontend)) + + js + "\n" + css + "\n\n" + end + + # a general-use loading indicator (the "stuff is happening, please wait" feedback) + def loading_indicator_tag(options) + image_tag "/images/active_scaffold/default/indicator.gif", :style => "visibility:hidden;", :id => loading_indicator_id(options), :alt => "loading indicator", :class => "loading-indicator" + end + + def params_for(options = {}) + # :adapter and :position are one-use rendering arguments. they should not propagate. + # :sort, :sort_direction, and :page are arguments that stored in the session. they need not propagate. + # and wow. no we don't want to propagate :record. + # :commit is a special rails variable for form buttons + blacklist = [:adapter, :position, :sort, :sort_direction, :page, :record, :commit, :_method] + unless @params_for + @params_for = params.clone.delete_if { |key, value| blacklist.include? key.to_sym if key } + @params_for[:controller] = '/' + @params_for[:controller] unless @params_for[:controller].first(1) == '/' # for namespaced controllers + @params_for.delete(:id) if @params_for[:id].nil? + end + @params_for.merge(options) + end + + # Creates a javascript-based link that toggles the visibility of some element on the page. + # By default, it toggles the visibility of the sibling after the one it's nested in. You may pass custom javascript logic in options[:of] to change that, though. For example, you could say :of => '$("my_div_id")'. + # You may also flag whether the other element is visible by default or not, and the initial text will adjust accordingly. + def link_to_visibility_toggle(options = {}) + options[:of] ||= '$(this.parentNode).next()' + options[:default_visible] = true if options[:default_visible].nil? + + link_text = options[:default_visible] ? 'hide' : 'show' + link_to_function as_(link_text), "e = #{options[:of]}; e.toggle(); this.innerHTML = (e.style.display == 'none') ? '#{as_('show')}' : '#{as_('hide')}'", :class => 'visibility-toggle' + end + + def render_action_link(link, url_options) + url_options = url_options.clone + url_options[:action] = link.action + url_options[:controller] = link.controller if link.controller + url_options.delete(:search) if link.controller and link.controller.to_s != params[:controller] + url_options.merge! link.parameters if link.parameters + + html_options = link.html_options.merge({:class => link.action}) + if link.inline? + # NOTE this is in url_options instead of html_options on purpose. the reason is that the client-side + # action link javascript needs to submit the proper method, but the normal html_options[:method] + # argument leaves no way to extract the proper method from the rendered tag. + url_options[:_method] = link.method + + if link.method != :get and respond_to?(:protect_against_forgery?) and protect_against_forgery? + url_options[:authenticity_token] = form_authenticity_token + end + + # robd: protect against submitting get links as forms, since this causes annoying + # 'Do you wish to resubmit your form?' messages whenever you go back and forwards. + elsif link.method != :get + # Needs to be in html_options to as the adding _method to the url is no longer supported by Rails + html_options[:method] = link.method + end + + html_options[:confirm] = link.confirm if link.confirm? + html_options[:position] = link.position if link.position and link.inline? + html_options[:class] += ' action' if link.inline? + html_options[:popup] = true if link.popup? + html_options[:id] = action_link_id(url_options[:action],url_options[:id] || url_options[:parent_id]) + + if link.dhtml_confirm? + html_options[:class] += ' action' if !link.inline? + html_options[:page_link] = 'true' if !link.inline? + html_options[:dhtml_confirm] = link.dhtml_confirm.value + html_options[:onclick] = link.dhtml_confirm.onclick_function(controller,action_link_id(url_options[:action],url_options[:id] || url_options[:parent_id])) + end + html_options[:class] += " #{link.html_options[:class]}" unless link.html_options[:class].blank? + + # issue 260, use url_options[:link] if it exists. This prevents DB data from being localized. + label = url_options.delete(:link) || link.label + link_to label, url_options, html_options + end + + def column_class(column, column_value) + classes = [] + classes << "#{column.name}-column" + classes << column.css_class unless column.css_class.nil? + classes << 'empty' if column_empty? column_value + classes << 'sorted' if active_scaffold_config.list.user.sorting.sorts_on?(column) + classes << 'numeric' if column.column and [:decimal, :float, :integer].include?(column.column.type) + classes.join(' ') + end + + def column_empty?(column_value) + empty = column_value.nil? + empty ||= column_value.empty? if column_value.respond_to? :empty? + empty ||= (column_value == ' ') + empty ||= (column_value == active_scaffold_config.list.empty_field_text) + return empty + end + + def column_calculation(column) + calculation = active_scaffold_config.model.calculate(column.calculate, column.name, :conditions => controller.send(:all_conditions), + :joins => controller.send(:joins_for_collection), :include => controller.send(:active_scaffold_joins)) + end + end + end +end diff --git a/test/config/update_test.rb b/test/config/update_test.rb index b4aac17..7a2d0d8 100644 --- a/test/config/update_test.rb +++ b/test/config/update_test.rb @@ -1,17 +1,17 @@ -require File.join(File.dirname(__FILE__), '../test_helper.rb') - -class Config::UpdateTest < Test::Unit::TestCase - def setup - @config = ActiveScaffold::Config::Core.new :model_stub - @update = @config.update - - @config._load_action_columns - end - - def test__params_for_columns__returns_all_params - @config.columns[:a].params.add :keep_a, :a_temp - - assert @config.columns[:a].params.include?(:keep_a) - assert @config.columns[:a].params.include?(:a_temp) - end +require File.join(File.dirname(__FILE__), '../test_helper.rb') + +class Config::UpdateTest < Test::Unit::TestCase + def setup + @config = ActiveScaffold::Config::Core.new :model_stub + @update = @config.update + + @config._load_action_columns + end + + def test__params_for_columns__returns_all_params + @config.columns[:a].params.add :keep_a, :a_temp + + assert @config.columns[:a].params.include?(:keep_a) + assert @config.columns[:a].params.include?(:a_temp) + end end \ No newline at end of file