theme_support 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
+