create a middleware for serving fonts (solve cross domain issue) + add cache for consume liquid tag + fix image picker

This commit is contained in:
dinedine 2010-10-11 16:26:46 +02:00
parent 86ac74e290
commit 54063d6b46
17 changed files with 138 additions and 39 deletions

View File

@ -4,6 +4,7 @@ module Admin
include ActionView::Helpers::SanitizeHelper include ActionView::Helpers::SanitizeHelper
extend ActionView::Helpers::SanitizeHelper::ClassMethods extend ActionView::Helpers::SanitizeHelper::ClassMethods
include ActionView::Helpers::TextHelper include ActionView::Helpers::TextHelper
include ActionView::Helpers::NumberHelper
sections 'settings', 'theme_assets' sections 'settings', 'theme_assets'
@ -15,6 +16,7 @@ module Admin
@js_and_css_assets = (@assets[:javascripts] || []) + (@assets[:stylesheets] || []) @js_and_css_assets = (@assets[:javascripts] || []) + (@assets[:stylesheets] || [])
if request.xhr? if request.xhr?
@images = @assets[:images]
render :action => 'images', :layout => false and return render :action => 'images', :layout => false and return
else else
@snippets = current_site.snippets.order_by([[:name, :asc]]).all.to_a @snippets = current_site.snippets.order_by([[:name, :asc]]).all.to_a
@ -33,9 +35,10 @@ module Admin
success.json do success.json do
render :json => { render :json => {
:status => 'success', :status => 'success',
:name => truncate(@theme_asset.slug, :length => 22), :url => @theme_asset.source.url,
:slug => @theme_asset.slug, :local_path => @theme_asset.local_path(true),
:url => @theme_asset.source.url :size => number_to_human_size(@theme_asset.size),
:date => l(@theme_asset.updated_at, :format => :short)
} }
end end
failure.json { render :json => { :status => 'error' } } failure.json { render :json => { :status => 'error' } }

View File

@ -49,6 +49,14 @@ class ThemeAsset
self.stylesheet? || self.javascript? self.stylesheet? || self.javascript?
end 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 def plain_text_name
if not @plain_text_name_changed if not @plain_text_name_changed
@plain_text_name ||= self.safe_source_filename @plain_text_name ||= self.safe_source_filename

View File

@ -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 %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 .more
%span.size= number_to_human_size(asset.size) %span.size= number_to_human_size(asset.size)
— —
%span!= t('.updated_at') %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

View File

@ -4,12 +4,12 @@
.actions .actions
= admin_button_tag t('admin.theme_assets.index.new'), admin_theme_assets_url(:json), :class => 'button small add', :id => 'upload-link' = 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') %p.no-items!= t('.no_items')
%ul.assets %ul.list.theme-assets
= render 'asset', :asset => current_site.theme_assets.build, :edit => false = 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 %li.clear

View File

@ -46,5 +46,8 @@ module Locomotive
# Configure sensitive parameters which will be filtered from the log file. # Configure sensitive parameters which will be filtered from the log file.
config.filter_parameters << :password 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
end end

View File

@ -4,14 +4,14 @@ Locomotive::Application.configure do
# In the development environment your application's code is reloaded on # In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development # 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. # 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. # Log error messages when you accidentally call methods on nil.
config.whiny_nils = true config.whiny_nils = true
# Show full error reports and disable caching # Show full error reports and disable caching
config.consider_all_requests_local = true 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 # Don't care if the mailer can't send
config.action_mailer.raise_delivery_errors = false config.action_mailer.raise_delivery_errors = false

View File

@ -38,7 +38,8 @@ x snippet dependencies => do not work correctly
x mask internal asset_collections x mask internal asset_collections
x refactor ui for the theme assets page x refactor ui for the theme assets page
x fix assets liquid tags / filters 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 - fix tests
- order yaml file (http://www.ruby-forum.com/topic/120295) - order yaml file (http://www.ruby-forum.com/topic/120295)
- global regions: keyword in editable element (http://www.mongodb.org/display/DOCS/Updating) - global regions: keyword in editable element (http://www.mongodb.org/display/DOCS/Updating)

View File

@ -1,4 +1,3 @@
# require 'locomotive/patches'
require 'locomotive/configuration' require 'locomotive/configuration'
require 'locomotive/logger' require 'locomotive/logger'
require 'locomotive/liquid' require 'locomotive/liquid'
@ -14,6 +13,7 @@ require 'locomotive/regexps'
require 'locomotive/render' require 'locomotive/render'
require 'locomotive/import' require 'locomotive/import'
require 'locomotive/delayed_job' require 'locomotive/delayed_job'
require 'locomotive/middlewares'
require 'mongo_session_store/mongoid' require 'mongo_session_store/mongoid'

View File

@ -9,13 +9,17 @@ module Locomotive
return '' if input.nil? return '' if input.nil?
unless input =~ /^(\/|http:)/ unless input =~ /^(\/|http:)/
stylesheet = ThemeAsset.new(:site => @context.registers[:site], :folder => 'stylesheets') segments = "stylesheets/#{input}".split('/')
input = '/' + ThemeAssetUploader.new(stylesheet).store_path(input)
filename, folder = segments.pop, segments.join('/')
stylesheet = ThemeAsset.new(:site => @context.registers[:site], :folder => folder)
input = '/' + ThemeAssetUploader.new(stylesheet).store_path(filename)
end end
# puts "stylesheet_tag context ? #{@context}"
input = "#{input}.css" unless input.ends_with?('.css') input = "#{input}.css" unless input.ends_with?('.css')
%{<link href="#{input}" media="screen" rel="stylesheet" type="text/css" />} %{<link href="#{input}" media="screen" rel="stylesheet" type="text/css" />}
end end
@ -25,20 +29,39 @@ module Locomotive
return '' if input.nil? return '' if input.nil?
unless input =~ /^(\/|http:)/ unless input =~ /^(\/|http:)/
javascript = ThemeAsset.new(:site => @context.registers[:site], :folder => 'javascripts') segments = "javascripts/#{input}".split('/')
input = '/' + ThemeAssetUploader.new(javascript).store_path(input)
filename, folder = segments.pop, segments.join('/')
javascript = ThemeAsset.new(:site => @context.registers[:site], :folder => folder)
input = '/' + ThemeAssetUploader.new(javascript).store_path(filename)
end end
input = "#{input}.js" unless input.ends_with?('.js') input = "#{input}.js" unless input.ends_with?('.js')
%{<script src="#{input}" type="text/javascript"></script>} %{<script src="#{input}" type="text/javascript"></script>}
end 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 # Write an image tag
# input: url of the image OR asset drop # input: url of the image OR asset drop
def image_tag(input, *args) def image_tag(input, *args)
image_options = inline_options(args_to_options(args)) image_options = inline_options(args_to_options(args))
"<img src=\"#{File.join('/', get_path_from_asset(input))}\" #{image_options}/>" "<img src=\"#{File.join('/', get_url_from_asset(input))}\" #{image_options}/>"
end end
# Embed a flash movie into a page # Embed a flash movie into a page
@ -46,7 +69,7 @@ module Locomotive
# width: width (in pixel or in %) of the embedded movie # width: width (in pixel or in %) of the embedded movie
# height: height (in pixel or in %) of the embedded movie # height: height (in pixel or in %) of the embedded movie
def flash_tag(input, *args) 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)) embed_options = inline_options(args_to_options(args))
%{ %{
<object #{embed_options}> <object #{embed_options}>
@ -114,9 +137,9 @@ module Locomotive
(options.stringify_keys.to_a.collect { |a, b| "#{a}=\"#{b}\"" }).join(' ') << ' ' (options.stringify_keys.to_a.collect { |a, b| "#{a}=\"#{b}\"" }).join(' ') << ' '
end 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 # 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 input.respond_to?(:url) ? input.url : input
end end
end end

View File

@ -5,7 +5,7 @@ module Locomotive
# #
# Usage: # 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 %} # {% for post in blog.posts %}
# {{ post.title }} # {{ post.title }}
# {% endfor %} # {% endfor %}
@ -23,6 +23,8 @@ module Locomotive
markup.scan(::Liquid::TagAttributes) do |key, value| markup.scan(::Liquid::TagAttributes) do |key, value|
@options[key] = value if key != 'http' @options[key] = value if key != 'http'
end end
@expires_in = (@options.delete('expires_in') || 0).to_i
@cache_key = Digest::SHA1.hexdigest(@target)
else else
raise ::Liquid::SyntaxError.new("Syntax Error in 'consume' - Valid syntax: consume <var> from \"<url>\" [username: value, password: value]") raise ::Liquid::SyntaxError.new("Syntax Error in 'consume' - Valid syntax: consume <var> from \"<url>\" [username: value, password: value]")
end end
@ -31,10 +33,18 @@ module Locomotive
end end
def render(context) def render(context)
context.stack do render_all_and_cache_it(context)
context.scopes.last[@target.to_s] = Locomotive::Httparty::Webservice.consume(@url, @options.symbolize_keys) 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
end end

View File

@ -0,0 +1 @@
require 'locomotive/middlewares/fonts'

View File

@ -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

View File

@ -56,7 +56,7 @@ module Locomotive
'asset_collections' => Locomotive::Liquid::Drops::AssetCollections.new, 'asset_collections' => Locomotive::Liquid::Drops::AssetCollections.new,
'stylesheets' => Locomotive::Liquid::Drops::ThemeAssets::Stylesheets.new, 'stylesheets' => Locomotive::Liquid::Drops::ThemeAssets::Stylesheets.new,
'javascripts' => Locomotive::Liquid::Drops::ThemeAssets::Javascripts.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, 'contents' => Locomotive::Liquid::Drops::Contents.new,
'current_page' => self.params[:page] 'current_page' => self.params[:page]
} }

View File

@ -80,7 +80,7 @@ $(document).ready(function() {
if (typeof $.fn.imagepicker != 'undefined') if (typeof $.fn.imagepicker != 'undefined')
$('a#image-picker-link').imagepicker({ $('a#image-picker-link').imagepicker({
insertFn: function(link) { insertFn: function(link) {
return "{{ theme_images." + link.attr('data-slug') + " }}"; return "{{ '" + link.attr('data-local-path') + "' | theme_image_url }}";
} }
}); });

View File

@ -47,13 +47,13 @@ $.fn.imagepicker = function(options) {
.insertBefore($('.asset-picker ul li.clear')) .insertBefore($('.asset-picker ul li.clear'))
.addClass('asset'); .addClass('asset');
asset.find('h4 a').attr('href', json.url) asset.find('strong a').attr('href', json.url)
.attr('data-slug', json.slug) .attr('data-local-path', json.local_path)
.attr('data-shortcut-url', json.shortcut_url) .html(json.local_path).bind('click', function(e) {
.html(json.name).bind('click', function(e) {
copyLinkToEditor($(this), 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) if ($('.asset-picker ul li.asset').length % 3 == 0)
asset.addClass('last'); asset.addClass('last');
@ -74,7 +74,7 @@ $.fn.imagepicker = function(options) {
'onComplete': function() { 'onComplete': function() {
setupUploader(); setupUploader();
$('ul.assets h4 a').bind('click', function(e) { copyLinkToEditor($(this), e); }); $('ul.theme-assets strong a').bind('click', function(e) { copyLinkToEditor($(this), e); });
} }
}); });
}); });

View File

@ -37,7 +37,7 @@ $(document).ready(function() {
$('a#image-picker-link').imagepicker({ $('a#image-picker-link').imagepicker({
insertFn: function(link) { insertFn: function(link) {
return link.attr('data-url'); return link.attr('href');
} }
}); });
}); });

View File

@ -49,7 +49,7 @@
/* ___ asset picker ___ */ /* ___ 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 .actions { position: absolute; right: 4px; top: 0px; }
div.asset-picker p.no-items { background-image: url("/images/admin/list/none-small.png"); } 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 { overflow: auto; height: 471px; }
div.asset-picker ul li.new-asset { display: none; } 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 ___ */ /* ___ custom fields ___ */
#edit-custom-field { #edit-custom-field {