add missing asset collections import module + add google analytics import + work on simplifying the theme asset logic
This commit is contained in:
parent
dd0a09ec4d
commit
ecfa466074
@ -22,8 +22,8 @@ module Admin
|
||||
end
|
||||
|
||||
def set_collections_and_current_collection
|
||||
@asset_collections = current_site.asset_collections
|
||||
@asset_collection = @asset_collections.find(params[:collection_id])
|
||||
@asset_collections = current_site.asset_collections.not_internal.order_by([[:name, :asc]])
|
||||
@asset_collection = current_site.asset_collections.find(params[:collection_id])
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -3,5 +3,9 @@ module Admin
|
||||
|
||||
sections 'contents'
|
||||
|
||||
def destroy
|
||||
destroy! { admin_pages_url }
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -10,10 +10,11 @@ module Admin
|
||||
respond_to :json, :only => [:create, :update]
|
||||
|
||||
def index
|
||||
assets = current_site.theme_assets.all.to_a
|
||||
@non_image_assets = assets.find_all { |a| a.stylesheet? || a.javascript? }
|
||||
@image_assets = assets.find_all { |a| a.image? }
|
||||
@flash_assets = assets.find_all { |a| a.movie? }
|
||||
@assets = current_site.theme_assets.visible.all.order_by([[:slug, :asc]]).group_by { |a| a.folder.split('/').first.to_sym }
|
||||
@js_and_css_assets = (@assets[:javascripts] || []) + (@assets[:stylesheets] || [])
|
||||
# @non_image_assets = assets.find_all { |a| a.stylesheet? || a.javascript? }
|
||||
# @image_assets = assets.find_all { |a| a.image? }
|
||||
# @flash_assets = assets.find_all { |a| a.movie? }
|
||||
|
||||
if request.xhr?
|
||||
render :action => 'images', :layout => false and return
|
||||
@ -31,9 +32,7 @@ module Admin
|
||||
:status => 'success',
|
||||
:name => truncate(@theme_asset.slug, :length => 22),
|
||||
:slug => @theme_asset.slug,
|
||||
:url => @theme_asset.source.url,
|
||||
:vignette_url => @theme_asset.vignette_url,
|
||||
:shortcut_url => @theme_asset.shortcut_url
|
||||
:url => @theme_asset.source.url
|
||||
}
|
||||
end
|
||||
failure.json { render :json => { :status => 'error' } }
|
||||
|
@ -1,8 +1,8 @@
|
||||
module Admin::CustomFieldsHelper
|
||||
|
||||
def options_for_field_kind(selected = nil)
|
||||
options = %w{String Text Category Boolean Date File}.map do |kind|
|
||||
[t("admin.custom_fields.kind.#{kind.downcase}"), kind]
|
||||
def options_for_field_kind
|
||||
options = %w{string text category boolean date file}.map do |kind|
|
||||
[t("admin.custom_fields.kind.#{kind}"), kind]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -53,7 +53,7 @@ class Snippet
|
||||
self._change_snippet_inside_template(node.parent) if node.parent
|
||||
else
|
||||
if node.respond_to?(:nodelist)
|
||||
node.nodelist.each do |child|
|
||||
(node.nodelist || []).each do |child|
|
||||
self._change_snippet_inside_template(child)
|
||||
end
|
||||
end
|
||||
|
@ -2,16 +2,15 @@ class ThemeAsset
|
||||
|
||||
include Locomotive::Mongoid::Document
|
||||
|
||||
## Extensions ##
|
||||
include Models::Extensions::Asset::Vignette
|
||||
|
||||
## fields ##
|
||||
field :slug
|
||||
field :local_path
|
||||
field :content_type
|
||||
field :width, :type => Integer
|
||||
field :height, :type => Integer
|
||||
field :size, :type => Integer
|
||||
field :plain_text
|
||||
# field :plain_text
|
||||
field :folder, :default => nil
|
||||
field :hidden, :type => Boolean, :default => false
|
||||
mount_uploader :source, ThemeAssetUploader
|
||||
|
||||
## associations ##
|
||||
@ -19,26 +18,39 @@ class ThemeAsset
|
||||
|
||||
## indexes ##
|
||||
index :site_id
|
||||
index [[:content_type, Mongo::ASCENDING], [:slug, Mongo::ASCENDING], [:site_id, Mongo::ASCENDING]]
|
||||
index [[:site_id, Mongo::ASCENDING], [:local_path, Mongo::ASCENDING]]
|
||||
|
||||
## callbacks ##
|
||||
before_validation :sanitize_slug
|
||||
before_validation :store_plain_text
|
||||
before_validation :sanitize_folder
|
||||
before_validation :build_local_path
|
||||
# before_validation :sanitize_slug
|
||||
# before_validation :escape_shortcut_urls
|
||||
before_save :set_slug
|
||||
# before_save :set_slug
|
||||
|
||||
## validations ##
|
||||
validate :extname_can_not_be_changed
|
||||
# validate :extname_can_not_be_changed
|
||||
validates_presence_of :site, :source
|
||||
validates_presence_of :slug, :if => Proc.new { |a| a.new_record? && a.performing_plain_text? }
|
||||
validates_uniqueness_of :slug, :scope => [:site_id, :content_type]
|
||||
# validate :plain_text_name_is_required_if_no_given_source
|
||||
validates_presence_of :plain_text_name, :if => Proc.new { |a| a.performing_plain_text? }
|
||||
# validates_presence_of :slug, :if => Proc.new { |a| a.new_record? && a.performing_plain_text? }
|
||||
# validates_uniqueness_of :slug, :scope => [:site_id, :content_type, :folder]
|
||||
validates_uniqueness_of :local_path, :scope => :site_id
|
||||
validates_integrity_of :source
|
||||
|
||||
## named scopes ##
|
||||
scope :visible, :where => { :hidden => false }
|
||||
|
||||
## accessors ##
|
||||
attr_accessor :performing_plain_text
|
||||
attr_accessor :plain_text_name, :plain_text, :performing_plain_text
|
||||
|
||||
## methods ##
|
||||
|
||||
# def source=(new_file)
|
||||
# @new_source = true
|
||||
# super
|
||||
# end
|
||||
|
||||
%w{movie image stylesheet javascript font}.each do |type|
|
||||
define_method("#{type}?") do
|
||||
self.content_type == type
|
||||
@ -49,46 +61,69 @@ class ThemeAsset
|
||||
self.stylesheet? || self.javascript?
|
||||
end
|
||||
|
||||
def plain_text
|
||||
if self.stylesheet_or_javascript?
|
||||
self.plain_text = self.source.read if read_attribute(:plain_text).blank?
|
||||
read_attribute(:plain_text)
|
||||
else
|
||||
nil
|
||||
def plain_text_name
|
||||
if not @plain_text_name_changed
|
||||
@plain_text_name ||= self.safe_source_filename
|
||||
end
|
||||
@plain_text_name.gsub(/(\.[a-z0-9A-Z]+)$/, '') rescue nil
|
||||
#
|
||||
# @plain_text_name ||= self.safe_source_filename rescue nil if
|
||||
#
|
||||
# if @plain_text_name_changed
|
||||
#
|
||||
#
|
||||
# @plain_text_name_changed ? @plain_text_name :
|
||||
# (@plain_text_name || self.safe_source_filename).gsub(/(\.[a-z0-9A-Z]+)$/, '') rescue nil
|
||||
end
|
||||
|
||||
def plain_text_name=(name)
|
||||
@plain_text_name_changed = true
|
||||
@plain_text_name = name
|
||||
end
|
||||
|
||||
def plain_text
|
||||
if not @plain_text_changed
|
||||
@plain_text ||= self.source.read rescue nil
|
||||
end
|
||||
@plain_text
|
||||
# # self.plain_text = self.source.read if read_attribute(:plain_text).blank?
|
||||
# # read_attribute(:plain_text)
|
||||
# else
|
||||
# nil
|
||||
# end
|
||||
end
|
||||
|
||||
def plain_text=(source)
|
||||
self.performing_plain_text = true if self.performing_plain_text.nil?
|
||||
write_attribute(:plain_text, source)
|
||||
# @new_source = true
|
||||
@plain_text_changed = true
|
||||
self.performing_plain_text = true #if self.performing_plain_text.nil?
|
||||
@plain_text = source
|
||||
# write_attribute(:plain_text, source)
|
||||
end
|
||||
|
||||
def performing_plain_text?
|
||||
return true if !self.new_record? && self.stylesheet_or_javascript? && self.errors.empty?
|
||||
|
||||
!(self.performing_plain_text.blank? || self.performing_plain_text == 'false' || self.performing_plain_text == false)
|
||||
Boolean.set(self.performing_plain_text)
|
||||
# self.performing_plain_text == true || self.performing_plain_text == '1' || self.performing_plain_text ==
|
||||
# return true if !self.new_record? && self.stylesheet_or_javascript? && self.errors.empty?
|
||||
# !(self.performing_plain_text.blank? || self.performing_plain_text == 'false' || self.performing_plain_text == false)
|
||||
end
|
||||
|
||||
def store_plain_text
|
||||
return if !self.stylesheet_or_javascript? || self.plain_text.blank?
|
||||
return if !self.stylesheet_or_javascript? || self.plain_text_name.blank? || self.plain_text.blank?
|
||||
|
||||
sanitized_source = self.escape_shortcut_urls(self.plain_text)
|
||||
|
||||
if self.source.nil?
|
||||
self.source = CarrierWave::SanitizedFile.new({
|
||||
:tempfile => StringIO.new(sanitized_source),
|
||||
:filename => "#{self.slug}.#{self.stylesheet? ? 'css' : 'js'}"
|
||||
})
|
||||
else
|
||||
self.source.file.instance_variable_set(:@file, StringIO.new(sanitized_source))
|
||||
end
|
||||
self.source = CarrierWave::SanitizedFile.new({
|
||||
:tempfile => StringIO.new(sanitized_source),
|
||||
:filename => "#{self.plain_text_name}.#{self.stylesheet? ? 'css' : 'js'}"
|
||||
})
|
||||
end
|
||||
|
||||
def shortcut_url # ex: /stylesheets/application.css is a shortcut for a theme asset (content_type => stylesheet, slug => 'application')
|
||||
File.join(self.content_type.pluralize, "#{self.slug}#{File.extname(self.source_filename)}")
|
||||
rescue
|
||||
''
|
||||
end
|
||||
# def shortcut_url # ex: /stylesheets/application.css is a shortcut for a theme asset (content_type => stylesheet, slug => 'application')
|
||||
# File.join(self.content_type.pluralize, "#{self.slug}#{File.extname(self.source_filename)}")
|
||||
# rescue
|
||||
# ''
|
||||
# end
|
||||
|
||||
def to_liquid
|
||||
{ :url => self.source.url }.merge(self.attributes)
|
||||
@ -96,41 +131,83 @@ class ThemeAsset
|
||||
|
||||
protected
|
||||
|
||||
def escape_shortcut_urls(text) # replace /<content_type>/<slug> occurences by the real amazon S3 url or local files
|
||||
# def new_source?
|
||||
# @new_source == true
|
||||
# end
|
||||
|
||||
def safe_source_filename
|
||||
self.source_filename || self.source.send(:original_filename) rescue nil
|
||||
end
|
||||
|
||||
def sanitize_folder
|
||||
self.folder = self.content_type.pluralize if self.folder.blank?
|
||||
|
||||
# no accents, no spaces, no leading and ending trails
|
||||
self.folder = ActiveSupport::Inflector.transliterate(self.folder).gsub(/(\s)+/, '_').gsub(/^\//, '').gsub(/\/$/, '')
|
||||
|
||||
# folder should begin by a root folder
|
||||
if (self.folder =~ /^(stylesheets|javascripts|images|media|fonts)/).nil?
|
||||
self.folder = File.join(self.content_type.pluralize, self.folder)
|
||||
end
|
||||
end
|
||||
|
||||
def build_local_path
|
||||
puts "self.source_filename = #{self.source_filename} / #{self.safe_source_filename} / #{File.join(self.folder, self.safe_source_filename)}"
|
||||
self.local_path = File.join(self.folder, self.safe_source_filename)
|
||||
end
|
||||
|
||||
def escape_shortcut_urls(text)
|
||||
return if text.blank?
|
||||
|
||||
text.gsub(/(\/(stylesheets|javascripts|images)\/([a-z_\-0-9]+)\.[a-z]{2,3})/) do |url|
|
||||
content_type, slug = url.split('/')[1..-1]
|
||||
text.gsub(/[("'](\/(stylesheets|javascripts|images|media)\/((.+)\/)*([a-z_\-0-9]+)\.[a-z]{2,3})[)"']/) do |path|
|
||||
sanitized_path = path.gsub(/[("')]/, '').gsub(/^\//, '')
|
||||
|
||||
content_type = content_type.singularize
|
||||
slug = slug.split('.').first
|
||||
# puts "\t\t\tfound path = #{sanitized_path}"
|
||||
|
||||
if asset = self.site.theme_assets.where(:content_type => content_type, :slug => slug).first
|
||||
asset.source.url
|
||||
if asset = self.site.theme_assets.where(:local_path => sanitized_path).first
|
||||
"#{path.first}#{asset.source.url}#{path.last}"
|
||||
else
|
||||
url
|
||||
path
|
||||
end
|
||||
|
||||
# content_type, slug = url.split('/')[1..-1]
|
||||
|
||||
# content_type = content_type.singularize
|
||||
# slug = slug.split('.').first
|
||||
|
||||
# if asset = self.site.theme_assets.where(:content_type => content_type, :slug => slug).first
|
||||
# asset.source.url
|
||||
# else
|
||||
# url
|
||||
# end
|
||||
end
|
||||
end
|
||||
|
||||
def sanitize_slug
|
||||
self.slug.parameterize! if self.slug.present?
|
||||
end
|
||||
# def plain_text_name_is_required_if_no_given_source
|
||||
# puts "@performing_plain_text = #{self.performing_plain_text?} / #{@plain_text_name} / new_file = #{self.source.inspect}"
|
||||
# if self.performing_plain_text? && @plain_text_name.blank?
|
||||
# self.errors.add(:plain_text_name, :blank)
|
||||
# end
|
||||
# end
|
||||
|
||||
def set_slug
|
||||
if self.slug.blank?
|
||||
self.slug = File.basename(self.source_filename, File.extname(self.source_filename))
|
||||
self.sanitize_slug
|
||||
end
|
||||
end
|
||||
|
||||
def extname_can_not_be_changed
|
||||
return if self.new_record? || self.source.file.original_filename.nil?
|
||||
|
||||
puts "filename => #{self.source_filename} / source file => #{self.source.file.inspect}"
|
||||
|
||||
if File.extname(self.source.file.original_filename) != File.extname(self.source_filename)
|
||||
self.errors.add(:source, :extname_changed)
|
||||
end
|
||||
end
|
||||
# def sanitize_slug
|
||||
# self.slug.parameterize! if self.slug.present?
|
||||
# end
|
||||
#
|
||||
# def set_slug
|
||||
# if self.slug.blank?
|
||||
# self.slug = File.basename(self.source_filename, File.extname(self.source_filename))
|
||||
# self.sanitize_slug
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# def extname_can_not_be_changed
|
||||
# return if self.new_record? || self.source.file.original_filename.nil?
|
||||
#
|
||||
# puts "filename => #{self.source_filename} / source file => #{self.source.file.inspect}"
|
||||
#
|
||||
# if File.extname(self.source.file.original_filename) != File.extname(self.source_filename)
|
||||
# self.errors.add(:source, :extname_changed)
|
||||
# end
|
||||
# end
|
||||
end
|
||||
|
@ -61,12 +61,12 @@ class AssetUploader < CarrierWave::Uploader::Base
|
||||
def self.content_types
|
||||
{
|
||||
:image => ['image/jpeg', 'image/pjpeg', 'image/gif', 'image/png', 'image/x-png', 'image/jpg'],
|
||||
:movie => [/^video/, 'application/x-shockwave-flash', 'application/x-swf'],
|
||||
:video => [/^video/, 'application/x-shockwave-flash', 'application/x-swf'],
|
||||
:audio => [/^audio/, 'application/ogg', 'application/x-mp3'],
|
||||
:pdf => ['application/pdf', 'application/x-pdf'],
|
||||
:stylesheet => ['text/css'],
|
||||
:javascript => ['text/javascript', 'text/js', 'application/x-javascript', 'application/javascript'],
|
||||
:font => ['application/x-font-ttf', 'application/vnd.ms-fontobject']
|
||||
:font => ['application/x-font-ttf', 'application/vnd.ms-fontobject', 'image/svg+xml', 'application/x-woff']
|
||||
}
|
||||
end
|
||||
|
||||
|
13
app/uploaders/font_uploader.rb
Normal file
13
app/uploaders/font_uploader.rb
Normal file
@ -0,0 +1,13 @@
|
||||
# encoding: utf-8
|
||||
|
||||
class FontUploader < CarrierWave::Uploader::Base
|
||||
|
||||
def store_dir
|
||||
"sites/#{model.id}/theme/fonts"
|
||||
end
|
||||
|
||||
def cache_dir
|
||||
"#{Rails.root}/tmp/uploads"
|
||||
end
|
||||
|
||||
end
|
@ -6,28 +6,40 @@ class ThemeAssetUploader < AssetUploader
|
||||
process :set_size
|
||||
process :set_width_and_height
|
||||
|
||||
version :thumb do
|
||||
process :resize_to_fill => [50, 50]
|
||||
process :convert => 'png'
|
||||
end
|
||||
|
||||
version :medium do
|
||||
process :resize_to_fill => [80, 80]
|
||||
process :convert => 'png'
|
||||
end
|
||||
|
||||
version :preview do
|
||||
process :resize_to_fit => [880, 1100]
|
||||
process :convert => 'png'
|
||||
end
|
||||
# version :thumb do
|
||||
# process :resize_to_fill => [50, 50]
|
||||
# process :convert => 'png'
|
||||
# end
|
||||
#
|
||||
# version :medium do
|
||||
# process :resize_to_fill => [80, 80]
|
||||
# process :convert => 'png'
|
||||
# end
|
||||
#
|
||||
# version :preview do
|
||||
# process :resize_to_fit => [880, 1100]
|
||||
# process :convert => 'png'
|
||||
# end
|
||||
|
||||
def store_dir
|
||||
# "sites/#{model.site_id}/themes/#{model.id}"
|
||||
"sites/#{model.site_id}/theme/#{model.content_type.pluralize}"
|
||||
File.join('sites', model.site_id.to_s, 'theme', model.folder)
|
||||
# File.join('sites', model.site_id.to_s, 'theme', model.content_type.pluralize, model.subfolder || '')
|
||||
|
||||
# base = File.join('sites', model.site_id.to_s, 'theme')
|
||||
# # puts "base = #{base} / #{model.subfolder.inspect}"
|
||||
# if model.subfolder.blank?
|
||||
# File.join(base, model.content_type.pluralize)
|
||||
# else
|
||||
# File.join(base, model.subfolder)
|
||||
# end
|
||||
|
||||
#
|
||||
# # "sites/#{model.site_id}/themes/#{model.id}/#{model.content_type.pluralize}"
|
||||
# File.join("sites/#{model.site_id}/theme", model.subfolder || '', model.content_type.pluralize)
|
||||
end
|
||||
|
||||
def extension_white_list
|
||||
%w(jpg jpeg gif png css js swf flv)
|
||||
%w(jpg jpeg gif png css js swf flv eot svg ttf woff)
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,14 +1,3 @@
|
||||
/ - per_row = local_assigns[:per_row] || 6
|
||||
/ - snippet_counter = local_assigns[:snippet_counter] || 0
|
||||
/
|
||||
/ %li{ :class => "asset #{'last' if (snippet_counter + 1) % per_row == 0}"}
|
||||
/ %h4= link_to truncate(snippet.slug, :length => 18), edit_admin_snippet_path(snippet)
|
||||
/ .image
|
||||
/ .inside
|
||||
/ / = vignette_tag(asset)
|
||||
/ .actions
|
||||
/ = link_to image_tag('admin/list/icons/cross.png'), admin_snippet_path(snippet), :class => 'remove', :confirm => t('admin.messages.confirm'), :method => :delete
|
||||
|
||||
%li
|
||||
%em
|
||||
%strong= link_to snippet.name, edit_admin_snippet_path(snippet)
|
||||
|
@ -1,12 +1,24 @@
|
||||
- per_row = local_assigns[:per_row] || 6
|
||||
- asset_counter = local_assigns[:asset_counter] || 0
|
||||
- edit = local_assigns.key?(:edit) ? edit : true
|
||||
/ - per_row = local_assigns[:per_row] || 6
|
||||
/ - asset_counter = local_assigns[:asset_counter] || 0
|
||||
/ - edit = local_assigns.key?(:edit) ? edit : true
|
||||
/
|
||||
/ %li{ :class => "#{asset.new_record? ? 'new-asset' : 'asset'} #{'last' if (asset_counter + 1) % per_row == 0}"}
|
||||
/ %h4= link_to truncate(asset.slug, :length => 18), edit ? edit_admin_theme_asset_path(asset) : asset.source.url, :"data-slug" => asset.slug, :"data-shortcut-url" => asset.shortcut_url
|
||||
/ .image
|
||||
/ .inside
|
||||
/ = vignette_tag(asset)
|
||||
/ - if edit
|
||||
/ .actions
|
||||
/ = link_to image_tag('admin/list/icons/cross.png'), admin_theme_asset_path(asset), :class => 'remove', :confirm => t('admin.messages.confirm'), :method => :delete
|
||||
|
||||
%li{ :class => "#{asset.new_record? ? 'new-asset' : 'asset'} #{'last' if (asset_counter + 1) % per_row == 0}"}
|
||||
%h4= link_to truncate(asset.slug, :length => 18), edit ? edit_admin_theme_asset_path(asset) : asset.source.url, :"data-slug" => asset.slug, :"data-shortcut-url" => asset.shortcut_url
|
||||
.image
|
||||
.inside
|
||||
= vignette_tag(asset)
|
||||
- if edit
|
||||
.actions
|
||||
= link_to image_tag('admin/list/icons/cross.png'), admin_theme_asset_path(asset), :class => 'remove', :confirm => t('admin.messages.confirm'), :method => :delete
|
||||
|
||||
%li
|
||||
%em
|
||||
%strong= link_to asset.local_path, edit_admin_theme_asset_path(asset)
|
||||
.more
|
||||
%span.size= number_to_human_size(asset.size)
|
||||
—
|
||||
%span!= t('.updated_at')
|
||||
= 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
|
||||
|
@ -13,34 +13,38 @@
|
||||
- if @snippets.empty?
|
||||
%p.no-items!= t('.no_items', :url => new_admin_snippet_url)
|
||||
- else
|
||||
%ul#snippets-list.list
|
||||
%ul.list.theme-assets
|
||||
= render @snippets
|
||||
|
||||
%br
|
||||
|
||||
%h3!= t('.css_and_js')
|
||||
- if @non_image_assets.empty?
|
||||
- if @js_and_css_assets.empty?
|
||||
%p.no-items!= t('.no_items', :url => new_admin_theme_asset_url)
|
||||
- else
|
||||
%ul.assets
|
||||
= render :partial => 'asset', :collection => @non_image_assets
|
||||
%li.clear
|
||||
%ul.list.theme-assets
|
||||
= render :partial => 'asset', :collection => @js_and_css_assets
|
||||
|
||||
%br
|
||||
|
||||
%h3!= t('.images')
|
||||
- if @image_assets.empty?
|
||||
- if @assets[:images].nil?
|
||||
%p.no-items!= t('.no_items', :url => new_admin_theme_asset_url)
|
||||
- else
|
||||
%ul.assets
|
||||
= render :partial => 'asset', :collection => @image_assets
|
||||
%li.clear
|
||||
%ul.list.theme-assets
|
||||
= render :partial => 'asset', :collection => @assets[:images]
|
||||
|
||||
|
||||
- if not @flash_assets.empty?
|
||||
- if @assets[:fonts]
|
||||
%br
|
||||
|
||||
%h3!= t('.flashes')
|
||||
%ul.assets
|
||||
= render :partial => 'asset', :collection => @flash_assets
|
||||
%li.clear
|
||||
%h3!= t('.fonts')
|
||||
%ul.list.theme-assets
|
||||
= render :partial => 'asset', :collection => @assets[:fonts]
|
||||
|
||||
- if @assets[:media]
|
||||
%br
|
||||
|
||||
%h3!= t('.media')
|
||||
%ul.list.theme-assets
|
||||
= render :partial => 'asset', :collection => @assets[:media]
|
||||
|
||||
|
@ -8,3 +8,8 @@
|
||||
# inflect.irregular 'person', 'people'
|
||||
# inflect.uncountable %w( fish sheep )
|
||||
# end
|
||||
|
||||
ActiveSupport::Inflector.inflections do |inflect|
|
||||
inflect.irregular 'media', 'media'
|
||||
end
|
||||
|
||||
|
@ -164,8 +164,10 @@ en:
|
||||
css_and_js: Style and javascript
|
||||
fonts: Fonts
|
||||
images: Images
|
||||
flashes: Flash
|
||||
media: Media
|
||||
no_items: "There are no files for now. Just click <a href=\"%{url}\">here</a> to create the first one."
|
||||
asset:
|
||||
updated_at: Updated at
|
||||
new:
|
||||
title: New file
|
||||
help: "You have the choice to either upload any file or to copy/paste a stylesheet or a javascript in plain text."
|
||||
|
@ -163,9 +163,11 @@ fr:
|
||||
snippets: Snippets
|
||||
css_and_js: Style et javascript
|
||||
images: Images
|
||||
flashes: Flash
|
||||
media: Media
|
||||
fonts: Polices
|
||||
no_items: "Il n'existe pas de fichiers. Vous pouvez commencer par créer un <a href='%{url}'>ici</a>."
|
||||
asset:
|
||||
updated_at: Mis à jour le
|
||||
new:
|
||||
title: Nouveau fichier
|
||||
help: "Vous avez le choix de soit uploader n'importe quel fichier ou bien soit de copier/coller du code css ou javascript."
|
||||
|
15
doc/TODO
15
doc/TODO
@ -22,12 +22,23 @@ x create a repo for a tool "a la" vision
|
||||
x asset collections => liquid
|
||||
x images tag to write
|
||||
! apply http://github.com/flori/json/commit/2c0f8d2c9b15a33b8d10ffcb1959aef54d320b57
|
||||
x import tool:
|
||||
x snippet dependencies => do not work correctly
|
||||
? google analytics tag
|
||||
- import tool:
|
||||
x select field (see custom fields and nocoffee theme) ?
|
||||
x disable sub tasks by passing options
|
||||
x exceptions
|
||||
x page to import theme
|
||||
x snippet dependencies => do not work correctly
|
||||
x contents: group_by, oder_by, api_enabled
|
||||
? asset collections
|
||||
? fonts
|
||||
? folders for theme assets
|
||||
? theme assets whitelist
|
||||
- add samples ?
|
||||
x mask internal asset_collections
|
||||
- refactor ui for the theme assets page
|
||||
- proxy for fonts
|
||||
- order yaml file (http://www.ruby-forum.com/topic/120295)
|
||||
- global regions: keyword in editable element (http://www.mongodb.org/display/DOCS/Updating)
|
||||
- write my first tutorial about locomotive
|
||||
|
||||
|
@ -4,3 +4,4 @@ require 'locomotive/carrierwave/patches'
|
||||
|
||||
# register missing mime types
|
||||
EXTENSIONS[:eot] = 'application/vnd.ms-fontobject'
|
||||
EXTENSIONS[:woff] = 'application/x-woff'
|
||||
|
@ -39,17 +39,21 @@ module CarrierWave
|
||||
module Mongoid
|
||||
def validates_integrity_of(*attrs)
|
||||
options = attrs.last.is_a?(Hash) ? attrs.last : {}
|
||||
options[:message] ||= I18n.t('carrierwave.errors.integrity', :default => 'is not an allowed type of file.')
|
||||
validates_each(*attrs) do |record, attr, value|
|
||||
record.errors.add attr, options[:message] if record.send("#{attr}_integrity_error")
|
||||
if record.send("#{attr}_integrity_error")
|
||||
message = options[:message] || I18n.t('carrierwave.errors.integrity', :default => 'is not an allowed type of file.')
|
||||
record.errors.add attr, message
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def validates_processing_of(*attrs)
|
||||
options = attrs.last.is_a?(Hash) ? attrs.last : {}
|
||||
options[:message] ||= I18n.t('carrierwave.errors.processing', :default => 'failed to be processed.')
|
||||
validates_each(*attrs) do |record, attr, value|
|
||||
record.errors.add attr, options[:message] if record.send("#{attr}_processing_error")
|
||||
if record.send("#{attr}_processing_error")
|
||||
message = options[:message] || I18n.t('carrierwave.errors.processing', :default => 'failed to be processed.')
|
||||
record.errors.add attr, message
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,6 +1,7 @@
|
||||
require 'locomotive/import/job'
|
||||
require 'locomotive/import/site'
|
||||
require 'locomotive/import/assets'
|
||||
require 'locomotive/import/asset_collections'
|
||||
require 'locomotive/import/content_types'
|
||||
require 'locomotive/import/snippets'
|
||||
require 'locomotive/import/pages'
|
51
lib/locomotive/import/asset_collections.rb
Normal file
51
lib/locomotive/import/asset_collections.rb
Normal file
@ -0,0 +1,51 @@
|
||||
module Locomotive
|
||||
module Import
|
||||
module AssetCollections
|
||||
|
||||
def self.process(context)
|
||||
site, database = context[:site], context[:database]
|
||||
|
||||
asset_collections = database['site']['asset_collections']
|
||||
|
||||
return if asset_collections.nil?
|
||||
|
||||
asset_collections.each do |name, attributes|
|
||||
puts "....asset_collection = #{attributes['slug']}"
|
||||
|
||||
asset_collection = site.asset_collections.where(:slug => attributes['slug']).first
|
||||
|
||||
asset_collection ||= self.build_asset_collection(site, attributes.merge(:name => name))
|
||||
|
||||
self.add_or_update_fields(asset_collection, attributes['fields'])
|
||||
|
||||
asset_collection.save!
|
||||
|
||||
site.reload
|
||||
end
|
||||
end
|
||||
|
||||
def self.build_asset_collection(site, data)
|
||||
attributes = { :internal => false }.merge(data)
|
||||
|
||||
attributes.delete_if { |name, value| %w{fields assets}.include?(name) }
|
||||
|
||||
site.asset_collections.build(attributes)
|
||||
end
|
||||
|
||||
def self.add_or_update_fields(asset_collection, fields)
|
||||
fields.each do |name, data|
|
||||
attributes = { :_alias => name, :label => name.humanize, :kind => 'string' }.merge(data).symbolize_keys
|
||||
|
||||
field = asset_collection.asset_custom_fields.detect { |f| f._alias == attributes[:_alias] }
|
||||
|
||||
field ||= asset_collection.asset_custom_fields.build(attributes)
|
||||
|
||||
field.send(:set_unique_name!) if field.new_record?
|
||||
|
||||
field.attributes = attributes
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -5,26 +5,45 @@ module Locomotive
|
||||
def self.process(context)
|
||||
site, theme_path = context[:site], context[:theme_path]
|
||||
|
||||
self.add_theme_assets(site, theme_path)
|
||||
whitelist = self.build_regexps_in_withlist(context[:database]['site']['assets']['whitelist']) rescue nil
|
||||
|
||||
puts "whitelist = #{whitelist.inspect}"
|
||||
|
||||
self.add_theme_assets(site, theme_path, whitelist)
|
||||
|
||||
# self.add_font_assets(site, theme_path)
|
||||
|
||||
self.add_other_assets(site, theme_path)
|
||||
end
|
||||
|
||||
def self.add_theme_assets(site, theme_path)
|
||||
%w(images stylesheets javascripts).each do |kind|
|
||||
Dir[File.join(theme_path, 'public', kind, '*')].each do |asset_path|
|
||||
def self.add_theme_assets(site, theme_path, whitelist)
|
||||
%w(images media fonts javascripts stylesheets).each do |kind|
|
||||
Dir[File.join(theme_path, 'public', kind, '**/*')].each do |asset_path|
|
||||
|
||||
next if File.directory?(asset_path)
|
||||
|
||||
slug = File.basename(asset_path, File.extname(asset_path)).parameterize('_')
|
||||
visible = self.check_against_whitelist(whitelist, asset_path.gsub(File.join(theme_path, 'public'), ''))
|
||||
|
||||
asset = site.theme_assets.where(:content_type => kind.singularize, :slug => slug).first
|
||||
|
||||
asset ||= site.theme_assets.build
|
||||
folder = asset_path.gsub(File.join(theme_path, 'public'), '').gsub(File.basename(asset_path), '').gsub(/^\//, '').gsub(/\/$/, '')
|
||||
# folder = nil if folder.blank? || folder == kind
|
||||
|
||||
asset.attributes = { :source => File.open(asset_path), :performing_plain_text => false }
|
||||
puts "folder = #{folder} / #{visible.inspect} / #{asset_path.gsub(File.join(theme_path, 'public'), '')} / local_path = #{File.join(folder, File.basename(asset_path))}"
|
||||
|
||||
# slug = File.basename(asset_path, File.extname(asset_path)).parameterize('_')
|
||||
|
||||
# asset = site.theme_assets.where(:content_type => kind.singularize, :folder => folder, :slug => slug).first
|
||||
|
||||
asset = site.theme_assets.where(:local_path => File.join(folder, File.basename(asset_path))).first
|
||||
|
||||
puts "found asset ! #{!asset.nil?} / #{File.join(folder, File.basename(asset_path))} / #{kind.singularize}"
|
||||
|
||||
asset ||= site.theme_assets.build(:folder => folder)
|
||||
|
||||
asset.attributes = { :source => File.open(asset_path), :performing_plain_text => false, :hidden => !visible }
|
||||
asset.save!
|
||||
|
||||
puts "--------------------"
|
||||
|
||||
site.reload
|
||||
# asset.reload
|
||||
#
|
||||
@ -36,6 +55,16 @@ module Locomotive
|
||||
end
|
||||
end
|
||||
|
||||
# def self.add_font_assets(site, theme_path)
|
||||
# uploader = FontUploader.new(site)
|
||||
#
|
||||
# Dir[File.join(theme_path, 'public', 'fonts', '*')].each do |asset_path|
|
||||
# next if File.directory?(asset_path)
|
||||
# puts "font file = #{asset_path}"
|
||||
# uploader.store!(File.open(asset_path))
|
||||
# end
|
||||
# end
|
||||
|
||||
def self.add_other_assets(site, theme_path)
|
||||
collection = AssetCollection.find_or_create_internal(site)
|
||||
|
||||
@ -49,6 +78,27 @@ module Locomotive
|
||||
end
|
||||
end
|
||||
|
||||
def self.build_regexps_in_withlist(rules)
|
||||
rules.collect do |rule|
|
||||
if rule.start_with?('^')
|
||||
Regexp.new(rule.gsub('/', '\/'))
|
||||
else
|
||||
rule
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.check_against_whitelist(whitelist, path)
|
||||
(whitelist || []).each do |rule|
|
||||
case rule
|
||||
when Regexp
|
||||
return true if path =~ rule
|
||||
when String
|
||||
return true if path == rule
|
||||
end
|
||||
end
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -10,20 +10,28 @@ module Locomotive
|
||||
return if content_types.nil?
|
||||
|
||||
content_types.each do |name, attributes|
|
||||
puts "....content_type = #{attributes['slug']}"
|
||||
|
||||
content_type = site.content_types.where(:slug => attributes['slug']).first
|
||||
|
||||
content_type ||= self.create_content_type(site, attributes.merge(:name => name))
|
||||
content_type ||= self.build_content_type(site, attributes.merge(:name => name))
|
||||
|
||||
self.add_or_update_fields(content_type, attributes['fields'])
|
||||
|
||||
self.set_highlighted_field_name(content_type)
|
||||
|
||||
self.set_order_by_value(content_type)
|
||||
|
||||
self.set_group_by_value(content_type)
|
||||
|
||||
content_type.save!
|
||||
|
||||
site.reload
|
||||
end
|
||||
end
|
||||
|
||||
def self.create_content_type(site, data)
|
||||
attributes = { :order_by => 'manually' }.merge(data)
|
||||
def self.build_content_type(site, data)
|
||||
attributes = { :order_by => '_position_in_list', :group_by_field_name => data.delete('group_by') }.merge(data)
|
||||
|
||||
attributes.delete_if { |name, value| %w{fields contents}.include?(name) }
|
||||
|
||||
@ -32,16 +40,43 @@ module Locomotive
|
||||
|
||||
def self.add_or_update_fields(content_type, fields)
|
||||
fields.each do |name, data|
|
||||
attributes = { :label => name.humanize, :_name => name, :kind => 'String' }.merge(data).symbolize_keys
|
||||
attributes = { :_alias => name, :label => name.humanize, :kind => 'string' }.merge(data).symbolize_keys
|
||||
|
||||
field = content_type.content_custom_fields.detect { |f| f._name == attributes[:_name] }
|
||||
field = content_type.content_custom_fields.detect { |f| f._alias == attributes[:_alias] }
|
||||
|
||||
field ||= content_type.content_custom_fields.build(attributes)
|
||||
|
||||
field.send(:set_unique_name!) if field.new_record?
|
||||
|
||||
field.attributes = attributes
|
||||
end
|
||||
end
|
||||
|
||||
def self.set_highlighted_field_name(content_type)
|
||||
field = content_type.content_custom_fields.detect { |f| f._alias == content_type.highlighted_field_name }
|
||||
|
||||
content_type.highlighted_field_name = field._name if field
|
||||
end
|
||||
|
||||
def self.set_order_by_value(content_type)
|
||||
order_by = (case content_type.order_by
|
||||
when 'manually', '_position_in_list' then '_position_in_list'
|
||||
when 'date', 'updated_at' then 'updated_at'
|
||||
else
|
||||
content_type.content_custom_fields.detect { |f| f._alias == content_type.order_by }._name rescue nil
|
||||
end)
|
||||
|
||||
content_type.order_by = order_by || '_position_in_list'
|
||||
end
|
||||
|
||||
def self.set_group_by_value(content_type)
|
||||
return if content_type.group_by_field_name.blank?
|
||||
|
||||
field = content_type.content_custom_fields.detect { |f| f._alias == content_type.group_by_field_name }
|
||||
|
||||
content_type.group_by_field_name = field._name if field
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -33,10 +33,10 @@ module Locomotive
|
||||
:worker => @worker
|
||||
}
|
||||
|
||||
%w(site content_types assets snippets pages).each do |step|
|
||||
%w(site content_types assets asset_collections snippets pages).each do |step|
|
||||
if @enabled[step] != false
|
||||
@worker.update_attributes :step => step
|
||||
puts "@worker...#{@worker.failed_at.inspect} / #{@worker.failed?.inspect}"
|
||||
@worker.update_attributes :step => step if @worker
|
||||
# puts "@worker...#{@worker.failed_at.inspect} / #{@worker.failed?.inspect}"
|
||||
"Locomotive::Import::#{step.camelize}".constantize.process(context)
|
||||
else
|
||||
puts "skipping #{step}"
|
||||
|
@ -30,7 +30,7 @@ module Locomotive
|
||||
|
||||
site, pages, theme_path = context[:site], context[:database]['site']['pages'], context[:theme_path]
|
||||
|
||||
template = File.read(File.join(theme_path, 'templates', "#{fullpath}.liquid"))
|
||||
template = File.read(File.join(theme_path, 'templates', "#{fullpath}.liquid")) rescue "Unable to find #{fullpath}.liquid"
|
||||
|
||||
self.build_parent_template(template, context)
|
||||
|
||||
@ -95,9 +95,9 @@ module Locomotive
|
||||
|
||||
return site.pages.index.first if segments.size == 1
|
||||
|
||||
(segments.last == 'index' ? 2 : 1).times { segments.pop }
|
||||
segments.pop
|
||||
|
||||
parent_fullpath = File.join(segments.join('/'), 'index').gsub(/^\//, '')
|
||||
parent_fullpath = segments.join('/').gsub(/^\//, '')
|
||||
|
||||
# look for a local index page in db
|
||||
parent = site.pages.where(:fullpath => parent_fullpath).first
|
||||
|
@ -9,7 +9,7 @@ module Locomotive
|
||||
content_type = self.class.name.demodulize.underscore.singularize
|
||||
|
||||
asset = ThemeAsset.new(:site => @context.registers[:site], :content_type => content_type)
|
||||
ThemeAssetUploader.new(asset).store_path(meth.gsub('__', '.'))
|
||||
'/' + ThemeAssetUploader.new(asset).store_path(meth.gsub('__', '.'))
|
||||
end
|
||||
|
||||
end
|
||||
|
39
lib/locomotive/liquid/tags/google_analytics.rb
Normal file
39
lib/locomotive/liquid/tags/google_analytics.rb
Normal file
@ -0,0 +1,39 @@
|
||||
module Liquid
|
||||
module Locomotive
|
||||
module Tags
|
||||
class GoogleAnalytics < ::Liquid::Tag
|
||||
|
||||
Syntax = /(#{::Liquid::Expression}+)?/
|
||||
|
||||
def initialize(tag_name, markup, tokens, context)
|
||||
if markup =~ Syntax
|
||||
@account_id = $1.gsub('\'', '')
|
||||
else
|
||||
raise ::Liquid::SyntaxError.new("Syntax Error in 'google_analytics' - Valid syntax: google_analytics <account_id>")
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def render(context)
|
||||
%{
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', '#{@account_id}']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() \{
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
\})();
|
||||
|
||||
</script>}
|
||||
end
|
||||
end
|
||||
|
||||
::Liquid::Template.register_tag('google_analytics', GoogleAnalytics)
|
||||
end
|
||||
end
|
||||
end
|
@ -53,7 +53,6 @@ ul.list li {
|
||||
margin-bottom: 10px;
|
||||
position: relative;
|
||||
clear: both;
|
||||
background: transparent url(/images/admin/list/item.png) no-repeat 0 0;
|
||||
}
|
||||
|
||||
ul.list li em {
|
||||
@ -64,6 +63,13 @@ ul.list li em {
|
||||
width: 18px;
|
||||
}
|
||||
|
||||
ul.list li strong {
|
||||
margin-left: 18px;
|
||||
display: block;
|
||||
height: 31px;
|
||||
background: transparent url(/images/admin/list/item-right.png) no-repeat right 0;
|
||||
}
|
||||
|
||||
ul.list li strong a {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
@ -71,6 +77,7 @@ ul.list li strong a {
|
||||
text-decoration: none;
|
||||
color: #1f82bc;
|
||||
font-size: 0.9em;
|
||||
text-shadow: 1px 1px 1px #fff;
|
||||
}
|
||||
|
||||
ul.list.sortable li strong a { left: 10px; }
|
||||
@ -98,12 +105,68 @@ ul.list li span.handle {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
|
||||
/*ul.list li {
|
||||
height: 31px;
|
||||
margin-bottom: 10px;
|
||||
position: relative;
|
||||
clear: both;
|
||||
background: transparent url(/images/admin/list/item.png) no-repeat 0 0;
|
||||
}
|
||||
|
||||
ul.list li em {
|
||||
display: block;
|
||||
float: left;
|
||||
background: transparent url(/images/admin/list/item-left.png) no-repeat left 0;
|
||||
height: 31px;
|
||||
width: 18px;
|
||||
}
|
||||
|
||||
ul.list li strong a {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
left: 15px;
|
||||
text-decoration: none;
|
||||
color: #1f82bc;
|
||||
font-size: 0.9em;
|
||||
text-shadow: 1px 1px 1px #fff;
|
||||
}
|
||||
|
||||
ul.list.sortable li strong a { left: 10px; }
|
||||
|
||||
ul.list li strong a:hover { text-decoration: underline; }
|
||||
|
||||
ul.list li div.more {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
right: 15px;
|
||||
font-size: 0.7em;
|
||||
color: #8b8d9a;
|
||||
}
|
||||
|
||||
ul.list li div.more a {
|
||||
margin-left: 10px;
|
||||
position: relative;
|
||||
top: 4px;
|
||||
}
|
||||
|
||||
ul.list li span.handle {
|
||||
position: relative;
|
||||
top: 5px;
|
||||
margin: 0 0 0 15px;
|
||||
cursor: move;
|
||||
}
|
||||
*/
|
||||
/* ___ asset collections ___ */
|
||||
|
||||
div#asset-uploader { display: inline-block; margin-left: 10px; }
|
||||
div#asset-uploader span.spinner { position: relative; top: -3px; display: none; }
|
||||
div#uploadAssetsInputQueue { display: none; }
|
||||
|
||||
/* ___ theme assets ___ */
|
||||
|
||||
ul.theme-assets { margin-left: 40px; }
|
||||
|
||||
/* ___ contents ___ */
|
||||
|
||||
#contents-list li { background: none; }
|
||||
@ -122,7 +185,7 @@ div#uploadAssetsInputQueue { display: none; }
|
||||
|
||||
/* ___ snippets ___ */
|
||||
|
||||
#snippets-list { margin-left: 40px; }
|
||||
/*#snippets-list { margin-left: 40px; }
|
||||
|
||||
#snippets-list li { background: none; }
|
||||
|
||||
@ -136,7 +199,7 @@ div#uploadAssetsInputQueue { display: none; }
|
||||
height: 31px;
|
||||
background: transparent url(/images/admin/list/item-right.png) no-repeat right 0;
|
||||
}
|
||||
|
||||
*/
|
||||
/* ___ pages ___ */
|
||||
|
||||
#pages-list {
|
||||
@ -192,6 +255,7 @@ div#uploadAssetsInputQueue { display: none; }
|
||||
color: #1f82bc;
|
||||
font-size: 0.9em;
|
||||
padding-left: 6px;
|
||||
text-shadow: 1px 1px 1px #fff;
|
||||
}
|
||||
|
||||
#pages-list li strong a:hover { text-decoration: underline; }
|
||||
@ -225,7 +289,7 @@ div#uploadAssetsInputQueue { display: none; }
|
||||
|
||||
#import-steps { margin: 0px 200px; }
|
||||
|
||||
#import-steps li { background: none; }
|
||||
/*#import-steps li { background: none; }
|
||||
|
||||
#import-steps li em {
|
||||
background-position: left 0px;
|
||||
@ -236,7 +300,7 @@ div#uploadAssetsInputQueue { display: none; }
|
||||
display: block;
|
||||
height: 31px;
|
||||
background: transparent url(/images/admin/list/item-right.png) no-repeat right 0;
|
||||
}
|
||||
}*/
|
||||
|
||||
#import-steps li strong a { color: #b7baca; }
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
padding: 0 10px;
|
||||
font-family: Helvetica;
|
||||
-webkit-box-shadow: -3px 3px 12px #818181;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
#page-toolbar ul {
|
||||
@ -26,6 +27,7 @@
|
||||
padding-left: 24px;
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#page-toolbar ul li.link a:hover span { text-decoration: underline; }
|
||||
|
@ -97,6 +97,7 @@ body {
|
||||
font-weight: bold;
|
||||
color: #1e1f26;
|
||||
padding: 7px 0 10px 20px;
|
||||
text-shadow: 1px 1px 1px #fff;
|
||||
}
|
||||
|
||||
#content div.inner p {
|
||||
|
Loading…
Reference in New Issue
Block a user