theme_support 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Gemfile ADDED
@@ -0,0 +1 @@
1
+ gem 'rails', '3.0.0'
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2005 Matt McCray, based on code from Typo by Tobias Luetke
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWAR
data/README ADDED
@@ -0,0 +1,223 @@
1
+ This theme support has been turned into a gem and ported to Rails 3.0 by Pierre Yager and Sylvain Claudel (http://www.crisalid.com)
2
+
3
+ = Theme Support for Rails Applications
4
+
5
+ This plugin provides support for themes to the rails application environment.
6
+ It supports theme specific images, stylesheets, javascripts, and views. The
7
+ views can be in ERb (rhtml) or liquid formats. Optionally, you can configure
8
+ the theme system to ignore any templates except liquid ones.
9
+
10
+
11
+ == Creating a Theme using Theme Support ==
12
+
13
+ This plugin automatically makes any patches needed for theme support. Use the following command to create the file structure needed (replace YOUR_THEME_NAME with the name of your theme):
14
+
15
+ rails generate theme YOUR_THEME_NAME
16
+
17
+ The following theme folder structure will generate in your app code:
18
+
19
+ $app_root
20
+ themes/
21
+ [theme_name]
22
+ images/
23
+ stylesheets/
24
+ javascripts/
25
+ views/ <- you can override application views
26
+ layouts/ <- layout .rhtml or .liquid templates
27
+ about.markdown
28
+ preview.png
29
+
30
+ ==Caveats==
31
+ When run in production mode, it will automatically cache the theme files so that
32
+ the web-server will deliver them in subsequent requests.
33
+
34
+ It bears noting that, like Typo, this will mean your apache/fcgi process will need
35
+ write permissions. This could be a possible security vulnerability. For those of us using passanger and mongrels, more information will follow.
36
+
37
+ With that in mind, it is best to pre-cache all of the theme files by using the
38
+ included rake tasks:
39
+
40
+ $ rake themes:cache:create
41
+
42
+ The theme file cache generates the following file structure:
43
+
44
+ $app_root
45
+ public/
46
+ themes/
47
+ [theme_name]/
48
+ images/
49
+ stylesheets/
50
+ javascripts/
51
+
52
+ There are other rake tasks available:
53
+
54
+ - themes:cache:create
55
+ - themes:cache:remove
56
+ - themes:cache:update
57
+
58
+ == Using your new Theme in your app code ==
59
+ You specify which theme to use in your controller by using the 'theme' helper.
60
+ It's used just like the 'layout' helper. In fact, you can use them both
61
+ simultaneously. The following will render actions using the 'application' layout
62
+ in the 'blue_bird' theme (theme/blue_bird/views/layouts/application.html.erb):
63
+
64
+ class ApplicationController < ActionController::Base
65
+ layout 'application'
66
+
67
+ theme 'blue_bird'
68
+
69
+ ...
70
+ end
71
+
72
+ You can also defer the theme lookup to a controller method:
73
+
74
+ class ApplicationController < ActionController::Base
75
+ layout 'application'
76
+
77
+ theme :get_theme
78
+
79
+ def get_theme
80
+
81
+ # If you let the user choose their own theme, you might
82
+ # add a User#theme field...
83
+
84
+ current_user.theme
85
+ end
86
+
87
+ ...
88
+ end
89
+
90
+
91
+ Note: By setting the theme in the ApplicationController you can set
92
+ the theme for the whole application.
93
+
94
+ == Using themes in your Views ==
95
+
96
+ ERb:
97
+ ----
98
+ In your application views, there are theme specific helper tags
99
+ available to you.
100
+
101
+ - theme_image_tag
102
+ - theme_image_path
103
+ - theme_javascript_include_tag
104
+ - theme_javascript_path
105
+ - theme_stylesheet_link_tag
106
+ - theme_stylesheet_path
107
+
108
+ ERB Example :
109
+ # Note my theme is called "blue_bird" and my css file is called "style.css"
110
+ <%= theme_stylesheet_link_tag 'blue_bird', 'style' %>
111
+
112
+ LIQUID:
113
+ -------
114
+ Liquid templates there is a single helper, themeitem, that will determine
115
+ the path base on the theme file extension. Here's how you'd use it:
116
+
117
+ <link rel="StyleSheet" href="{% themeitem %} default.css {% endthemeitem %}" />
118
+ ...
119
+ <img src="{% themeitem %} logo.png {% endthemeitem %}" />
120
+
121
+ The output from those two calls are:
122
+
123
+ <link rel="StyleSheet" href="/themes/[current_theme]/stylesheets/default.css" />
124
+ ...
125
+ <img src="/themes/[current_theme]/images/logo.png" />
126
+
127
+ == ActionMailer Support ==
128
+
129
+ New in version 1.4 is ActionMailer support. Note, this is still experimental. However,
130
+ if you would like your themes to be able to override your ActionMailer views, you can
131
+ send the theme in your deliver_* method call. For example, assuming we have an ActionMailer
132
+ class named Mailer, and have implemented theme_support as shown above, here's how you would
133
+ allowing themes in emails:
134
+
135
+
136
+ def send_email
137
+ Mailer.deliver_my_email( 'a variable', :theme=>get_theme )
138
+ end
139
+
140
+
141
+ == Contributors
142
+
143
+ The theme_support plugin includes patches from the following:
144
+
145
+ * agkr
146
+ * D.J. Vogel
147
+ * Pierre Yager (zedalaye) and Sylvain Claudel (riven)
148
+
149
+ Thanks guys!
150
+
151
+ == Changelog
152
+
153
+ 3.0.0 - Converted theme_support plugin into a Rails 3.0 compatible gem.
154
+
155
+ 1.5.0 - Using jystewart's fork of the original github theme_support, the helper methods should
156
+ work in Rails 2.2.2. ReadME fixed. Layouts changed to reflect Rails conventions: e.g.,
157
+ layouts are now under views, application.html.erb used to reflect standard naming
158
+ conventions.
159
+
160
+ 1.4.0 - Better support for Rails 1.1+. Updated the liquid themeitem tag.
161
+ Liquid layouts are no longer generated by default.Added a couple
162
+ of patches. One allows theme sub-directories. For example, you
163
+ can have:
164
+
165
+ [theme_dir]
166
+ stylesheets/
167
+ admin/
168
+ main.css
169
+
170
+ Added experimental support for themeing ActionMailer classes.
171
+ They work as normal, if you want to all theme's to override the
172
+ .rhtml|.liquid views, send the theme in the deliver_* method. For
173
+ example:
174
+
175
+ Mailer.deliver_signup( user, :theme=>get_theme() )
176
+
177
+ In that example, `get_theme` is a method on the controller and at
178
+ the top we've used:
179
+
180
+ layout 'default'
181
+ theme :get_theme
182
+
183
+ 1.3.0 - The theme_system component is no longer needed. All of the
184
+ theme support is driven by a single plugin named, oddly enough,
185
+ 'theme_support'. Also improved theme route support. Instead of
186
+ overriding RouteSet#reload, RouteSet#draw is overridden, making
187
+ the theme support entirely transparent -- hopefully ;-)
188
+
189
+ 1.2.2 - More Bug-fixes.
190
+
191
+ 1.2.1 - Bug-fixes and documentation clean up.
192
+
193
+ 1.2.0 - Updated actionview_ex with the new render_file additions from
194
+ Typo. Renamed the rake tasks so that they all start with
195
+ 'theme' (theme_create_cache, theme_remove_cache,
196
+ theme_update_cache). You can update the system files by running:
197
+
198
+ $ ./script/generate theme _system_
199
+
200
+ Full support for Liquid templates, as well as an option to only
201
+ allow Liquid templates in a theme.
202
+
203
+ 1.1.1 - Added rake tasks for pre-caching the themes, and removing the
204
+ cached themes.
205
+
206
+ 1.1.0 - [Breaking] Abstraction of the Typo theme system. The themes are
207
+ now the same as is used in Typo. The theme engine itself is a
208
+ combination of plugins and a component. No more symlinks, thank
209
+ goodness.
210
+
211
+ 1.0.2 - The current_theme is now retrieved from the controller. Where
212
+ symlinks are created on *nix systems, shortcuts are created
213
+ on Windows if Win32Utils is installed.
214
+
215
+ 1.0.1 - Added 'themes' directory, theme definition file, and symlinks
216
+ to the appropriate directories on supported platforms.
217
+
218
+ 1.0.0 - Initial release
219
+
220
+
221
+ ---
222
+ Copyright (c) 2005 Matt McCray, based on code from Typo by Tobias Luetke
223
+ released under the MIT license
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 3.0.0
@@ -0,0 +1,15 @@
1
+ NAME
2
+ theme - Creates the folder structure for a new theme
3
+
4
+ SYNOPSIS
5
+ theme [theme_name]
6
+
7
+ DESCRIPTION
8
+ This generator creates the folder structure for a new theme. It creates all of
9
+ the folders for your theme content (images, stylesheets, javascripts, layouts,
10
+ and views).
11
+
12
+ EXAMPLE
13
+ rails generate theme default
14
+
15
+ This will generate the file structure for a theme named 'default'.
@@ -0,0 +1,5 @@
1
+ ### <%= class_name.underscore.humanize.titleize %>
2
+
3
+ Author: *Me*
4
+
5
+ This description can be found in themes/<%= file_name %>/about.markdown
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html>
4
+ <head>
5
+ <title></title>
6
+ <%%= theme_stylesheet_link_tag '<%= file_name %>' %>
7
+ </head>
8
+ <body>
9
+ <%= yield %>
10
+ </body>
11
+ </html>
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html>
4
+ <head>
5
+ <title></title>
6
+ <link href="{% themeitem %} <%= file_name %>.css {% endthemeitem %}" media="screen" rel="Stylesheet" type="text/css" />
7
+ </head>
8
+ <body>
9
+ {{ content_for_layout }}
10
+ </body>
11
+ </html>
@@ -0,0 +1,7 @@
1
+ /*
2
+ Main StyleSheet for the '<%= class_name %>' theme
3
+ */
4
+
5
+ BODY {
6
+
7
+ }
@@ -0,0 +1,4 @@
1
+ enabled: true
2
+ title: <%= class_name.underscore.humanize.titleize %>
3
+ author: Matt McCray
4
+ description: This is the description... All light and fluffy.
@@ -0,0 +1,13 @@
1
+ # Overriding Views
2
+
3
+ You can override views by putting custom `html.erb` or `liquid`
4
+ templates in this directory. You use the same folder structure
5
+ as Rails:
6
+
7
+ views/
8
+ [controller_name]/
9
+ _overriden_partial.html.erb
10
+ overriden_action.html.erb
11
+
12
+ *Note:* These are overrides! They will only work if they have
13
+ a matching view in the main rails `app/views` folder.
@@ -0,0 +1,21 @@
1
+ class ThemeGenerator < Rails::Generators::NamedBase
2
+ source_root File.expand_path("../templates", __FILE__)
3
+
4
+ def create_theme_directories
5
+ theme_root = File.join("themes", file_name)
6
+
7
+ empty_directory theme_root
8
+
9
+ %w{images javascripts views stylesheets}.each do |d|
10
+ empty_directory File.join(theme_root, d)
11
+ end
12
+
13
+ empty_directory File.join(theme_root, "views", "layouts")
14
+
15
+ copy_file 'about.markdown', File.join(theme_root, "about.markdown")
16
+ copy_file 'preview.png', File.join(theme_root, 'images', 'preview.png' )
17
+ copy_file 'theme.css', File.join(theme_root, 'stylesheets', "#{file_name}.css" )
18
+ copy_file 'layout.html.erb', File.join(theme_root, 'views', 'layouts', 'application.html.erb' )
19
+ copy_file 'views_readme', File.join(theme_root, 'views', 'views_readme.txt' )
20
+ end
21
+ end
@@ -0,0 +1,63 @@
1
+ #
2
+ # These are theme helper tags
3
+ #
4
+ module ActionView::Helpers::AssetTagHelper
5
+ # returns the public path to a theme stylesheet
6
+ def theme_stylesheet_path( source=nil, theme=nil )
7
+ theme = theme || controller.current_theme
8
+ compute_public_path(source || "theme", "themes/#{theme}/stylesheets", 'css')
9
+ end
10
+
11
+ # returns the path to a theme image
12
+ def theme_image_path( source, theme=nil )
13
+ theme = theme || controller.current_theme
14
+ compute_public_path(source, "themes/#{theme}/images", 'png')
15
+ end
16
+
17
+ # returns the path to a theme javascript
18
+ def theme_javascript_path( source, theme=nil )
19
+ theme = theme || controller.current_theme
20
+ compute_public_path(source, "themes/#{theme}/javascripts", 'js')
21
+ end
22
+
23
+ # This tag it will automatially include theme specific css files
24
+ def theme_stylesheet_link_tag(*sources)
25
+ sources.uniq!
26
+ options = sources.last.is_a?(Hash) ? sources.pop.stringify_keys : { }
27
+ sources.collect { |source|
28
+ source = theme_stylesheet_path(source)
29
+ tag("link", { "rel" => "Stylesheet", "type" => "text/css", "media" => "screen", "href" => source }.merge(options))
30
+ }.join("\n")
31
+ end
32
+
33
+ # This tag will return a theme-specific IMG
34
+ def theme_image_tag(source, options = {})
35
+ options.symbolize_keys
36
+
37
+ options[:src] = theme_image_path(source)
38
+ options[:alt] ||= File.basename(options[:src], '.*').split('.').first.capitalize
39
+
40
+ if options[:size]
41
+ options[:width], options[:height] = options[:size].split("x")
42
+ options.delete :size
43
+ end
44
+
45
+ tag("img", options)
46
+ end
47
+
48
+ # This tag can be used to return theme-specific javscripts
49
+ def theme_javascript_include_tag(*sources)
50
+ options = sources.last.is_a?(Hash) ? sources.pop.stringify_keys : { }
51
+ if sources.include?(:defaults)
52
+ sources = sources[0..(sources.index(:defaults))] +
53
+ @@javascript_default_sources.dup +
54
+ sources[(sources.index(:defaults) + 1)..sources.length]
55
+ sources.delete(:defaults)
56
+ sources << "application" if defined?(Rails.root) && File.exists?("#{Rails.root}/public/javascripts/application.js")
57
+ end
58
+ sources.collect { |source|
59
+ source = theme_javascript_path(source)
60
+ content_tag("script", "", { "type" => "text/javascript", "src" => source }.merge(options))
61
+ }.join("\n")
62
+ end
63
+ end
@@ -0,0 +1,31 @@
1
+ # A Liquid Tag for retrieving path information for theme specific media
2
+ #
3
+ # Returns the path based on the file extension
4
+ #
5
+ class Themeitem < Liquid::Block
6
+
7
+ @@image_exts = %w( .png .jpg .jpeg .jpe .gif )
8
+ @@stylesheet_exts = %w( .css )
9
+ @@javascript_exts = %w( .js .htc )
10
+
11
+ def render(context)
12
+ # Which, if either, of these are correct?
13
+ base_url = context['request'].relative_url_root || ActionController::Base.asset_host.to_s
14
+ theme_name = @theme_name || context['active_theme']
15
+
16
+ filename = @nodelist.join('').strip
17
+ ext = File.extname( filename )
18
+
19
+ if @@image_exts.include?( ext )
20
+ "#{base_url}/themes/#{theme_name}/images/#{filename}"
21
+
22
+ elsif @@stylesheet_exts.include?( ext )
23
+ "#{base_url}/themes/#{theme_name}/stylesheets/#{filename}"
24
+
25
+ elsif @@javascript_exts.include?( ext )
26
+ "#{base_url}/themes/#{theme_name}/javascripts/#{filename}"
27
+ end
28
+ end
29
+ end
30
+
31
+ Liquid::Template.register_tag( 'themeitem', Themeitem )
@@ -0,0 +1,54 @@
1
+ class AbstractController::Base
2
+ attr_accessor :current_theme
3
+ attr_accessor :force_liquid_template
4
+
5
+ # Use this in your controller just like the <tt>layout</tt> macro.
6
+ # Example:
7
+ #
8
+ # theme 'theme_name'
9
+ #
10
+ # -or-
11
+ #
12
+ # theme :get_theme
13
+ #
14
+ # def get_theme
15
+ # 'theme_name'
16
+ # end
17
+
18
+ #class << self
19
+ def self.theme(theme_name, conditions = {})
20
+ # TODO: Allow conditions... (?)
21
+ write_inheritable_attribute "theme", theme_name
22
+ theme = ActionView::Base.process_view_paths(File.join("themes", theme_name, "views"))
23
+ prepend_view_path(theme)
24
+ end
25
+ #end
26
+
27
+ # Retrieves the current set theme
28
+ def current_theme(passed_theme=nil)
29
+ theme = passed_theme || self.class.read_inheritable_attribute("theme")
30
+
31
+ @active_theme = case theme
32
+ when Symbol then send(theme)
33
+ when Proc then theme.call(self)
34
+ when String then theme
35
+ end
36
+ end
37
+ end
38
+
39
+ AbstractController::Layouts.module_eval do
40
+ def _normalize_options(options)
41
+ super
42
+
43
+ if _include_layout?(options)
44
+ layout = options.key?(:layout) ? options.delete(:layout) : :default
45
+ value = _layout_for_option(layout)
46
+ options[:layout] = (value =~ /\blayouts/ ? value : "layouts/#{value}") if value
47
+ end
48
+
49
+ if current_theme
50
+ theme_path = File.join(Rails.root, "themes", current_theme, "views")
51
+ options[:layout] = File.join(theme_path, options[:layout])
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,93 @@
1
+ # Extend the Base ActionController to support themes
2
+ module ActionMailer
3
+ class Base
4
+
5
+ alias_method :__render, :render
6
+ alias_method :__initialize, :initialize
7
+
8
+ @current_theme = nil
9
+
10
+ attr_accessor :current_theme
11
+
12
+ def initialize(method_name=nil, *parameters)
13
+ if parameters[-1].is_a? Hash and (parameters[-1].include? :theme)
14
+ @current_theme = parameters[-1][:theme]
15
+ parameters[-1].delete :theme
16
+ parameters[-1][:current_theme] = @current_theme
17
+ end
18
+ create!(method_name, *parameters) if method_name
19
+ end
20
+
21
+ def create!(method_name, *parameters) #:nodoc:
22
+ initialize_defaults(method_name)
23
+ __send__(method_name, *parameters)
24
+
25
+ tpaths = []
26
+ tpaths << File.join(Rails.root, "themes", self.current_theme, "views", mailer_name) if self.current_theme
27
+ tpaths << template_path
28
+
29
+ # If an explicit, textual body has not been set, we check assumptions.
30
+ unless String === @body
31
+ # First, we look to see if there are any likely templates that match,
32
+ # which include the content-type in their file name (i.e.,
33
+ # "the_template_file.text.html.erb", etc.). Only do this if parts
34
+ # have not already been specified manually.
35
+
36
+ if @parts.empty?
37
+
38
+ tpaths.each do |tpath|
39
+ Dir.glob("#{tpath}/#{@template}.*").each do |path|
40
+ template = template_root["#{tpath}/#{File.basename(path)}"]
41
+
42
+ # Skip unless template has a multipart format
43
+ next unless template && template.multipart?
44
+
45
+ @parts << Part.new(
46
+ :content_type => template.content_type,
47
+ :disposition => "inline",
48
+ :charset => charset,
49
+ :body => render_message(template, @body)
50
+ )
51
+ end
52
+ break if @parts.any?
53
+ end
54
+ unless @parts.empty?
55
+ @content_type = "multipart/alternative"
56
+ @parts = sort_parts(@parts, @implicit_parts_order)
57
+ end
58
+ end
59
+
60
+ # Then, if there were such templates, we check to see if we ought to
61
+ # also render a "normal" template (without the content type). If a
62
+ # normal template exists (or if there were no implicit parts) we render
63
+ # it.
64
+ template_exists = @parts.empty?
65
+ tpaths.each do |tpath|
66
+ template_exists ||= template_root["#{tpath}/#{@template}"]
67
+ if template_exists
68
+ @body = render_message(@template, @body)
69
+ break
70
+ end
71
+ end
72
+
73
+ # Finally, if there are other message parts and a textual body exists,
74
+ # we shift it onto the front of the parts and set the body to nil (so
75
+ # that create_mail doesn't try to render it in addition to the parts).
76
+ if !@parts.empty? && String === @body
77
+ @parts.unshift Part.new(:charset => charset, :body => @body)
78
+ @body = nil
79
+ end
80
+ end
81
+
82
+ # If this is a multipart e-mail add the mime_version if it is not
83
+ # already set.
84
+ @mime_version ||= "1.0" if !@parts.empty?
85
+
86
+ # build the mail object itself
87
+ @mail = create_mail
88
+ end
89
+
90
+
91
+
92
+ end
93
+ end
@@ -0,0 +1,14 @@
1
+ module ThemeSupport
2
+ module RoutingExtensions
3
+ def themeing
4
+ @set.with_options :controller => 'theme' do |theme|
5
+ match '/themes/:theme/images/*filename', :to => 'theme#images', :as => 'theme_images'
6
+ match '/themes/:theme/stylesheets/*filename', :to => 'theme#stylesheets', :as => 'theme_stylesheets'
7
+ match '/themes/:theme/javascripts/*filename', :to => 'theme#javascript', :as => 'theme_javascript'
8
+ match '/themes/*whatever', :to => 'theme#error'
9
+ end
10
+ end
11
+ end
12
+ end
13
+
14
+ ActionDispatch::Routing::Mapper.send :include, ThemeSupport::RoutingExtensions
@@ -0,0 +1,10 @@
1
+ require 'rails'
2
+
3
+ module ThemeSupport
4
+ class Railtie < Rails::Railtie
5
+ rake_tasks do
6
+ load File.expand_path('../tasks.rb', __FILE__)
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,39 @@
1
+ namespace :themes do
2
+ namespace :cache do
3
+
4
+ desc "Creates the cached (public) theme folders"
5
+ task :create do
6
+ themes_root = File.join(Rails.root, "themes")
7
+ for theme in Dir.glob(File.join(themes_root, '*'))
8
+
9
+ theme_name = theme.split( File::Separator )[-1]
10
+ theme_root = File.join(Rails.root, "public", "themes", theme_name)
11
+
12
+ puts "Creating #{theme_root}"
13
+ FileUtils.mkdir_p "#{theme_root}"
14
+
15
+ %w{ images stylesheets javascripts }.each do |d|
16
+ FileUtils.mkdir_p File.join(theme_root, d)
17
+ Dir.glob(File.join(theme, d, '**', '*')) do |f|
18
+ final_path = f[theme.length + 1, f.length]
19
+ if File.stat(f).directory? then
20
+ FileUtils.mkdir_p File.join(theme_root, final_path) #, :verbose => true
21
+ else
22
+ FileUtils.cp f, File.join(theme_root, final_path) #, :verbose => true
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ desc "Removes the cached (public) theme folders"
30
+ task :remove do
31
+ themes_cache = File.join(Rails.root, 'public', 'themes')
32
+ puts "Removing #{themes_cache}"
33
+ FileUtils.rm_r themes_cache, :force => true
34
+ end
35
+
36
+ desc "Updates the cached (public) theme folders"
37
+ task :update => [:remove, :create]
38
+ end
39
+ end
@@ -0,0 +1,58 @@
1
+ class Theme
2
+ cattr_accessor :cache_theme_lookup
3
+ @@cache_theme_lookup = false
4
+
5
+ attr_accessor :name, :title, :description, :preview_image
6
+
7
+ def initialize(name)
8
+ @name = name
9
+ @title = name.underscore.humanize.titleize
10
+ @description_html = nil
11
+ end
12
+
13
+ def description
14
+ if @description_html.nil?
15
+ @description_html = RedCloth.new(File.read( File.join(Theme.path_to_theme(name), "about.markdown") )).to_html(:markdown, :textile) rescue "#{title}"
16
+ end
17
+ @description_html
18
+ end
19
+
20
+ def has_preview?
21
+ File.exists?( File.join( Theme.path_to_theme(name), 'images', 'preview.png' ) ) rescue false
22
+ end
23
+
24
+ def preview_image
25
+ 'preview.png'
26
+ end
27
+
28
+ def self.find_all
29
+ installed_themes.inject([]) do |array, path|
30
+ array << theme_from_path(path)
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def self.themes_root
37
+ File.join(Rails.root, "themes")
38
+ end
39
+
40
+ def self.path_to_theme(theme)
41
+ File.join(themes_root, theme)
42
+ end
43
+
44
+ def self.theme_from_path(path)
45
+ name = path.scan(/[-\w]+$/i).flatten.first
46
+ self.new(name)
47
+ end
48
+
49
+ def self.installed_themes
50
+ cache_theme_lookup ? @theme_cache ||= search_theme_directory : search_theme_directory
51
+ end
52
+
53
+ def self.search_theme_directory
54
+ Dir.glob("#{themes_root}/[-_a-zA-Z0-9]*").collect do |file|
55
+ file if File.directory?(file)
56
+ end.compact
57
+ end
58
+ end
@@ -0,0 +1,59 @@
1
+ # The controller for serving/cacheing theme content...
2
+ #
3
+ class ThemeController < ActionController::Base
4
+
5
+ after_filter :cache_theme_files
6
+
7
+ def stylesheets
8
+ render_theme_item(:stylesheets, params[:filename].join('/'), params[:theme])
9
+ end
10
+
11
+ def javascript
12
+ render_theme_item(:javascripts, params[:filename].join('/'), params[:theme], 'text/javascript')
13
+ end
14
+
15
+ def images
16
+ render_theme_item(:images, params[:filename].to_s, params[:theme])
17
+ end
18
+
19
+ def error
20
+ render :nothing => true, :status => 404
21
+ end
22
+
23
+ private
24
+
25
+ def render_theme_item(type, file, theme, mime = mime_for(file))
26
+ render :text => "Not Found", :status => 404 and return if file.split(%r{[\\/]}).include?("..")
27
+ send_file "#{Theme.path_to_theme(theme)}/#{type}/#{file}", :type => mime, :content_type => mime, :disposition => 'inline'
28
+ end
29
+
30
+ def cache_theme_files
31
+ path = request.fullpath
32
+ begin
33
+ ThemeController.cache_page( response.body, path )
34
+ rescue
35
+ STERR.puts "Cache Exception: #{$!}"
36
+ end
37
+ end
38
+
39
+ def mime_for(filename)
40
+ case filename.downcase
41
+ when /\.js$/
42
+ 'text/javascript'
43
+ when /\.css$/
44
+ 'text/css'
45
+ when /\.gif$/
46
+ 'image/gif'
47
+ when /(\.jpg|\.jpeg)$/
48
+ 'image/jpeg'
49
+ when /\.png$/
50
+ 'image/png'
51
+ when /\.swf$/
52
+ 'application/x-shockwave-flash'
53
+ else
54
+ 'application/binary'
55
+ end
56
+ end
57
+ end
58
+
59
+
@@ -0,0 +1,4 @@
1
+ # <tt>ThemeError</tt> is thrown when <tt>force_liquid</tt> is true, and
2
+ # a <tt>.liquid</tt> template isn't found.
3
+ class ThemeError < StandardError
4
+ end
@@ -0,0 +1,3 @@
1
+ # this is here so that Rails doesn't complain about a missing default helper...
2
+ module ThemeHelper
3
+ end
@@ -0,0 +1,23 @@
1
+ # Load rake tasks
2
+ require 'theme_support/railtie'
3
+
4
+ # Load the Theme model and ThemeController
5
+ require 'theme_support/theme'
6
+ require 'theme_support/theme_controller'
7
+
8
+ # Initializes theme support by extending some of the core Rails classes
9
+ require 'theme_support/patches/abstractcontroller_ex'
10
+ require 'theme_support/patches/routeset_ex'
11
+
12
+ # Add the tag helpers for rhtml and, optionally, liquid templates
13
+ require 'theme_support/helpers/erb_theme_tags'
14
+
15
+ # Commented out to remove the message
16
+ # "Liquid doesn't seem to be loaded... uninitialized constant Liquid"
17
+ #begin
18
+ # require 'helpers/liquid_theme_tags'
19
+ #rescue
20
+ # # I guess Liquid isn't being used...
21
+ # STDERR.puts "Liquid doesn't seem to be loaded... #{$!}"
22
+ #end
23
+
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+
3
+ spec = Gem::Specification.new do |s|
4
+ ## package information
5
+ s.name = 'theme_support'
6
+ s.author = 'Pierre Yager and Sylvain Claudel'
7
+ s.email = "pierre@levosgien.net"
8
+ s.version = ("$Release: 3.0.0" =~ /[\.\d]+/) && $&
9
+ s.platform = Gem::Platform::RUBY
10
+ s.homepage = 'http://github.com/zedalaye/theme_support'
11
+ s.rubyforge_project = 'theme-support'
12
+ s.summary = "add multi-themes support to Rails 3.0"
13
+ s.description = <<-END
14
+ ThemeSupport adds support for multi-themes to your Rails 3.0 application
15
+ END
16
+
17
+ ## files
18
+ files = []
19
+ files += Dir.glob('lib/**/*')
20
+ files += %w[Gemfile LICENSE README VERSION theme_support.gemspec]
21
+ s.files = files.delete_if { |path| path =~ /\.svn/ }
22
+ s.files = files
23
+ end
24
+
25
+ if $0 == __FILE__
26
+ Gem::manage_gems
27
+ Gem::Builder.new(spec).build
28
+ end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: theme_support
3
+ version: !ruby/object:Gem::Version
4
+ hash: 7
5
+ prerelease: false
6
+ segments:
7
+ - 3
8
+ - 0
9
+ - 0
10
+ version: 3.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Pierre Yager and Sylvain Claudel
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-09-08 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: " ThemeSupport adds support for multi-themes to your Rails 3.0 application\n"
23
+ email: pierre@levosgien.net
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - lib/generators/theme/USAGE
32
+ - lib/generators/theme/templates/theme.css
33
+ - lib/generators/theme/templates/theme.yml
34
+ - lib/generators/theme/templates/layout.liquid
35
+ - lib/generators/theme/templates/views_readme
36
+ - lib/generators/theme/templates/layout.html.erb
37
+ - lib/generators/theme/templates/about.markdown
38
+ - lib/generators/theme/templates/preview.png
39
+ - lib/generators/theme/theme_generator.rb
40
+ - lib/theme_support.rb
41
+ - lib/theme_support/patches/abstractcontroller_ex.rb
42
+ - lib/theme_support/patches/routeset_ex.rb
43
+ - lib/theme_support/patches/actionmailer_ex.rb
44
+ - lib/theme_support/theme_controller.rb
45
+ - lib/theme_support/theme_helper.rb
46
+ - lib/theme_support/tasks.rb
47
+ - lib/theme_support/theme.rb
48
+ - lib/theme_support/railtie.rb
49
+ - lib/theme_support/theme_error.rb
50
+ - lib/theme_support/helpers/erb_theme_tags.rb
51
+ - lib/theme_support/helpers/liquid_theme_tags.rb
52
+ - Gemfile
53
+ - LICENSE
54
+ - README
55
+ - VERSION
56
+ - theme_support.gemspec
57
+ has_rdoc: true
58
+ homepage: http://github.com/zedalaye/theme_support
59
+ licenses: []
60
+
61
+ post_install_message:
62
+ rdoc_options: []
63
+
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 3
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ hash: 3
81
+ segments:
82
+ - 0
83
+ version: "0"
84
+ requirements: []
85
+
86
+ rubyforge_project: theme-support
87
+ rubygems_version: 1.3.7
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: add multi-themes support to Rails 3.0
91
+ test_files: []
92
+