theme_generator 1.1.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/USAGE +21 -0
- data/templates/README +55 -0
- data/templates/about.markdown +3 -0
- data/templates/actioncontroller_ex.rb +45 -0
- data/templates/actionview_ex.rb +21 -0
- data/templates/init.rb +6 -0
- data/templates/layout.rhtml +11 -0
- data/templates/preview.png +0 -0
- data/templates/routeset_ex.rb +22 -0
- data/templates/theme.css +5 -0
- data/templates/theme.rb +59 -0
- data/templates/theme_controller.rb +59 -0
- data/templates/theme_helpers.rb +69 -0
- data/theme_generator.rb +37 -0
- metadata +62 -0
data/USAGE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
NAME
|
2
|
+
theme - Initializes the application to support themes and creates a new theme
|
3
|
+
folder structure.
|
4
|
+
|
5
|
+
SYNOPSIS
|
6
|
+
theme [theme name]
|
7
|
+
|
8
|
+
DESCRIPTION
|
9
|
+
This generator creates general purpose theme support. It's designed to leverage
|
10
|
+
webservers for the static content of the theme (images, stylesheets, javascripts,
|
11
|
+
etc).
|
12
|
+
|
13
|
+
Included:
|
14
|
+
- Abstraction of Typo style theme support
|
15
|
+
- New View Tag Helpers for accessing themed content
|
16
|
+
|
17
|
+
EXAMPLE
|
18
|
+
./script/generate theme default
|
19
|
+
|
20
|
+
This will generate the file structure for a theme named 'default' and prepare
|
21
|
+
the rails application for theme support.
|
data/templates/README
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
== Usage
|
2
|
+
|
3
|
+
You can specify the current theme the same way you would a layout:
|
4
|
+
|
5
|
+
class ApplicationController < ActionController::Base
|
6
|
+
|
7
|
+
layout 'default'
|
8
|
+
theme 'blue'
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
If your application supports per-user themes, and the user's selected theme is
|
13
|
+
stored in the user object, you could implement that like this:
|
14
|
+
|
15
|
+
class ApplicationController < ActionController::Base
|
16
|
+
|
17
|
+
layout 'default'
|
18
|
+
theme :get_user_theme
|
19
|
+
|
20
|
+
# If a user is logged in, use their theme choice, otherwise
|
21
|
+
# use the theme named 'default'
|
22
|
+
def get_user_theme
|
23
|
+
return @session[:user].theme unless @session[:user].nil?
|
24
|
+
'default'
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
In the views, there are theme specific helper tags available to you.
|
30
|
+
|
31
|
+
- theme_image_tag
|
32
|
+
- theme_image_path
|
33
|
+
- theme_javascript_include_tag
|
34
|
+
- theme_javascript_path
|
35
|
+
- theme_stylesheet_link_tag
|
36
|
+
- theme_stylesheet_path
|
37
|
+
|
38
|
+
|
39
|
+
== In the future...
|
40
|
+
|
41
|
+
- Add a rake task to pre-cache all static theme files (stylesheets, images, and javascript)
|
42
|
+
- Add a rake task to remove all cached theme files
|
43
|
+
|
44
|
+
|
45
|
+
== Changelog
|
46
|
+
|
47
|
+
1.0.0 - Initial release
|
48
|
+
1.0.1 - Added 'themes' directory, theme definition file, and symlinks
|
49
|
+
to the appropriate directories on supported platforms.
|
50
|
+
1.0.2 - The current_theme is now retrieved from the controller. Where
|
51
|
+
symlinks are created on *nix systems, shortcuts are created
|
52
|
+
on Windows if Win32Utils is installed.
|
53
|
+
1.1.0 - [Breaking] Abstraction of the Typo theme system. The themes are
|
54
|
+
now the same as is used in Typo. The theme engine itself is a
|
55
|
+
combination of plugins and a component.
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# Extend the Base ActionController to support themes
|
2
|
+
#
|
3
|
+
ActionController::Base.class_eval do
|
4
|
+
|
5
|
+
attr_accessor :current_theme
|
6
|
+
|
7
|
+
def self.theme(theme_name, conditions = {})
|
8
|
+
# TODO: Allow conditions... (?)
|
9
|
+
write_inheritable_attribute "theme", theme_name
|
10
|
+
end
|
11
|
+
|
12
|
+
# You need to override this in your +ApplicationController+
|
13
|
+
# This should return the current theme name
|
14
|
+
def current_theme(passed_theme=nil)
|
15
|
+
theme = passed_theme || self.class.read_inheritable_attribute("theme")
|
16
|
+
|
17
|
+
active_theme = case theme
|
18
|
+
when Symbol then send(theme)
|
19
|
+
when Proc then theme.call(self)
|
20
|
+
when String then theme
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
alias_method :__active_layout, :active_layout
|
27
|
+
|
28
|
+
def active_layout(passed_layout = nil)
|
29
|
+
unless current_theme.nil?
|
30
|
+
puts "THEME LAYOUT"
|
31
|
+
layout = passed_layout || self.class.read_inheritable_attribute("layout")
|
32
|
+
|
33
|
+
active_layout = case layout
|
34
|
+
when Symbol then send(layout)
|
35
|
+
when Proc then layout.call(self)
|
36
|
+
when String then layout
|
37
|
+
end
|
38
|
+
|
39
|
+
active_layout.include?("/") ? active_layout : Theme.new(current_theme).layout(active_layout) if active_layout
|
40
|
+
else
|
41
|
+
__active_layout(passed_layout)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ActionView
|
2
|
+
class Base
|
3
|
+
alias_method :__render_file, :render_file
|
4
|
+
|
5
|
+
def render_file(template_path, use_full_path = true, local_assigns = {})
|
6
|
+
if use_full_path
|
7
|
+
begin
|
8
|
+
theme_path = "../../themes/#{controller.current_theme}/views/#{template_path}"
|
9
|
+
template_extension = pick_template_extension(theme_path)
|
10
|
+
__render_file(theme_path, use_full_path, local_assigns)
|
11
|
+
rescue => err
|
12
|
+
__render_file(template_path, use_full_path, local_assigns)
|
13
|
+
end
|
14
|
+
else
|
15
|
+
__render_file(template_path, use_full_path, local_assigns)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
end
|
data/templates/init.rb
ADDED
@@ -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 %>
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
<%%= @content_for_layout %>
|
10
|
+
</body>
|
11
|
+
</html>
|
Binary file
|
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
class ActionController::Routing::RouteSet
|
3
|
+
|
4
|
+
alias_method :__reload, :reload
|
5
|
+
|
6
|
+
def reload
|
7
|
+
__reload
|
8
|
+
create_theme_routes
|
9
|
+
end
|
10
|
+
|
11
|
+
def create_theme_routes
|
12
|
+
named_route 'theme_images', "/themes/:theme/images/:filename", :controller=>'theme_system/theme', :action=>'images'
|
13
|
+
named_route 'theme_stylesheets', "/themes/:theme/stylesheets/:filename", :controller=>'theme_system/theme', :action=>'stylesheets'
|
14
|
+
named_route 'theme_javascript', "/themes/:theme/javascript/:filename", :controller=>'theme_system/theme', :action=>'javascript'
|
15
|
+
|
16
|
+
connect "/themes/*", :controller=>'theme_system/theme', :action=>'error'
|
17
|
+
|
18
|
+
write_generation
|
19
|
+
write_recognition
|
20
|
+
ActionController::Routing::NamedRoutes.install
|
21
|
+
end
|
22
|
+
end
|
data/templates/theme.css
ADDED
data/templates/theme.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
class Theme
|
2
|
+
cattr_accessor :cache_theme_lookup
|
3
|
+
@@cache_theme_lookup = false
|
4
|
+
|
5
|
+
attr_accessor :name, :path, :description_html
|
6
|
+
|
7
|
+
def initialize(name, path=nil)
|
8
|
+
@name = name
|
9
|
+
@path = path ||= Theme.path_to_theme(name)
|
10
|
+
end
|
11
|
+
|
12
|
+
def layout(layout='default')
|
13
|
+
"../../themes/#{name}/layouts/#{layout}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def description
|
17
|
+
File.read("#{path}/about.markdown") rescue "### #{name}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.themes_root
|
21
|
+
RAILS_ROOT + "/themes"
|
22
|
+
end
|
23
|
+
|
24
|
+
# DEPRECATED: There is no 'current' theme, at least, not from here...
|
25
|
+
def self.current_theme_path
|
26
|
+
raise 'DEPRECATED: The current theme is set in the controller'
|
27
|
+
"#{themes_root}/#{config[:theme]}"
|
28
|
+
end
|
29
|
+
# DEPRECATED: There is no 'current' theme, at least, not from here...
|
30
|
+
def self.current
|
31
|
+
theme_from_path(current_theme_path)
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def self.path_to_theme(theme)
|
36
|
+
"#{themes_root}/#{theme}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.theme_from_path(path)
|
40
|
+
name = path.scan(/[-\w]+$/i).flatten.first
|
41
|
+
self.new(name, path)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.find_all
|
45
|
+
installed_themes.inject([]) do |array, path|
|
46
|
+
array << theme_from_path(path)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.installed_themes
|
51
|
+
cache_theme_lookup ? @theme_cache ||= search_theme_directory : search_theme_directory
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.search_theme_directory
|
55
|
+
Dir.glob("#{themes_root}/[-_a-zA-Z0-9]*").collect do |file|
|
56
|
+
file if File.directory?(file)
|
57
|
+
end.compact
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
class ThemeSystem::ThemeController < ActionController::Base
|
2
|
+
|
3
|
+
after_filter :cache_theme_files
|
4
|
+
|
5
|
+
def stylesheets
|
6
|
+
render_theme_item(:stylesheets, params[:filename], params[:theme], 'text/css')
|
7
|
+
end
|
8
|
+
|
9
|
+
def javascript
|
10
|
+
render_theme_item(:javascript, params[:filename], params[:theme], 'text/javascript')
|
11
|
+
end
|
12
|
+
|
13
|
+
def images
|
14
|
+
render_theme_item(:images, params[:filename], params[:theme])
|
15
|
+
end
|
16
|
+
|
17
|
+
def error
|
18
|
+
render :nothing => true, :status => 404
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def render_theme_item(type, file, theme, mime = mime_for(file))
|
24
|
+
render :text => "Not Found", :status => 404 and return if file.split(%r{[\\/]}).include?("..")
|
25
|
+
send_file "#{Theme.path_to_theme(theme)}/#{type}/#{file}", :type => mime, :disposition => 'inline', :stream => false
|
26
|
+
end
|
27
|
+
|
28
|
+
def cache_theme_files
|
29
|
+
path = request.request_uri
|
30
|
+
begin
|
31
|
+
ThemeSystem::ThemeController.cache_page( response.body, path )
|
32
|
+
rescue
|
33
|
+
#STERR.puts "Cache Exception: #{$!}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def mime_for(filename)
|
39
|
+
case filename.downcase
|
40
|
+
when /\.js$/
|
41
|
+
'text/javascript'
|
42
|
+
when /\.css$/
|
43
|
+
'text/css'
|
44
|
+
when /\.gif$/
|
45
|
+
'image/gif'
|
46
|
+
when /(\.jpg|\.jpeg)$/
|
47
|
+
'image/jpeg'
|
48
|
+
when /\.png$/
|
49
|
+
'image/png'
|
50
|
+
when /\.swf$/
|
51
|
+
'application/x-shockwave-flash'
|
52
|
+
else
|
53
|
+
'application/binary'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
end
|
59
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
#
|
2
|
+
# These are theme helper tags
|
3
|
+
#
|
4
|
+
module ActionView
|
5
|
+
module Helpers
|
6
|
+
module AssetTagHelper
|
7
|
+
|
8
|
+
# TODO: Convert these to user the named route helpers (?)
|
9
|
+
|
10
|
+
# returns the public path to a theme stylesheet
|
11
|
+
def theme_stylesheet_path( source=nil, theme=nil )
|
12
|
+
theme = theme || controller.current_theme
|
13
|
+
compute_public_path(source || "theme", "themes/#{theme}/stylesheets", 'css')
|
14
|
+
end
|
15
|
+
|
16
|
+
# returns the path to a theme image
|
17
|
+
def theme_image_path( source, theme=nil )
|
18
|
+
theme = theme || controller.current_theme
|
19
|
+
compute_public_path(source, "themes/#{theme}/images", 'png')
|
20
|
+
end
|
21
|
+
|
22
|
+
# returns the path to a theme javascript
|
23
|
+
def theme_javascript_path( source, theme=nil )
|
24
|
+
theme = theme || controller.current_theme
|
25
|
+
compute_public_path(source, "themes/#{theme}/javascript", 'js')
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
# This tag it will automatially include the 'theme' css, plus any other
|
30
|
+
# stylesheets you include in the params...
|
31
|
+
# This doesn't support overriding the Theme -- it will use the current theme
|
32
|
+
def theme_stylesheet_link_tag(*sources)
|
33
|
+
sources << controller.current_theme.to_s
|
34
|
+
sources.uniq!
|
35
|
+
options = sources.last.is_a?(Hash) ? sources.pop.stringify_keys : { }
|
36
|
+
sources.collect { |source|
|
37
|
+
source = theme_stylesheet_path(source)
|
38
|
+
tag("link", { "rel" => "Stylesheet", "type" => "text/css", "media" => "screen", "href" => source }.merge(options))
|
39
|
+
}.join("\n")
|
40
|
+
end
|
41
|
+
|
42
|
+
# This tag will return a theme-specific IMG
|
43
|
+
def theme_image_tag(source, options = {})
|
44
|
+
options.symbolize_keys
|
45
|
+
|
46
|
+
options[:src] = theme_image_path(source)
|
47
|
+
options[:alt] ||= File.basename(options[:src], '.*').split('.').first.capitalize
|
48
|
+
|
49
|
+
if options[:size]
|
50
|
+
options[:width], options[:height] = options[:size].split("x")
|
51
|
+
options.delete :size
|
52
|
+
end
|
53
|
+
|
54
|
+
tag("img", options)
|
55
|
+
end
|
56
|
+
|
57
|
+
# This tag can be used to return theme-specific javscripts
|
58
|
+
def theme_javascript_include_tag(*sources)
|
59
|
+
options = sources.last.is_a?(Hash) ? sources.pop.stringify_keys : { }
|
60
|
+
sources = ['prototype', 'effects', 'controls', 'dragdrop'] if sources.first == :defaults
|
61
|
+
sources.collect { |source|
|
62
|
+
source = theme_javascript_path(source)
|
63
|
+
content_tag("script", "", { "type" => "text/javascript", "src" => source }.merge(options))
|
64
|
+
}.join("\n")
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/theme_generator.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
class ThemeGenerator < Rails::Generator::NamedBase
|
2
|
+
def manifest
|
3
|
+
record do |m|
|
4
|
+
# Readme file
|
5
|
+
m.template 'README', "README_THEMES"
|
6
|
+
|
7
|
+
# Theme folder(s)
|
8
|
+
m.directory File.join( "themes", file_name )
|
9
|
+
m.template 'about.markdown', File.join( 'themes', file_name, 'about.markdown' )
|
10
|
+
m.template 'preview.png', File.join( 'themes', file_name, 'preview.png' )
|
11
|
+
|
12
|
+
m.directory File.join( "themes", file_name, "stylesheets" )
|
13
|
+
m.template "theme.css", File.join( "themes", file_name, "stylesheets", "#{file_name}.css" )
|
14
|
+
|
15
|
+
m.directory File.join( "themes", file_name, "layouts" )
|
16
|
+
m.template 'layout.rhtml', File.join( 'themes', file_name, 'layouts', 'default.rhtml' )
|
17
|
+
|
18
|
+
m.directory File.join( "themes", file_name, "views" )
|
19
|
+
m.directory File.join( "themes", file_name, "images" )
|
20
|
+
m.directory File.join( "themes", file_name, "javascript" )
|
21
|
+
|
22
|
+
# The ThemeEngine plugins
|
23
|
+
m.directory File.join( "vendor", "plugins", "theme_engine" )
|
24
|
+
m.template 'init.rb', File.join( 'vendor', 'plugins', 'theme_engine', 'init.rb' )
|
25
|
+
m.directory File.join( "vendor", "plugins", "theme_engine", "lib" )
|
26
|
+
m.template 'actioncontroller_ex.rb', File.join( 'vendor', 'plugins', 'theme_engine', 'lib', 'actioncontroller_ex.rb' )
|
27
|
+
m.template 'actionview_ex.rb', File.join( 'vendor', 'plugins', 'theme_engine', 'lib', 'actionview_ex.rb' )
|
28
|
+
m.template 'routeset_ex.rb', File.join( 'vendor', 'plugins', 'theme_engine', 'lib', 'routeset_ex.rb' )
|
29
|
+
m.template 'theme_helpers.rb', File.join( 'vendor', 'plugins', 'theme_engine', 'lib', 'theme_helpers.rb' )
|
30
|
+
|
31
|
+
# The ThemeSystem Component
|
32
|
+
m.directory File.join( "components", "theme_system" )
|
33
|
+
m.template 'theme.rb', File.join( 'components', 'theme_system', 'theme.rb' )
|
34
|
+
m.template 'theme_controller.rb', File.join( 'components', 'theme_system', 'theme_controller.rb' )
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11
|
3
|
+
specification_version: 1
|
4
|
+
name: theme_generator
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 1.1.0
|
7
|
+
date: 2005-10-27 00:00:00 -05:00
|
8
|
+
summary: "[Rails] Theme generator adds support for themes into Rails applications"
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: darthapo@gmail.com
|
12
|
+
homepage: http://www.mattmccray.com
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: false
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
-
|
22
|
+
- ">"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.0.0
|
25
|
+
version:
|
26
|
+
platform: ruby
|
27
|
+
signing_key:
|
28
|
+
cert_chain:
|
29
|
+
authors:
|
30
|
+
- M@ McCray
|
31
|
+
files:
|
32
|
+
- templates/README
|
33
|
+
- templates/actionview_ex.rb
|
34
|
+
- templates/preview.png
|
35
|
+
- templates/theme.rb
|
36
|
+
- templates/about.markdown
|
37
|
+
- templates/init.rb
|
38
|
+
- templates/routeset_ex.rb
|
39
|
+
- templates/theme_controller.rb
|
40
|
+
- templates/actioncontroller_ex.rb
|
41
|
+
- templates/layout.rhtml
|
42
|
+
- templates/theme.css
|
43
|
+
- templates/theme_helpers.rb
|
44
|
+
- USAGE
|
45
|
+
- theme_generator.rb
|
46
|
+
test_files: []
|
47
|
+
rdoc_options: []
|
48
|
+
extra_rdoc_files: []
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
requirements: []
|
52
|
+
dependencies:
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: rails
|
55
|
+
version_requirement:
|
56
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
57
|
+
requirements:
|
58
|
+
-
|
59
|
+
- ">"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.0.0
|
62
|
+
version:
|