active_theme 0.5.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/.rspec +2 -0
- data/.rvmrc +1 -0
- data/.travis.yml +2 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +91 -0
- data/LICENSE +21 -0
- data/README.textile +3 -0
- data/Rakefile +11 -0
- data/active_theme.gemspec +25 -0
- data/doc/README.textile +332 -0
- data/doc/REVIEW_NOTES +0 -0
- data/doc/TODO.textile +3 -0
- data/lib/active_theme.rb +58 -0
- data/lib/active_theme/action_controller.rb +32 -0
- data/lib/active_theme/action_mailer.rb +22 -0
- data/lib/active_theme/action_view.rb +59 -0
- data/lib/active_theme/assets_controller.rb +66 -0
- data/lib/active_theme/common_methods.rb +66 -0
- data/lib/active_theme/config.rb +74 -0
- data/lib/active_theme/interpolation.rb +11 -0
- data/lib/active_theme/railtie.rb +32 -0
- data/lib/active_theme/routes.rb +27 -0
- data/lib/active_theme/url_helpers.rb +27 -0
- data/lib/active_theme/version.rb +4 -0
- data/lib/generators/active_theme/create_generator.rb +14 -0
- data/lib/generators/active_theme/install_generator.rb +16 -0
- data/lib/generators/active_theme/templates/theme/images/.gitkeep +0 -0
- data/lib/generators/active_theme/templates/theme/javascripts/.gitkeep +0 -0
- data/lib/generators/active_theme/templates/theme/stylesheets/.gitkeep +0 -0
- data/lib/generators/active_theme/templates/theme/views/layouts/.gitkeep +0 -0
- data/lib/tasks/active_theme.rake +22 -0
- data/test/dummy_app/.gitignore +4 -0
- data/test/dummy_app/Gemfile +30 -0
- data/test/dummy_app/Rakefile +7 -0
- data/test/dummy_app/another_themes/another_default/images/logo.png +0 -0
- data/test/dummy_app/another_themes/another_default/images/nested/logo.png +0 -0
- data/test/dummy_app/another_themes/another_default/javascripts/app.js +1 -0
- data/test/dummy_app/another_themes/another_default/stylesheets/style.css +0 -0
- data/test/dummy_app/another_themes/another_default/stylesheets/style2.css +3 -0
- data/test/dummy_app/another_themes/another_default/views/layouts/default.html.erb +10 -0
- data/test/dummy_app/another_themes/another_default/views/products/index.html.erb +0 -0
- data/test/dummy_app/app/controllers/application_controller.rb +3 -0
- data/test/dummy_app/app/helpers/application_helper.rb +2 -0
- data/test/dummy_app/app/views/layouts/application.html.erb +14 -0
- data/test/dummy_app/config.ru +4 -0
- data/test/dummy_app/config/application.rb +42 -0
- data/test/dummy_app/config/boot.rb +13 -0
- data/test/dummy_app/config/database.yml +18 -0
- data/test/dummy_app/config/environment.rb +5 -0
- data/test/dummy_app/config/environments/development.rb +26 -0
- data/test/dummy_app/config/environments/production.rb +49 -0
- data/test/dummy_app/config/environments/test.rb +35 -0
- data/test/dummy_app/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy_app/config/initializers/inflections.rb +10 -0
- data/test/dummy_app/config/initializers/mime_types.rb +5 -0
- data/test/dummy_app/config/initializers/secret_token.rb +7 -0
- data/test/dummy_app/config/initializers/session_store.rb +8 -0
- data/test/dummy_app/config/locales/en.yml +5 -0
- data/test/dummy_app/config/routes.rb +4 -0
- data/test/dummy_app/db/seeds.rb +7 -0
- data/test/dummy_app/empty_themes/.gitkeep +0 -0
- data/test/dummy_app/lib/tasks/.gitkeep +0 -0
- data/test/dummy_app/public/404.html +26 -0
- data/test/dummy_app/public/422.html +26 -0
- data/test/dummy_app/public/500.html +26 -0
- data/test/dummy_app/public/favicon.ico +0 -0
- data/test/dummy_app/public/images/rails.png +0 -0
- data/test/dummy_app/public/index.html +239 -0
- data/test/dummy_app/public/javascripts/application.js +2 -0
- data/test/dummy_app/public/javascripts/controls.js +965 -0
- data/test/dummy_app/public/javascripts/dragdrop.js +974 -0
- data/test/dummy_app/public/javascripts/effects.js +1123 -0
- data/test/dummy_app/public/javascripts/prototype.js +6001 -0
- data/test/dummy_app/public/javascripts/rails.js +175 -0
- data/test/dummy_app/public/robots.txt +5 -0
- data/test/dummy_app/public/stylesheets/.gitkeep +0 -0
- data/test/dummy_app/script/rails +6 -0
- data/test/dummy_app/themes/default/images/logo.png +0 -0
- data/test/dummy_app/themes/default/images/nested/logo.png +0 -0
- data/test/dummy_app/themes/default/javascripts/app.js +1 -0
- data/test/dummy_app/themes/default/javascripts/app.min.js +0 -0
- data/test/dummy_app/themes/default/stylesheets/images/logo.png +0 -0
- data/test/dummy_app/themes/default/stylesheets/style.css +0 -0
- data/test/dummy_app/themes/default/stylesheets/style2.css +3 -0
- data/test/dummy_app/themes/default/views/layouts/default.html.erb +10 -0
- data/test/dummy_app/themes/default/views/products/index.html.erb +0 -0
- data/test/lib/action_controller_test.rb +170 -0
- data/test/lib/action_mailer_test.rb +35 -0
- data/test/lib/action_view_test.rb +54 -0
- data/test/lib/assets_controller_test.rb +73 -0
- data/test/lib/common_methods_test.rb +28 -0
- data/test/lib/config_test.rb +26 -0
- data/test/lib/integration_test.rb +12 -0
- data/test/lib/routes_test.rb +40 -0
- data/test/lib/themes_for_rails_test.rb +18 -0
- data/test/support/extensions.rb +19 -0
- data/test/test_helper.rb +12 -0
- metadata +276 -0
data/doc/REVIEW_NOTES
ADDED
File without changes
|
data/doc/TODO.textile
ADDED
data/lib/active_theme.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module ActiveTheme
|
3
|
+
|
4
|
+
class << self
|
5
|
+
|
6
|
+
def config
|
7
|
+
@config ||= ActiveTheme::Config.new
|
8
|
+
yield(@config) if block_given?
|
9
|
+
@config
|
10
|
+
end
|
11
|
+
|
12
|
+
def available_themes(&block)
|
13
|
+
Dir.glob(File.join(config.themes_path, "*"), &block)
|
14
|
+
end
|
15
|
+
alias each_theme_dir available_themes
|
16
|
+
|
17
|
+
def available_theme_names
|
18
|
+
available_themes.map {|theme| File.basename(theme) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_themes_path_to_sass
|
22
|
+
if ActiveTheme.config.sass_is_available?
|
23
|
+
each_theme_dir do |dir|
|
24
|
+
if File.directory?(dir) # Need to get rid of the '.' and '..'
|
25
|
+
|
26
|
+
sass_dir = "#{dir}/stylesheets/sass"
|
27
|
+
css_dir = "#{dir}/stylesheets"
|
28
|
+
|
29
|
+
unless already_configured_in_sass?(sass_dir)
|
30
|
+
Sass::Plugin.add_template_location sass_dir, css_dir
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
else
|
35
|
+
raise "Sass is not available. What are you trying to do?"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def already_configured_in_sass?(sass_dir)
|
40
|
+
Sass::Plugin.template_location_array.map(&:first).include?(sass_dir)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
require 'active_support/dependencies'
|
47
|
+
require 'active_theme/interpolation'
|
48
|
+
require 'active_theme/config'
|
49
|
+
require 'active_theme/common_methods'
|
50
|
+
require 'active_theme/url_helpers'
|
51
|
+
|
52
|
+
require 'active_theme/action_view'
|
53
|
+
require 'active_theme/assets_controller'
|
54
|
+
require 'active_theme/action_controller'
|
55
|
+
require 'active_theme/action_mailer'
|
56
|
+
require 'active_theme/railtie'
|
57
|
+
require 'active_theme/routes'
|
58
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module ActiveTheme
|
3
|
+
|
4
|
+
module ActionController
|
5
|
+
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
|
10
|
+
include ActiveTheme::CommonMethods
|
11
|
+
include ActiveTheme::UrlHelpers
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
|
17
|
+
def theme(name, options = {})
|
18
|
+
before_filter(options) do |controller|
|
19
|
+
controller.set_theme(name)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
def theme(name)
|
26
|
+
set_theme(name)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module ActiveTheme
|
3
|
+
|
4
|
+
module ActionMailer
|
5
|
+
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
include ActiveTheme::ActionController
|
10
|
+
alias_method_chain :mail, :theme
|
11
|
+
end
|
12
|
+
|
13
|
+
def mail_with_theme(headers = {}, &block)
|
14
|
+
theme_opts = headers[:theme] || self.class.default[:theme]
|
15
|
+
theme(theme_opts) if theme_opts
|
16
|
+
|
17
|
+
mail_without_theme(headers, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module ActiveTheme
|
3
|
+
|
4
|
+
module ActionView
|
5
|
+
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
include ActiveTheme::CommonMethods
|
10
|
+
end
|
11
|
+
|
12
|
+
def current_theme_stylesheet_path(asset)
|
13
|
+
base_theme_stylesheet_path(:theme => self.theme_name, :asset => "#{asset}.css")
|
14
|
+
end
|
15
|
+
|
16
|
+
def current_theme_javascript_path(asset)
|
17
|
+
base_theme_javascript_path(:theme => self.theme_name, :asset => "#{asset}.js")
|
18
|
+
end
|
19
|
+
|
20
|
+
def current_theme_image_path(asset)
|
21
|
+
base_theme_image_path(:theme => self.theme_name, :asset => asset)
|
22
|
+
end
|
23
|
+
|
24
|
+
def theme_stylesheet_path(asset, new_theme_name = self.theme_name)
|
25
|
+
base_theme_stylesheet_path(:theme => new_theme_name, :asset => "#{asset}.css")
|
26
|
+
end
|
27
|
+
|
28
|
+
def theme_javascript_path(asset, new_theme_name = self.theme_name)
|
29
|
+
base_theme_javascript_path(:theme => new_theme_name, :asset => "#{asset}.js")
|
30
|
+
end
|
31
|
+
|
32
|
+
def theme_image_path(asset, new_theme_name = self.theme_name)
|
33
|
+
base_theme_image_path(:theme => new_theme_name, :asset => asset)
|
34
|
+
end
|
35
|
+
|
36
|
+
def theme_image_tag(source, options = {})
|
37
|
+
image_tag(theme_image_path(source), options)
|
38
|
+
end
|
39
|
+
|
40
|
+
def theme_image_submit_tag(source, options = {})
|
41
|
+
image_submit_tag(theme_image_path(source), options)
|
42
|
+
end
|
43
|
+
|
44
|
+
def theme_javascript_include_tag(*files)
|
45
|
+
options = files.extract_options!
|
46
|
+
options.merge!({ :type => "text/javascript" })
|
47
|
+
files.collect! {|file| theme_javascript_path(file) }
|
48
|
+
javascript_include_tag(*files, options)
|
49
|
+
end
|
50
|
+
|
51
|
+
def theme_stylesheet_link_tag(*files)
|
52
|
+
options = files.extract_options!
|
53
|
+
options.merge!({ :type => "text/css" })
|
54
|
+
files.collect! {|file| theme_stylesheet_path(file) }
|
55
|
+
stylesheet_link_tag(*files, options)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "action_controller/metal"
|
3
|
+
|
4
|
+
module ActiveTheme
|
5
|
+
class AssetsController < ActionController::Base
|
6
|
+
|
7
|
+
def stylesheets
|
8
|
+
handle_asset("stylesheets")
|
9
|
+
end
|
10
|
+
|
11
|
+
def javascripts
|
12
|
+
handle_asset("javascripts")
|
13
|
+
end
|
14
|
+
|
15
|
+
def images
|
16
|
+
handle_asset("images")
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def handle_asset(prefix)
|
22
|
+
asset, theme = params[:asset], params[:theme]
|
23
|
+
find_themed_asset(asset, theme, prefix) do |path, mime_type|
|
24
|
+
send_file path, :type => mime_type, :disposition => "inline"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def find_themed_asset(asset_name, asset_theme, asset_type, &block)
|
29
|
+
path = asset_path(asset_name, asset_theme, asset_type)
|
30
|
+
if File.exists?(path)
|
31
|
+
yield path, mime_type_for(request)
|
32
|
+
elsif File.extname(path).blank?
|
33
|
+
asset_name = "#{asset_name}.#{extension_from(request.path_info)}"
|
34
|
+
return find_themed_asset(asset_name, asset_theme, asset_type, &block)
|
35
|
+
else
|
36
|
+
render_not_found
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def asset_path(asset_name, asset_theme, asset_type)
|
41
|
+
File.join(theme_asset_path_for(asset_theme), asset_type, asset_name)
|
42
|
+
end
|
43
|
+
|
44
|
+
def render_not_found
|
45
|
+
render :text => 'Not found', :status => 404
|
46
|
+
end
|
47
|
+
|
48
|
+
def mime_type_for(request)
|
49
|
+
existing_mime_type = mime_type_from_uri(request.path_info)
|
50
|
+
unless existing_mime_type.nil?
|
51
|
+
existing_mime_type.to_s
|
52
|
+
else
|
53
|
+
"image/#{extension_from(request.path_info)}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def mime_type_from_uri(path)
|
58
|
+
extension = extension_from(path)
|
59
|
+
Mime::Type.lookup_by_extension(extension)
|
60
|
+
end
|
61
|
+
|
62
|
+
def extension_from(path)
|
63
|
+
File.extname(path).to_s[1..-1]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module ActiveTheme
|
3
|
+
module CommonMethods
|
4
|
+
|
5
|
+
include ActiveTheme::Interpolation
|
6
|
+
|
7
|
+
def theme_name
|
8
|
+
@cached_theme_name ||= begin
|
9
|
+
case @theme_name
|
10
|
+
when Symbol then
|
11
|
+
self.respond_to?(@theme_name, true) ? self.send(@theme_name) : @theme_name.to_s
|
12
|
+
when String then @theme_name
|
13
|
+
else
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def theme_name=(name)
|
20
|
+
@theme_name = name
|
21
|
+
end
|
22
|
+
|
23
|
+
def set_theme(name)
|
24
|
+
self.theme_name = name
|
25
|
+
if valid_theme?
|
26
|
+
add_theme_view_path
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
public
|
31
|
+
|
32
|
+
def valid_theme?
|
33
|
+
!self.theme_name.nil?
|
34
|
+
end
|
35
|
+
|
36
|
+
# will add the view path for the current theme
|
37
|
+
def add_theme_view_path
|
38
|
+
add_theme_view_path_for(self.theme_name)
|
39
|
+
end
|
40
|
+
|
41
|
+
# will add the view path for a given theme name
|
42
|
+
def add_theme_view_path_for(name)
|
43
|
+
self.view_paths.insert 0, ::ActionView::FileSystemResolver.new(theme_view_path_for(name))
|
44
|
+
end
|
45
|
+
|
46
|
+
def public_theme_path
|
47
|
+
theme_view_path("/")
|
48
|
+
end
|
49
|
+
|
50
|
+
def theme_asset_path
|
51
|
+
theme_asset_path_for(theme_name)
|
52
|
+
end
|
53
|
+
|
54
|
+
def theme_view_path
|
55
|
+
theme_view_path_for(theme_name)
|
56
|
+
end
|
57
|
+
|
58
|
+
def theme_view_path_for(theme_name)
|
59
|
+
interpolate(ActiveTheme.config.views_dir, theme_name)
|
60
|
+
end
|
61
|
+
|
62
|
+
def theme_asset_path_for(theme_name)
|
63
|
+
interpolate(ActiveTheme.config.assets_dir, theme_name)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module ActiveTheme
|
3
|
+
class Config
|
4
|
+
|
5
|
+
attr_writer :base_dir, :themes_dir, :assets_dir, :views_dir, :themes_routes_dir
|
6
|
+
attr_accessor :use_sass, :default_theme
|
7
|
+
|
8
|
+
include Interpolation
|
9
|
+
|
10
|
+
def initialize(&block)
|
11
|
+
@use_sass = true
|
12
|
+
@default_theme = 'default'
|
13
|
+
yield if block_given?
|
14
|
+
end
|
15
|
+
|
16
|
+
def base_dir
|
17
|
+
@base_dir ||= Rails.root.to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
# relative assets dir for view overloading support
|
21
|
+
# used for theme_view_path_for method to get theme path and add to view paths.
|
22
|
+
# Defaults to themes_dir for non asset pipeline users
|
23
|
+
#
|
24
|
+
# If you are using the Rails Asset Pipeline, this should be changed to the
|
25
|
+
# path of your assets in your app. For example, if you store your themes
|
26
|
+
# under /app/assets/themes - {Rails.root}/app/assets/themes
|
27
|
+
# you would need to set this to 'app/assets/themes' in your initializer config
|
28
|
+
def assets_dir
|
29
|
+
@assets_dir ||= ":root/themes/:name"
|
30
|
+
end
|
31
|
+
|
32
|
+
# relative views directory for theme views to be separated from assets
|
33
|
+
# used for Asset Pipeline support. Defaults to match {assets_dir}/views
|
34
|
+
def views_dir
|
35
|
+
@views_dir ||= ":root/themes/:name/views"
|
36
|
+
end
|
37
|
+
|
38
|
+
def themes_dir
|
39
|
+
@themes_dir ||= ":root/themes"
|
40
|
+
end
|
41
|
+
|
42
|
+
# Full path to themes
|
43
|
+
def themes_path
|
44
|
+
interpolate(themes_dir)
|
45
|
+
end
|
46
|
+
|
47
|
+
# This is the base themes dir that is used for mapping URL paths.
|
48
|
+
#
|
49
|
+
# If you are using the Rails Asset Pipeline, this should be changed to the
|
50
|
+
# prefix dir of your assets path. For example, if you store your themes
|
51
|
+
# under /app/assets/themes - {Rails.root}/app/assets/themes
|
52
|
+
# you would need to set this value to 'assets' to match up with the Sprockets
|
53
|
+
# path resolution process.
|
54
|
+
|
55
|
+
def themes_routes_dir
|
56
|
+
@themes_routes_dir ||= "themes"
|
57
|
+
end
|
58
|
+
|
59
|
+
def clear
|
60
|
+
@base_dir = nil
|
61
|
+
@themes_dir = nil
|
62
|
+
@assets_dir = nil
|
63
|
+
@views_dir = nil
|
64
|
+
end
|
65
|
+
|
66
|
+
def use_sass?
|
67
|
+
@use_sass and sass_is_available?
|
68
|
+
end
|
69
|
+
|
70
|
+
def sass_is_available?
|
71
|
+
!!defined?Sass::Plugin
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module ActiveTheme
|
3
|
+
class Railtie < ::Rails::Railtie
|
4
|
+
|
5
|
+
config.active_theme = ActiveSupport::OrderedOptions.new
|
6
|
+
|
7
|
+
config.to_prepare do
|
8
|
+
ActiveTheme::Railtie.config.active_theme.each do |key, value|
|
9
|
+
ActiveTheme.config.send "#{key}=".to_sym, value
|
10
|
+
end
|
11
|
+
|
12
|
+
# Adding theme stylesheets path to sass, automatically.
|
13
|
+
ActiveTheme.add_themes_path_to_sass if ActiveTheme.config.use_sass?
|
14
|
+
|
15
|
+
ActiveSupport.on_load(:action_view) do
|
16
|
+
include ActiveTheme::ActionView
|
17
|
+
end
|
18
|
+
|
19
|
+
ActiveSupport.on_load(:action_controller) do
|
20
|
+
include ActiveTheme::ActionController
|
21
|
+
end
|
22
|
+
|
23
|
+
ActiveSupport.on_load(:action_mailer) do
|
24
|
+
include ActiveTheme::ActionMailer
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
rake_tasks do
|
29
|
+
load "tasks/active_theme.rake"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module ActiveTheme
|
3
|
+
module Routes
|
4
|
+
|
5
|
+
def active_theme
|
6
|
+
theme_dir = ActiveTheme.config.themes_routes_dir
|
7
|
+
constraints = { :theme => /[\w\.]*/ }
|
8
|
+
|
9
|
+
match "#{theme_dir}/:theme/stylesheets/*asset" => 'active_theme/assets#stylesheets',
|
10
|
+
:as => :base_theme_stylesheet, :constraints => constraints
|
11
|
+
match "#{theme_dir}/:theme/javascripts/*asset" => 'active_theme/assets#javascripts',
|
12
|
+
:as => :base_theme_javascript, :constraints => constraints
|
13
|
+
match "#{theme_dir}/:theme/images/*asset" => 'active_theme/assets#images',
|
14
|
+
:as => :base_theme_image, :constraints => constraints
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module ActionDispatch::Routing
|
21
|
+
class Mapper #:nodoc:
|
22
|
+
|
23
|
+
include ActiveTheme::Routes
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|