Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Version 0.3.1 (exported from SVN)

  • Loading branch information...
commit d4351fffb14838ffd7ac6aef85956e51c9d91aab 1 parent 2518f90
@chrisparrish chrisparrish authored
View
26 CHANGELOG
@@ -1,3 +1,22 @@
+v0.3.1 Moved Templates to Haml -- now requires Radiant 0.6.7 (or 0.6.6 and
+ install Haml yourself -- untested).
+
+ Added 'link' value to <r:stylesheet> and <r:javascript> tags so now you
+ can create an external link like:
+
+ <r:stylesheet name="my_file.css" as="link" />
+
+ or
+
+ <r:javascript name="my_file.js" as="link" />
+
+ Also made the as="inline" option XHTML compliant by replacing the
+ commenting (<!-- -->) with a proper CDATA wrapper.
+
+ See the documentation in 'available tags' on the page-edit page for more
+ (now more readable).
+
+
v0.3 Big new features plus code refactoring and a bug fix. First, the new
fetures include:
@@ -16,6 +35,13 @@ v0.3 Big new features plus code refactoring and a bug fix. First, the new
referenced by a <r:stylesheet> or <r:javascript> tag and the
dependant file's effectively_updated_at time changes to reflect it).
+ * Added file upload button to the index pages. Now instead of just
+ creating new stylesheets or javascripts, you can upload a file into
+ Radiant
+
+ The bugfix includes the completion of the one addressed in v0.2.1 by
+ adding the form helper to the remove.html.erb template.
+
v0.2.2 Bugfix - I added the UserActionObserver behavior and accompanying specs
to the Stylesheet and Javascript models
View
29 README
@@ -45,31 +45,30 @@ automagical and too top secret to disclose.
WHY CHANGE THINGS?
==================
-As John sees it, the pages tab is really for storing the main content. (Think of
-it as the list of available destinations for your users). Sure, they need
+As John sees it, the pages tab is for storing the main content. (Think of the
+tree view as the list of available destinations for your users). Sure, they need
stylesheets and javascripts but those are supporting files (much like images).
They augment your pages.
There are a number of interesting benefits gained by this approach:
- * These files really deserve designer-level permissions -- not user-level.
- Well, they just got their own tabs with the appropriate permissions.
+ * CSS and JS files now get designer-level permissions -- not user-level.
- * These files should be cached differently. Rather than the 5 minute
- page cache, we now have essentially infinite caching. Even more importantly
- because there's no dynamic content, we can tie the Last-Modified header to
- the updated_at datestamp and allow your server to quit repeatedly serving
- these assets.
+ * These files are now cached differently. Rather than the 5-minute expiration
+ on pages, these files can now report to the browser the true LAST-MODIFIED
+ date so we don't have to serve up these files constantly. We can put the
+ user's browser caching to work.
- * This frees up pages to offer fields (like meta keywords, meta description,
- etc.) and focus on behaviors that make absolutely no sense for, say, a
- stylesheet page (I mean, do javascripts really need a layout?).
+ * This properly separates the concerns of Pages and Text Assets. (I mean, do
+ javascripts really need a layout or stylesheets a breadcrumb?). Easier to
+ understand for the user and easier to develop for.
- * Makes it easy to include search functionality across your pages without
- terms like "background" yielding all your stylesheets.
+ * Allows extensions to deal better interact with pages. For example, a search
+ extension can now safely parse all the pages without terms like "background"
+ yielding all your stylesheets.
* Declutter the pages tree view so that it truly only shows what your clients
- see -- the things they'd aim their browser at.
+ see -- the things they'd aim their browser at (see John's point above).
* This opens the door for validation, minification and obfuscation of scripts
and stylesheets (I'm thinking that these belong in a separate extension but
View
12 app/controllers/admin/text_asset_controller.rb
@@ -47,6 +47,18 @@ def remove
end
+ def upload
+ @uploaded_file = params[:text_asset][:file]
+ puts
+ puts @uploaded_file.content_type
+ puts @uploaded_file.original_filename
+ puts
+ puts @uploaded_file.methods.sort.join("\n")
+ puts params[:text_asset][:file].string
+ redirect_to send("#{ model_symbol }_new_url")
+ end
+
+
private
# since the model name comes from the params, the model_class cannot
View
2  app/models/text_asset.rb
@@ -25,7 +25,7 @@ def after_initialize
def url
- StylesNScripts::Config["#{self.class.to_s.underscore}_directory"] +
+ "/" + StylesNScripts::Config["#{self.class.to_s.underscore}_directory"] +
"/" + self.filename
end
View
27 app/views/admin/text_asset/edit.html.erb
@@ -1,27 +0,0 @@
-<% if @text_asset.new_record? -%>
-<h1>New <%= proper_model_name %></h1>
-<% else -%>
-<h1>Edit <%= proper_model_name %></h1>
-<% end -%>
-
-<% form_tag do %>
- <%= hidden_field(model_name, "lock_version") %>
- <div class="form-area">
- <p class="title">
- <label for="<%= model_name %>_filename">Filename</label>
- <%= text_field(model_name, "filename", :class => 'textbox', :maxlength => 100) %>
- </p>
-
- <p class="content">
- <label for="<%= model_name %>_content">Body</label>
- <%= text_area(model_name, "content", :class => "textarea", :style => "width: 100%") %>
- </p>
- <%= updated_stamp @text_asset %>
- </div>
-
- <p class="buttons">
- <%= submit_tag(@text_asset.new_record? ? "Create #{proper_model_name}" : 'Save Changes', :class => 'button') %> <%= save_model_and_continue_editing_button(@text_asset) %> or <%= link_to("Cancel", send("#{model_name}_index_url") ) %>
- </p>
-<% end %>
-
-<%= focus("#{model_name}_filename") %>
View
22 app/views/admin/text_asset/edit.html.haml
@@ -0,0 +1,22 @@
+- if @text_asset.new_record?
+ %h1== New #{proper_model_name}
+- else
+ %h1== Edit #{proper_model_name}
+- form_tag do
+ = hidden_field model_name, 'lock_version'
+ .form-area
+ %p.title
+ %label{:for=>"#{model_name}_filename"} Filename
+ = text_field model_name, "filename", :class => 'textbox', :maxlength => 100
+ %p.content
+ %label{:for=>"#{model_name}_content"} Body
+ ~ text_area model_name, "content", :class => "textarea", :style => "width: 100%"
+ = updated_stamp @text_asset
+
+ = javascript_tag "$("#{model_name}_filename").activate()"
+
+ %p.buttons
+ = save_model_button(@text_asset)
+ = save_model_and_continue_editing_button(@text_asset)
+ or
+ = link_to 'Cancel', send("#{model_name}_index_url")
View
40 app/views/admin/text_asset/index.html.erb
@@ -1,40 +0,0 @@
-<% if model_name == 'stylesheet' -%>
-<h1>Stylesheets</h1>
-<p>Cascading Stylesheets (CSS files) can be used to alter the look &amp; feel of your pages, layouts, and/or snippets.</p>
-<% elsif model_name == 'javascript' -%>
-<h1>Javascripts</h1>
-<p>Javascripts add dynamic behaviors that can be used within your pages, layouts, and/or snippets.</p>
-<% end -%>
-
-<table id="stylesheets" class="index" cellpadding="0" cellspacing="0" border="0">
- <thead>
- <tr>
- <th class="<%= model_name %>"><%= proper_model_name %></th>
- <th class="modify">Modify</th>
- </tr>
- </thead>
- <tbody>
-<% unless @text_assets.empty? -%>
-<% for text_asset in @text_assets -%>
- <tr class="node level-1">
- <td class="snippet">
- <%= image model_name, :class => "icon", :alt => "#{model_name}-icon", :title => text_asset.url %>
- <span><%= link_to text_asset.filename, send("#{model_name}_edit_url", :id => text_asset), :title => text_asset.url %></span>
- </td>
- <td class="remove"><%= link_to image('remove', :alt => "Remove #{proper_model_name}"), send("#{model_name}_remove_url", :id => text_asset) %></td>
- </tr>
-<% end -%>
-<% else -%>
- <tr>
- <td colspan="2" class="note">No <%= proper_model_name.pluralize %></td>
- </tr>
-<% end -%>
- </tbody>
-</table>
-<script type="text/javascript">
-// <![CDATA[
- new RuledTable('<%= model_name %>');
-// ]]>
-</script>
-
-<p><%= link_to image("new-#{model_name}", :alt => "New #{proper_model_name}"), send("#{model_name}_new_url") %></p>
View
29 app/views/admin/text_asset/index.html.haml
@@ -0,0 +1,29 @@
+- if model_name == 'stylesheet'
+ %h1 Stylesheets
+ %p Cascading Stylesheets (CSS files) can be used to alter the look &amp; feel of your pages, layouts, and/or snippets.
+- elsif model_name == 'javascript'
+ %h1 Javascripts
+ %p Javascripts add dynamic behaviors that can be used within your pages, layouts, and/or snippets.
+
+%table.index{:id => model_name, :cellspacing => 0, :border => 0, :cellpadding => 0}
+ %thead
+ %tr
+ %th{:class => model_name}
+ = proper_model_name
+ %th.modify Modify
+ %tbody
+ - unless @text_assets.empty?
+ - @text_assets.each do |text_asset|
+ %tr.node.level-1
+ -# this next class is dumb but Radiant hard coded for the Snippet class so we'll just piggyback on that...
+ %td.snippet
+ = image(model_name, :alt => "#{model_name}-icon", :title => text_asset.url)
+ %span= link_to(text_asset.filename, send("#{model_name}_edit_url", :id => text_asset), :title => text_asset.url)
+ %td.remove
+ = link_to image('remove', :alt => "Remove #{proper_model_name}"), send("#{model_name}_remove_url", :id => text_asset)
+ - else
+ %tr
+ %td.note{:colspan => 2}== No #{proper_model_name.pluralize}
+
+%p
+ = link_to(image("new-#{model_name}", :alt => "New #{proper_model_name}"), send("#{model_name}_new_url"))
View
17 app/views/admin/text_asset/remove.html.erb
@@ -1,17 +0,0 @@
-<h1>Remove <%= proper_model_name %></h1>
-<p>Are you sure you want to <strong class="warning">permanently remove</strong> the following <%= model_name %>?</p>
-
-<table id="<%= model_name %>" class="index" cellpadding="0" cellspacing="0" border="0">
- <tbody>
- <tr class="node level-1" onmouseover="Element.addClassName(this, 'highlight');" onmouseout="Element.removeClassName(this, 'highlight');">
- <td class="<%= model_name %>">
- <%= image(model_name, :class => "icon", :alt => "#{model_name}-icon", :title => '') %>
- <%= @text_asset.filename %>
- </td>
- </tr>
- </tbody>
-</table>
-
-<% form_tag do %>
- <p class="buttons"><%= submit_tag("Delete #{proper_model_name}", :class => 'button') %> or <%= link_to('Cancel', send("#{model_name}_index_url") ) %></p>
-<% end %>
View
20 app/views/admin/text_asset/remove.html.haml
@@ -0,0 +1,20 @@
+%h1== Remove #{proper_model_name}
+
+%p
+ Are you sure you want to
+ %strong.warning permanently remove
+ == the following #{model_name}?
+
+%table.index{:id => model_name, :cellpadding => 0, :cellspacing => 0, :border => 0}
+ %tbody
+ %tr.node.level-1
+ -# this next class is dumb but Radiant hard coded for the Snippet class so we'll just piggyback on that...
+ %td.snippet
+ = image(model_name, :class => "icon", :alt => "#{model_name}-icon", :title => @text_asset.url)
+ %span.title= @text_asset.filename
+
+- form_tag do
+ %p.buttons
+ %input.button{:type=>"submit", :value=>"Delete #{proper_model_name}"}/
+ or
+ = link_to('Cancel', send("#{model_name}_index_url"))
View
79 lib/extended_page_tags.rb
@@ -5,45 +5,48 @@ class TagError < StandardError; end
[ { :name => 'stylesheet',
:class => Stylesheet,
:inline_tag => 'style',
+ :link_tag => 'link',
:sample_file => 'my_file.css' },
-
+
{ :name => 'javascript',
:class => Javascript,
:inline_tag => 'script',
+ :link_tag => 'script',
:sample_file => 'my_file.js' }
+
].each do |current_tag|
desc %{
- Renders the content from or url for a #{current_tag[:name]} asset. The
- @name@ attribute is required to identify the desired #{current_tag[:name]}.
- file. Additionally, the @as@ attribute can be used to choose whether to
- render the tag as one of the following:
-
- * @content@ - the content of the #{current_tag[:name]} is rendered (this
- is the default).
+ Renders the content from or a reference to the #{current_tag[:name]}
+ specified in the @name@ attribute. Additionally, the @as@ attribute can be
+ used to make the tag render as one of the following:
+
+ * @content@ - renders the #{current_tag[:name]}'s content (this is the
+ default when the @as@ attribute is omitted).
+
+ * @inline@ - wraps the #{current_tag[:name]}'s content in an (X)HTML
+ @<#{current_tag[:inline_tag]}>@ element.
+
+ * @url@ - the url to the #{current_tag[:name]} (relative to the web root).
+
+ * @link@ - embeds the url in an (X)HTML @<#{current_tag[:link_tag]}>@
+ element (creating a link to the external #{current_tag[:name]}).
+
+
+ *Additional Options:*
+ When rendering @as@="@inline@" or @as@="@link@", the (X)HTML @type@ attribute
+ is automatically be set to the default #{current_tag[:name]} content-type.
+ You can overrride this attribute or add additional ones by passing extra
+ attributes to the @<r:#{current_tag[:name]}>@ tag. For example,
+ <pre><code><r:#{current_tag[:name]} name="#{current_tag[:sample_file]}" as="inline" type="text/custom" id="my_id" /> produces...
- * @url@ - the url of the #{current_tag[:name]} file (relative to the
- web root).
-
- * @inline@ - same as @content@ but wraps the content in an (X)HTML
- &lt;#{current_tag[:inline_tag]}> element. By default, the @type@
- attribute of the &lt;#{current_tag[:inline_tag]}> element will
- automatically match the default #{current_tag[:name]} content-type
- (but you can override this -- see Additional Options below).
-
- *Additional Options:*
- When rendering &lt;r:#{current_tag[:name]} @as@="inline" />, any
- additional attributes you provide will be passed on directly to the
- &lt;#{current_tag[:inline_tag]}> element, like:
- <pre><code><r:#{current_tag[:name]} name="#{current_tag[:sample_file]}" as="inline" id="my_id" type="text/custom" />
- produces:
- <#{current_tag[:inline_tag]} type="text/custom" id="my_id">
- <!--
- Your #{current_tag[:name]}'s content here...
- -->
- </#{current_tag[:inline_tag]}></code></pre>
+<#{current_tag[:inline_tag]} type="text/custom" id="my_id">
+//<![CDATA[
+ Your #{current_tag[:name]}'s content here...
+//]]>
+</#{current_tag[:inline_tag]}></code></pre>
*Usage:*
- <pre><code><r:#{current_tag[:name]} name="#{current_tag[:sample_file]}" [as="content | inline | url"] /></code></pre>
+ <pre><code><r:#{current_tag[:name]} name="#{current_tag[:sample_file]}" [as="content | inline | url | link"] [other attribues...] /></code></pre>
}
tag(current_tag[:name]) do |tag|
if name = tag.attr['name']
@@ -51,13 +54,25 @@ class TagError < StandardError; end
case tag.attr['as']
when 'content', nil
text_asset.render
+
when 'url'
text_asset.url
- when 'inline'
+
+ when 'inline', 'link'
mime_type = tag.attr['type'] || StylesNScripts::Config["#{current_tag[:name]}_mime_type"]
optional_attribs = tag.attr.except('name', 'as', 'type').inject('') { |s, (k, v)| s << %{#{k.downcase}="#{v}" } }.strip
optional_attribs = " #{optional_attribs}" unless optional_attribs.empty?
- %{<#{current_tag[:inline_tag]} type="#{mime_type}"#{optional_attribs}>\n<!--\n#{text_asset.render}\n-->\n</#{current_tag[:inline_tag]}>}
+
+ if tag.attr['as'] == 'inline'
+ %{<#{current_tag[:inline_tag]} type="#{mime_type}"#{optional_attribs}>\n//<![CDATA[\n#{text_asset.render}\n//]]>\n</#{current_tag[:inline_tag]}>}
+
+ elsif tag.attr['as'] == 'link' && current_tag[:name] == 'stylesheet'
+ %{<link rel="stylesheet" href="#{text_asset.url}" type="#{mime_type}"#{optional_attribs} />}
+
+ elsif tag.attr['as'] == 'link' && current_tag[:name] == 'javascript'
+ %{<script src="#{text_asset.url}" type="#{mime_type}"#{optional_attribs}></script>}
+
+ end
end
else
raise TagError.new("#{current_tag[:name]} not found")
@@ -66,6 +81,6 @@ class TagError < StandardError; end
raise TagError.new("`#{current_tag[:name]}' tag must contain a `name' attribute.") unless tag.attr.has_key?('name')
end
end
-
+
end
end
View
86 spec/models/stylesheet_and_javascript_tags_spec.rb
@@ -10,11 +10,13 @@
[ { :asset_class => Stylesheet,
:name => 'stylesheet',
:default_mime_type => 'text/css',
+ :default_directory => '/css',
:inline_element => 'style' },
{ :asset_class => Javascript,
:name => 'javascript',
:default_mime_type => 'text/javascript',
+ :default_directory => '/js',
:inline_element => 'script' }
].each do |current_tag|
@@ -56,12 +58,12 @@
StylesNScripts::Config["#{current_tag[:name]}_directory"] = 'foo/bar/baz'
ActionController::Routing::Routes.reload!
@page.should render(%{<r:#{current_tag[:name]} name="main" as="url" />}).as(
- "foo/bar/baz/main")
+ "/foo/bar/baz/main")
StylesNScripts::Config.restore_defaults
ActionController::Routing::Routes.reload!
@page.should render(%{<r:#{current_tag[:name]} name="main" as="url" />}).as(
- "#{StylesNScripts::Config["#{current_tag[:name]}_directory"]}/main")
+ "#{current_tag[:default_directory]}/main")
end
@@ -75,9 +77,9 @@
ActionController::Routing::Routes.reload!
@page.should render(%{<r:#{current_tag[:name]} name="main" as="inline" />}).as(
%{<#{current_tag[:inline_element]} type="bologna">\n} <<
- %{<!--\n} <<
+ %{//<![CDATA[\n} <<
%{Main #{current_tag[:name]} content\n} <<
- %{-->\n} <<
+ %{//]]>\n} <<
%{</#{current_tag[:inline_element]}>}
)
@@ -86,9 +88,9 @@
ActionController::Routing::Routes.reload!
@page.should render(%{<r:#{current_tag[:name]} name="main" as="inline" />}).as(
%{<#{current_tag[:inline_element]} type="#{current_tag[:default_mime_type]}">\n} <<
- %{<!--\n} <<
+ %{//<![CDATA[\n} <<
%{Main #{current_tag[:name]} content\n} <<
- %{-->\n} <<
+ %{//]]>\n} <<
%{</#{current_tag[:inline_element]}>}
)
end
@@ -97,9 +99,9 @@
it %{if a 'type' element is defined in the <r:#{current_tag[:name]}> tag, this should override the default value as the <#{current_tag[:inline_element]}> element's 'type' attribute} do
@page.should render(%{<r:#{current_tag[:name]} name="main" as="inline" type="oscar" />}).as(
%{<#{current_tag[:inline_element]} type="oscar">\n} <<
- %{<!--\n} <<
+ %{//<![CDATA[\n} <<
%{Main #{current_tag[:name]} content\n} <<
- %{-->\n} <<
+ %{//]]>\n} <<
%{</#{current_tag[:inline_element]}>}
)
end
@@ -109,21 +111,85 @@
StylesNScripts::Config.restore_defaults
@page.should render(%{<r:#{current_tag[:name]} name="main" as="inline" another="mayer" ATTRIB="WEINER" />}).as(
%{<#{current_tag[:inline_element]} type="#{current_tag[:default_mime_type]}" another="mayer" attrib="WEINER">\n} <<
- %{<!--\n} <<
+ %{//<![CDATA[\n} <<
%{Main #{current_tag[:name]} content\n} <<
- %{-->\n} <<
+ %{//]]>\n} <<
%{</#{current_tag[:inline_element]}>}
)
end
end
+
+
+
+ describe "when the 'as' attribute is set to 'link'" do
+
+ it "should render a <#{current_tag[:inline_element]}> element with a 'src' attribute referencing the #{current_tag[:name]} and with the type attribute matching the #{current_tag[:name]}_mime_type setting" do
+ # try with a custom mime_type value
+ StylesNScripts::Config["#{current_tag[:name]}_mime_type"] = 'bologna'
+ StylesNScripts::Config["#{current_tag[:name]}_directory"] = 'foo/bar/baz'
+ ActionController::Routing::Routes.reload!
+ if current_tag[:name] == 'stylesheet'
+ @page.should render(%{<r:stylesheet name="main" as="link" />}).as(
+ %{<link rel="stylesheet" href="/foo/bar/baz/main" type="bologna" />}
+ )
+ elsif current_tag[:name] == 'javascript'
+ @page.should render(%{<r:javascript name="main" as="link" />}).as(
+ %{<script src="/foo/bar/baz/main" type="bologna"></script>}
+ )
+ end
+
+ # try with the default mime_type and directory values
+ StylesNScripts::Config.restore_defaults
+ ActionController::Routing::Routes.reload!
+ if current_tag[:name] == 'stylesheet'
+ @page.should render(%{<r:stylesheet name="main" as="link" />}).as(
+ %{<link rel="stylesheet" href="#{current_tag[:default_directory]}/main" type="#{current_tag[:default_mime_type]}" />}
+ )
+ elsif current_tag[:name] == 'javascript'
+ @page.should render(%{<r:javascript name="main" as="link" />}).as(
+ %{<script src="#{current_tag[:default_directory]}/main" type="#{current_tag[:default_mime_type]}"></script>}
+ )
+ end
+ end
+
+
+ it %{if a 'type' element is defined in the <r:#{current_tag[:name]}> tag, this should override the default value as the <#{current_tag[:inline_element]}> element's 'type' attribute} do
+ if current_tag[:name] == 'stylesheet'
+ @page.should render(%{<r:stylesheet name="main" as="link" type="oscar" />}).as(
+ %{<link rel="stylesheet" href="#{current_tag[:default_directory]}/main" type="oscar" />}
+ )
+ elsif current_tag[:name] == 'javascript'
+ @page.should render(%{<r:javascript name="main" as="link" type="oscar" />}).as(
+ %{<script src="#{current_tag[:default_directory]}/main" type="oscar"></script>}
+ )
+ end
+ end
+
+
+ it %{should pass additional attributes into the <#{current_tag[:inline_element]}> element (and downcase each attribute name)} do
+ StylesNScripts::Config.restore_defaults
+ if current_tag[:name] == 'stylesheet'
+ @page.should render(%{<r:stylesheet name="main" as="link" another="mayer" ATTRIB="WEINER" />}).as(
+ %{<link rel="stylesheet" href="#{current_tag[:default_directory]}/main" type="#{current_tag[:default_mime_type]}" another="mayer" attrib="WEINER" />}
+ )
+ elsif current_tag[:name] == 'javascript'
+ @page.should render(%{<r:javascript name="main" as="link" another="mayer" ATTRIB="WEINER" />}).as(
+ %{<script src="#{current_tag[:default_directory]}/main" type="#{current_tag[:default_mime_type]}" another="mayer" attrib="WEINER"></script>}
+ )
+ end
+ end
+
+ end
+
end
+
describe "<r:#{current_tag[:name]}> tags in a #{current_tag[:asset_class].to_s} context" do
scenario :pages, :javascripts, :stylesheets
View
4 styles_n_scripts_extension.rb
@@ -6,7 +6,7 @@
class StylesNScriptsExtension < Radiant::Extension
- version "0.3"
+ version "0.3.1"
extension_name "Styles 'n Scripts"
description "Adds CSS and JS file management to Radiant"
@@ -18,6 +18,7 @@ class StylesNScriptsExtension < Radiant::Extension
controller.stylesheet_edit 'admin/css/edit/:id', :action => 'edit'
controller.stylesheet_new 'admin/css/new', :action => 'new'
controller.stylesheet_remove 'admin/css/remove/:id', :action => 'remove'
+ controller.stylesheet_upload 'admin/css/upload', :action => 'upload'
end
# Admin javascript Routes
@@ -26,6 +27,7 @@ class StylesNScriptsExtension < Radiant::Extension
controller.javascript_edit 'admin/js/edit/:id', :action => 'edit'
controller.javascript_new 'admin/js/new', :action => 'new'
controller.javascript_remove 'admin/js/remove/:id', :action => 'remove'
+ controller.javascript_upload 'admin/js/upload', :action => 'upload'
end
# Public side routes (for JS and CSS directories)
Please sign in to comment.
Something went wrong with that request. Please try again.