From 54063d6b46feea7a98048b3c61e38c439244091c Mon Sep 17 00:00:00 2001 From: dinedine Date: Mon, 11 Oct 2010 16:26:46 +0200 Subject: [PATCH] create a middleware for serving fonts (solve cross domain issue) + add cache for consume liquid tag + fix image picker --- .../admin/theme_assets_controller.rb | 9 ++-- app/models/theme_asset.rb | 8 ++++ app/views/admin/theme_assets/_asset.html.haml | 11 +++-- app/views/admin/theme_assets/images.html.haml | 8 ++-- config/application.rb | 3 ++ config/environments/development.rb | 4 +- doc/TODO | 3 +- lib/locomotive.rb | 2 +- lib/locomotive/liquid/filters/html.rb | 43 +++++++++++++----- lib/locomotive/liquid/tags/consume.rb | 18 ++++++-- lib/locomotive/middlewares.rb | 1 + lib/locomotive/middlewares/fonts.rb | 44 +++++++++++++++++++ lib/locomotive/render.rb | 2 +- public/javascripts/admin/pages.js | 2 +- .../javascripts/admin/plugins/imagepicker.js | 12 ++--- public/javascripts/admin/theme_assets.js | 2 +- public/stylesheets/admin/fancybox_changes.css | 5 ++- 17 files changed, 138 insertions(+), 39 deletions(-) create mode 100644 lib/locomotive/middlewares.rb create mode 100644 lib/locomotive/middlewares/fonts.rb diff --git a/app/controllers/admin/theme_assets_controller.rb b/app/controllers/admin/theme_assets_controller.rb index 2ca7bd52..b6f4adac 100644 --- a/app/controllers/admin/theme_assets_controller.rb +++ b/app/controllers/admin/theme_assets_controller.rb @@ -4,6 +4,7 @@ module Admin include ActionView::Helpers::SanitizeHelper extend ActionView::Helpers::SanitizeHelper::ClassMethods include ActionView::Helpers::TextHelper + include ActionView::Helpers::NumberHelper sections 'settings', 'theme_assets' @@ -15,6 +16,7 @@ module Admin @js_and_css_assets = (@assets[:javascripts] || []) + (@assets[:stylesheets] || []) if request.xhr? + @images = @assets[:images] render :action => 'images', :layout => false and return else @snippets = current_site.snippets.order_by([[:name, :asc]]).all.to_a @@ -33,9 +35,10 @@ module Admin success.json do render :json => { :status => 'success', - :name => truncate(@theme_asset.slug, :length => 22), - :slug => @theme_asset.slug, - :url => @theme_asset.source.url + :url => @theme_asset.source.url, + :local_path => @theme_asset.local_path(true), + :size => number_to_human_size(@theme_asset.size), + :date => l(@theme_asset.updated_at, :format => :short) } end failure.json { render :json => { :status => 'error' } } diff --git a/app/models/theme_asset.rb b/app/models/theme_asset.rb index dcd54148..14828fb6 100644 --- a/app/models/theme_asset.rb +++ b/app/models/theme_asset.rb @@ -49,6 +49,14 @@ class ThemeAsset self.stylesheet? || self.javascript? end + def local_path(short = false) + if short + self.read_attribute(:local_path).gsub(/^#{self.content_type.pluralize}\//, '') + else + self.read_attribute(:local_path) + end + end + def plain_text_name if not @plain_text_name_changed @plain_text_name ||= self.safe_source_filename diff --git a/app/views/admin/theme_assets/_asset.html.haml b/app/views/admin/theme_assets/_asset.html.haml index 320a436c..b6bee5ac 100644 --- a/app/views/admin/theme_assets/_asset.html.haml +++ b/app/views/admin/theme_assets/_asset.html.haml @@ -1,10 +1,13 @@ -%li{ :class => "#{'hidden' if asset.hidden?}" } +- edit = local_assigns.key?(:edit) ? edit : true + +%li{ :class => "#{asset.new_record? ? 'new-asset' : 'asset'} #{'hidden' if asset.hidden?}" } %em - %strong= link_to asset.local_path, edit_admin_theme_asset_path(asset) + %strong= link_to asset.local_path(!edit), edit ? edit_admin_theme_asset_path(asset) : asset.source.url, :'data-local-path' => asset.local_path .more %span.size= number_to_human_size(asset.size) — %span!= t('.updated_at') - = l asset.updated_at, :format => :short + %span.date= l asset.updated_at, :format => :short - = link_to image_tag('admin/list/icons/trash.png'), admin_theme_asset_path(asset), :class => 'remove', :confirm => t('admin.messages.confirm'), :method => :delete + - if edit + = link_to image_tag('admin/list/icons/trash.png'), admin_theme_asset_path(asset), :class => 'remove', :confirm => t('admin.messages.confirm'), :method => :delete diff --git a/app/views/admin/theme_assets/images.html.haml b/app/views/admin/theme_assets/images.html.haml index 38c87747..24c0195a 100644 --- a/app/views/admin/theme_assets/images.html.haml +++ b/app/views/admin/theme_assets/images.html.haml @@ -4,12 +4,12 @@ .actions = admin_button_tag t('admin.theme_assets.index.new'), admin_theme_assets_url(:json), :class => 'button small add', :id => 'upload-link' - - if @image_assets.empty? + - if @images.empty? %p.no-items!= t('.no_items') - %ul.assets - = render 'asset', :asset => current_site.theme_assets.build, :edit => false + %ul.list.theme-assets + = render 'asset', :asset => current_site.theme_assets.build(:updated_at => Time.now, :local_path => 'images/new.jpg', :content_type => 'image'), :edit => false - = render :partial => 'asset', :collection => @image_assets, :locals => { :per_row => 3, :edit => false } + = render :partial => 'asset', :collection => @images, :locals => { :edit => false } %li.clear \ No newline at end of file diff --git a/config/application.rb b/config/application.rb index 95b268ee..88d63d5c 100644 --- a/config/application.rb +++ b/config/application.rb @@ -46,5 +46,8 @@ module Locomotive # Configure sensitive parameters which will be filtered from the log file. config.filter_parameters << :password + + config.middleware.insert_after ::ActionDispatch::Static, '::Locomotive::Middlewares::Fonts', :path => %r{^/fonts} + # config.middleware.insert_after 'Rack::Lock', 'Dragonfly::Middleware' end end diff --git a/config/environments/development.rb b/config/environments/development.rb index 15590651..384d8225 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -4,14 +4,14 @@ Locomotive::Application.configure do # In the development environment your application's code is reloaded on # every request. This slows down response time but is perfect for development # since you don't have to restart the webserver when you make code changes. - config.cache_classes = false + config.cache_classes = true # false # Log error messages when you accidentally call methods on nil. config.whiny_nils = true # Show full error reports and disable caching config.consider_all_requests_local = true - config.action_controller.perform_caching = false + config.action_controller.perform_caching = true #false # Don't care if the mailer can't send config.action_mailer.raise_delivery_errors = false diff --git a/doc/TODO b/doc/TODO index df047e55..48d55ea7 100644 --- a/doc/TODO +++ b/doc/TODO @@ -38,7 +38,8 @@ x snippet dependencies => do not work correctly x mask internal asset_collections x refactor ui for the theme assets page x fix assets liquid tags / filters -- proxy for fonts +x upload and insert new images in a css or js from the ui is broken +x proxy for fonts (http://markevans.github.com/dragonfly/file.Rails3.html) - fix tests - order yaml file (http://www.ruby-forum.com/topic/120295) - global regions: keyword in editable element (http://www.mongodb.org/display/DOCS/Updating) diff --git a/lib/locomotive.rb b/lib/locomotive.rb index b08cb3f7..2ebf1499 100644 --- a/lib/locomotive.rb +++ b/lib/locomotive.rb @@ -1,4 +1,3 @@ -# require 'locomotive/patches' require 'locomotive/configuration' require 'locomotive/logger' require 'locomotive/liquid' @@ -14,6 +13,7 @@ require 'locomotive/regexps' require 'locomotive/render' require 'locomotive/import' require 'locomotive/delayed_job' +require 'locomotive/middlewares' require 'mongo_session_store/mongoid' diff --git a/lib/locomotive/liquid/filters/html.rb b/lib/locomotive/liquid/filters/html.rb index 5aea887b..4673ac06 100644 --- a/lib/locomotive/liquid/filters/html.rb +++ b/lib/locomotive/liquid/filters/html.rb @@ -9,13 +9,17 @@ module Locomotive return '' if input.nil? unless input =~ /^(\/|http:)/ - stylesheet = ThemeAsset.new(:site => @context.registers[:site], :folder => 'stylesheets') - input = '/' + ThemeAssetUploader.new(stylesheet).store_path(input) + segments = "stylesheets/#{input}".split('/') + + filename, folder = segments.pop, segments.join('/') + + stylesheet = ThemeAsset.new(:site => @context.registers[:site], :folder => folder) + + input = '/' + ThemeAssetUploader.new(stylesheet).store_path(filename) end - # puts "stylesheet_tag context ? #{@context}" - input = "#{input}.css" unless input.ends_with?('.css') + %{} end @@ -25,20 +29,39 @@ module Locomotive return '' if input.nil? unless input =~ /^(\/|http:)/ - javascript = ThemeAsset.new(:site => @context.registers[:site], :folder => 'javascripts') - input = '/' + ThemeAssetUploader.new(javascript).store_path(input) + segments = "javascripts/#{input}".split('/') + + filename, folder = segments.pop, segments.join('/') + + javascript = ThemeAsset.new(:site => @context.registers[:site], :folder => folder) + + input = '/' + ThemeAssetUploader.new(javascript).store_path(filename) end input = "#{input}.js" unless input.ends_with?('.js') + %{} end + def theme_image_url(input) + return '' if input.nil? + + input = "images/#{input}" unless input.starts_with?('/') + + segments = input.split('/') + + filename, folder = segments.pop, segments.join('/') + + image = ThemeAsset.new(:site => @context.registers[:site], :folder => folder) + + '/' + ThemeAssetUploader.new(image).store_path(filename) + end # Write an image tag # input: url of the image OR asset drop def image_tag(input, *args) image_options = inline_options(args_to_options(args)) - "" + "" end # Embed a flash movie into a page @@ -46,7 +69,7 @@ module Locomotive # width: width (in pixel or in %) of the embedded movie # height: height (in pixel or in %) of the embedded movie def flash_tag(input, *args) - path = get_path_from_asset(input) + path = get_url_from_asset(input) embed_options = inline_options(args_to_options(args)) %{ @@ -114,9 +137,9 @@ module Locomotive (options.stringify_keys.to_a.collect { |a, b| "#{a}=\"#{b}\"" }).join(' ') << ' ' end - # Get the path to be used in html tags such as image_tag, flash_tag, ...etc + # Get the url to be used in html tags such as image_tag, flash_tag, ...etc # input: url (String) OR asset drop - def get_path_from_asset(input) + def get_url_from_asset(input) input.respond_to?(:url) ? input.url : input end end diff --git a/lib/locomotive/liquid/tags/consume.rb b/lib/locomotive/liquid/tags/consume.rb index 32fddd34..dc02a79c 100644 --- a/lib/locomotive/liquid/tags/consume.rb +++ b/lib/locomotive/liquid/tags/consume.rb @@ -5,7 +5,7 @@ module Locomotive # # Usage: # - # {% consume blog from 'http://nocoffee.tumblr.com/api/read.json?num=3' username: 'john', password: 'easy', format: 'json' %} + # {% consume blog from 'http://nocoffee.tumblr.com/api/read.json?num=3' username: 'john', password: 'easy', format: 'json', expires_in: 3000 %} # {% for post in blog.posts %} # {{ post.title }} # {% endfor %} @@ -23,6 +23,8 @@ module Locomotive markup.scan(::Liquid::TagAttributes) do |key, value| @options[key] = value if key != 'http' end + @expires_in = (@options.delete('expires_in') || 0).to_i + @cache_key = Digest::SHA1.hexdigest(@target) else raise ::Liquid::SyntaxError.new("Syntax Error in 'consume' - Valid syntax: consume from \"\" [username: value, password: value]") end @@ -31,10 +33,18 @@ module Locomotive end def render(context) - context.stack do - context.scopes.last[@target.to_s] = Locomotive::Httparty::Webservice.consume(@url, @options.symbolize_keys) + render_all_and_cache_it(context) + end - render_all(@nodelist, context) + protected + + def render_all_and_cache_it(context) + Rails.cache.fetch(@cache_key, :expires_in => @expires_in) do + context.stack do + context.scopes.last[@target.to_s] = Locomotive::Httparty::Webservice.consume(@url, @options.symbolize_keys) + + render_all(@nodelist, context) + end end end diff --git a/lib/locomotive/middlewares.rb b/lib/locomotive/middlewares.rb new file mode 100644 index 00000000..e241b9d3 --- /dev/null +++ b/lib/locomotive/middlewares.rb @@ -0,0 +1 @@ +require 'locomotive/middlewares/fonts' \ No newline at end of file diff --git a/lib/locomotive/middlewares/fonts.rb b/lib/locomotive/middlewares/fonts.rb new file mode 100644 index 00000000..9eb986e4 --- /dev/null +++ b/lib/locomotive/middlewares/fonts.rb @@ -0,0 +1,44 @@ +require 'rack/utils' + +module Locomotive + module Middlewares + class Fonts + include Rack::Utils + + def initialize(app, opts = {}) + @app = app + @path_regexp = opts[:path] || %r{^/fonts/} + @file_server = ::Rack::File.new(opts[:root] || "#{Rails.root}/public") + @expires_in = opts[:expires_in] || 24.hour + end + + def call(env) + if env["PATH_INFO"] =~ @path_regexp + site = fetch_site(env['SERVER_NAME']) + + if site.nil? + @app.call(env) + else + env["PATH_INFO"] = ::File.join('/', 'sites', site.id.to_s, 'theme', env["PATH_INFO"]) + + response = @file_server.call(env) + + response[1]['Cache-Control'] = "public; max-age=#{@expires_in}" # varnish + + response + end + else + @app.call(env) + end + end + + protected + + def fetch_site(domain_name) + Rails.cache.fetch(domain_name, :expires_in => @expires_in) do + Site.match_domain(domain_name).first + end + end + end + end +end diff --git a/lib/locomotive/render.rb b/lib/locomotive/render.rb index ce992c9a..c3c94372 100644 --- a/lib/locomotive/render.rb +++ b/lib/locomotive/render.rb @@ -56,7 +56,7 @@ module Locomotive 'asset_collections' => Locomotive::Liquid::Drops::AssetCollections.new, 'stylesheets' => Locomotive::Liquid::Drops::ThemeAssets::Stylesheets.new, 'javascripts' => Locomotive::Liquid::Drops::ThemeAssets::Javascripts.new, - 'images' => Locomotive::Liquid::Drops::ThemeAssets::Images.new, + 'theme_images' => Locomotive::Liquid::Drops::ThemeAssets::Images.new, 'contents' => Locomotive::Liquid::Drops::Contents.new, 'current_page' => self.params[:page] } diff --git a/public/javascripts/admin/pages.js b/public/javascripts/admin/pages.js index a554ade6..8e98e133 100644 --- a/public/javascripts/admin/pages.js +++ b/public/javascripts/admin/pages.js @@ -80,7 +80,7 @@ $(document).ready(function() { if (typeof $.fn.imagepicker != 'undefined') $('a#image-picker-link').imagepicker({ insertFn: function(link) { - return "{{ theme_images." + link.attr('data-slug') + " }}"; + return "{{ '" + link.attr('data-local-path') + "' | theme_image_url }}"; } }); diff --git a/public/javascripts/admin/plugins/imagepicker.js b/public/javascripts/admin/plugins/imagepicker.js index 72ab2414..13f3de88 100644 --- a/public/javascripts/admin/plugins/imagepicker.js +++ b/public/javascripts/admin/plugins/imagepicker.js @@ -47,13 +47,13 @@ $.fn.imagepicker = function(options) { .insertBefore($('.asset-picker ul li.clear')) .addClass('asset'); - asset.find('h4 a').attr('href', json.url) - .attr('data-slug', json.slug) - .attr('data-shortcut-url', json.shortcut_url) - .html(json.name).bind('click', function(e) { + asset.find('strong a').attr('href', json.url) + .attr('data-local-path', json.local_path) + .html(json.local_path).bind('click', function(e) { copyLinkToEditor($(this), e); }); - asset.find('.image .inside img').attr('src', json.vignette_url); + asset.find('.more .size').html(json.size); + asset.find('.more .date').html(json.date); if ($('.asset-picker ul li.asset').length % 3 == 0) asset.addClass('last'); @@ -74,7 +74,7 @@ $.fn.imagepicker = function(options) { 'onComplete': function() { setupUploader(); - $('ul.assets h4 a').bind('click', function(e) { copyLinkToEditor($(this), e); }); + $('ul.theme-assets strong a').bind('click', function(e) { copyLinkToEditor($(this), e); }); } }); }); diff --git a/public/javascripts/admin/theme_assets.js b/public/javascripts/admin/theme_assets.js index 0c65c4b2..4dc5d977 100644 --- a/public/javascripts/admin/theme_assets.js +++ b/public/javascripts/admin/theme_assets.js @@ -37,7 +37,7 @@ $(document).ready(function() { $('a#image-picker-link').imagepicker({ insertFn: function(link) { - return link.attr('data-url'); + return link.attr('href'); } }); }); diff --git a/public/stylesheets/admin/fancybox_changes.css b/public/stylesheets/admin/fancybox_changes.css index 4b4290a1..3c91839a 100644 --- a/public/stylesheets/admin/fancybox_changes.css +++ b/public/stylesheets/admin/fancybox_changes.css @@ -49,7 +49,7 @@ /* ___ asset picker ___ */ -div.asset-picker { width: 470px; position: relative; } +div.asset-picker { width: 720px; position: relative; } div.asset-picker .actions { position: absolute; right: 4px; top: 0px; } div.asset-picker p.no-items { background-image: url("/images/admin/list/none-small.png"); } @@ -57,6 +57,9 @@ div.asset-picker p.no-items { background-image: url("/images/admin/list/none-sma div.asset-picker ul { overflow: auto; height: 471px; } div.asset-picker ul li.new-asset { display: none; } +div.asset-picker ul { margin: 0px; } +div.asset-picker ul li .more { top: 8px; } + /* ___ custom fields ___ */ #edit-custom-field {