theme assets
2
.gitignore
vendored
@ -4,3 +4,5 @@ log/*.log
|
|||||||
tmp/**/*
|
tmp/**/*
|
||||||
.DS_Store
|
.DS_Store
|
||||||
rerun.txt
|
rerun.txt
|
||||||
|
uploads
|
||||||
|
spec/tmp
|
||||||
|
4
Gemfile
@ -11,9 +11,11 @@ gem "mongoid", ">= 2.0.0.beta4"
|
|||||||
gem "mongoid_acts_as_tree", :git => 'git://github.com/evansagge/mongoid_acts_as_tree.git'
|
gem "mongoid_acts_as_tree", :git => 'git://github.com/evansagge/mongoid_acts_as_tree.git'
|
||||||
gem "warden"
|
gem "warden"
|
||||||
gem "devise", ">= 1.1.rc0"
|
gem "devise", ">= 1.1.rc0"
|
||||||
gem "haml", '>= 3.0.0.beta.2', :git => 'git://github.com/nex3/haml.git'
|
gem "haml", '>= 3.0.1' #, :git => 'git://github.com/nex3/haml.git'
|
||||||
gem "formtastic", :git => 'git://github.com/justinfrench/formtastic.git', :branch => 'rails3'
|
gem "formtastic", :git => 'git://github.com/justinfrench/formtastic.git', :branch => 'rails3'
|
||||||
gem "mongoid_acts_as_tree", :git => 'git://github.com/evansagge/mongoid_acts_as_tree.git'
|
gem "mongoid_acts_as_tree", :git => 'git://github.com/evansagge/mongoid_acts_as_tree.git'
|
||||||
|
gem "carrierwave", :git => "http://github.com/jnicklas/carrierwave.git"
|
||||||
|
gem "rmagick"
|
||||||
|
|
||||||
|
|
||||||
# Development environment
|
# Development environment
|
||||||
|
54
app/controllers/admin/theme_assets_controller.rb
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
module Admin
|
||||||
|
class ThemeAssetsController < BaseController
|
||||||
|
|
||||||
|
sections 'settings', 'theme_assets'
|
||||||
|
|
||||||
|
def index
|
||||||
|
assets = current_site.theme_assets.all
|
||||||
|
@non_image_assets = assets.find_all { |a| a.stylesheet? || a.javascript? }
|
||||||
|
@image_assets = assets.find_all { |a| a.image? }
|
||||||
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
@asset = current_site.theme_assets.build
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
@asset = current_site.theme_assets.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@asset = current_site.theme_assets.build(params[:theme_asset])
|
||||||
|
|
||||||
|
if @asset.save
|
||||||
|
flash_success!
|
||||||
|
redirect_to edit_admin_theme_asset_url(@asset)
|
||||||
|
else
|
||||||
|
flash_error!
|
||||||
|
render :action => 'new'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@asset = current_site.theme_assets.find(params[:id])
|
||||||
|
|
||||||
|
if @asset.update_attributes(params[:theme_asset])
|
||||||
|
flash_success!
|
||||||
|
redirect_to edit_admin_theme_asset_url(@asset)
|
||||||
|
else
|
||||||
|
flash_error!
|
||||||
|
render :action => 'edit'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@asset = current_site.theme_assets.find(params[:id])
|
||||||
|
@asset.destroy
|
||||||
|
|
||||||
|
flash_success!
|
||||||
|
redirect_to admin_theme_assets_url
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
@ -4,6 +4,9 @@ class PagesController < ActionController::Base
|
|||||||
|
|
||||||
before_filter :require_site
|
before_filter :require_site
|
||||||
|
|
||||||
def show; end
|
def show
|
||||||
|
logger.debug "fullpath = #{request.fullpath}"
|
||||||
|
# @page = current_site.pages.find
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
40
app/helpers/admin/assets_helper.rb
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
module Admin::AssetsHelper
|
||||||
|
|
||||||
|
def vignette_tag(asset)
|
||||||
|
if asset.image?
|
||||||
|
if asset.width < 80 && asset.height < 80
|
||||||
|
image_tag(asset.source.url)
|
||||||
|
else
|
||||||
|
image_tag(asset.source.url(:medium))
|
||||||
|
end
|
||||||
|
# elsif asset.pdf?
|
||||||
|
# image_tag(asset.source.url(:medium))
|
||||||
|
else
|
||||||
|
mime_type_to_image(asset, :medium)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def mime_type_to_image(asset, size = :thumb)
|
||||||
|
mime_type = File.mime_type?(asset.source_filename)
|
||||||
|
filename = "unknown"
|
||||||
|
|
||||||
|
if !(mime_type =~ /pdf/).nil?
|
||||||
|
filename = "PDF"
|
||||||
|
elsif !(mime_type =~ /css/).nil?
|
||||||
|
filename = "CSS"
|
||||||
|
elsif !(mime_type =~ /javascript/).nil?
|
||||||
|
filename = "JAVA"
|
||||||
|
end
|
||||||
|
|
||||||
|
image_tag(File.join("admin", "icons", "filetype", size.to_s, filename + ".png"))
|
||||||
|
end
|
||||||
|
|
||||||
|
def image_dimensions_and_size(asset)
|
||||||
|
content_tag(:small, "#{asset.width}px x #{@asset.height}px | #{number_to_human_size(asset.size)}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def allow_plain_text_editing?(asset)
|
||||||
|
asset.new_record? || asset.stylesheet? || asset.javascript?
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
@ -21,7 +21,7 @@ class Page
|
|||||||
before_validate :normalize_slug
|
before_validate :normalize_slug
|
||||||
before_save { |p| p.parent_id = nil if p.parent_id.blank? }
|
before_save { |p| p.parent_id = nil if p.parent_id.blank? }
|
||||||
before_save :change_parent
|
before_save :change_parent
|
||||||
before_create { |p| p.parts << PagePart.build_body_part }
|
before_create { |p| p.parts << PagePart.build_body_part if p.parts.empty? }
|
||||||
before_create { |p| p.fix_position(false) }
|
before_create { |p| p.fix_position(false) }
|
||||||
before_create :add_to_list_bottom
|
before_create :add_to_list_bottom
|
||||||
before_destroy :do_not_remove_index_and_404_pages
|
before_destroy :do_not_remove_index_and_404_pages
|
||||||
|
@ -11,6 +11,7 @@ class Site
|
|||||||
has_many_related :pages
|
has_many_related :pages
|
||||||
has_many_related :layouts
|
has_many_related :layouts
|
||||||
has_many_related :snippets
|
has_many_related :snippets
|
||||||
|
has_many_related :theme_assets
|
||||||
embeds_many :memberships
|
embeds_many :memberships
|
||||||
|
|
||||||
## validations ##
|
## validations ##
|
||||||
@ -81,7 +82,7 @@ class Site
|
|||||||
end
|
end
|
||||||
|
|
||||||
def destroy_in_cascade!
|
def destroy_in_cascade!
|
||||||
%w{pages layouts snippets}.each do |association|
|
%w{pages layouts snippets theme_assets}.each do |association|
|
||||||
self.send(association).destroy_all
|
self.send(association).destroy_all
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
94
app/models/theme_asset.rb
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
class ThemeAsset
|
||||||
|
include Mongoid::Document
|
||||||
|
include Mongoid::Timestamps
|
||||||
|
|
||||||
|
## fields ##
|
||||||
|
field :slug, :type => String
|
||||||
|
field :content_type, :type => String
|
||||||
|
field :width, :type => Integer
|
||||||
|
field :height, :type => Integer
|
||||||
|
field :size, :type => Integer
|
||||||
|
mount_uploader :source, ThemeAssetUploader
|
||||||
|
|
||||||
|
## associations ##
|
||||||
|
belongs_to_related :site
|
||||||
|
|
||||||
|
## callbacks ##
|
||||||
|
before_validate :sanitize_slug
|
||||||
|
before_validate :store_plain_text
|
||||||
|
before_save :set_slug
|
||||||
|
|
||||||
|
## validations ##
|
||||||
|
validate :extname_can_not_be_changed
|
||||||
|
validates_presence_of :site
|
||||||
|
validates_presence_of :slug, :if => Proc.new { |a| a.new_record? && a.performing_plain_text? }
|
||||||
|
validates_integrity_of :source
|
||||||
|
|
||||||
|
## accessors ##
|
||||||
|
attr_accessor :performing_plain_text
|
||||||
|
|
||||||
|
## methods ##
|
||||||
|
|
||||||
|
%w{image stylesheet javascript}.each do |type|
|
||||||
|
define_method("#{type}?") do
|
||||||
|
self.content_type == type
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def plain_text
|
||||||
|
@plain_text ||= (if self.stylesheet? || self.javascript?
|
||||||
|
File.read(self.source.path)
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def plain_text=(source)
|
||||||
|
self.performing_plain_text = true if self.performing_plain_text.nil?
|
||||||
|
@plain_text = source
|
||||||
|
end
|
||||||
|
|
||||||
|
def performing_plain_text?
|
||||||
|
!(self.performing_plain_text.blank? || self.performing_plain_text == 'false' || self.performing_plain_text == false)
|
||||||
|
end
|
||||||
|
|
||||||
|
def store_plain_text
|
||||||
|
return if self.plain_text.blank?
|
||||||
|
|
||||||
|
self.source = CarrierWave::SanitizedFile.new({
|
||||||
|
:tempfile => StringIO.new(self.plain_text),
|
||||||
|
:filename => self.filename
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
def filename
|
||||||
|
if not self.image?
|
||||||
|
"#{self.slug}.#{self.stylesheet? ? 'css' : 'js'}"
|
||||||
|
else
|
||||||
|
"#{self.slug}#{File.extname(self.source.file.original_filename)}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def sanitize_slug
|
||||||
|
self.slug.slugify!(:underscore => true) 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?
|
||||||
|
|
||||||
|
Rails.logger.debug "previous = #{self.source.file.original_filename.inspect} / #{self.source_filename.inspect}"
|
||||||
|
|
||||||
|
if File.extname(self.source.file.original_filename) != File.extname(self.source_filename)
|
||||||
|
self.errors.add(:source, :extname_changed)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
87
app/uploaders/theme_asset_uploader.rb
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
class ThemeAssetUploader < CarrierWave::Uploader::Base
|
||||||
|
|
||||||
|
include CarrierWave::RMagick
|
||||||
|
|
||||||
|
# Choose what kind of storage to use for this uploader
|
||||||
|
# storage :file
|
||||||
|
# storage :s3
|
||||||
|
|
||||||
|
# Override the directory where uploaded files will be stored
|
||||||
|
# This is a sensible default for uploaders that are meant to be mounted:
|
||||||
|
def store_dir
|
||||||
|
"sites/#{model.site_id}/themes/#{model.id}"
|
||||||
|
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
|
||||||
|
|
||||||
|
process :set_content_type
|
||||||
|
process :set_size
|
||||||
|
process :set_width_and_height
|
||||||
|
|
||||||
|
def set_content_type
|
||||||
|
value = :other
|
||||||
|
|
||||||
|
self.class.content_types.each_pair do |type, rules|
|
||||||
|
rules.each do |rule|
|
||||||
|
case rule
|
||||||
|
when String then value = type if file.content_type == rule
|
||||||
|
when Regexp then value = type if (file.content_type =~ rule) == 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
model.content_type = value
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_size
|
||||||
|
model.size = file.size
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_width_and_height
|
||||||
|
if model.image?
|
||||||
|
model.width, model.height = `identify -format "%wx%h" #{file.path}`.split(/x/).collect(&:to_i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.content_types
|
||||||
|
{
|
||||||
|
:image => ['image/jpeg', 'image/pjpeg', 'image/gif', 'image/png', 'image/x-png', 'image/jpg'],
|
||||||
|
:stylesheet => ['text/css'],
|
||||||
|
:javascript => ['text/javascript', 'text/js', 'application/x-javascript']
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def extension_white_list
|
||||||
|
%w(jpg jpeg gif png css js)
|
||||||
|
end
|
||||||
|
|
||||||
|
def filename
|
||||||
|
Rails.logger.debug "slug ===> #{model.slug} / #{model.content_type} / #{original_filename}"
|
||||||
|
|
||||||
|
if model.slug.present?
|
||||||
|
model.filename
|
||||||
|
else
|
||||||
|
extension = File.extname(original_filename)
|
||||||
|
basename = File.basename(original_filename, extension).slugify(:underscore => true)
|
||||||
|
"#{basename}#{extension}"
|
||||||
|
end
|
||||||
|
#
|
||||||
|
# original_filename
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
@ -34,7 +34,7 @@
|
|||||||
= f.custom_input :language, { :css => 'full', :with_label => false } do
|
= f.custom_input :language, { :css => 'full', :with_label => false } do
|
||||||
- Locomotive.config.locales.each do |locale|
|
- Locomotive.config.locales.each do |locale|
|
||||||
%span
|
%span
|
||||||
= image_tag "admin/flags/#{locale}.png"
|
= image_tag "admin/icons/flags/#{locale}.png"
|
||||||
= f.radio_button :locale, locale
|
= f.radio_button :locale, locale
|
||||||
|
|
||||||
= t(".#{locale}")
|
= t(".#{locale}")
|
||||||
|
@ -2,4 +2,5 @@
|
|||||||
= admin_submenu_item 'site', edit_admin_current_site_url
|
= admin_submenu_item 'site', edit_admin_current_site_url
|
||||||
= admin_submenu_item 'layouts', admin_layouts_url
|
= admin_submenu_item 'layouts', admin_layouts_url
|
||||||
= admin_submenu_item 'snippets', admin_snippets_url
|
= admin_submenu_item 'snippets', admin_snippets_url
|
||||||
|
= admin_submenu_item 'theme_assets', admin_theme_assets_url
|
||||||
= admin_submenu_item 'account', edit_admin_my_account_url
|
= admin_submenu_item 'account', edit_admin_my_account_url
|
7
app/views/admin/theme_assets/_asset.html.haml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
%li{ :class => "asset #{'last' if (asset_counter + 1) % 6 == 0}"}
|
||||||
|
%h4= link_to truncate(asset.slug, :length => 22), edit_admin_theme_asset_path(asset)
|
||||||
|
.image
|
||||||
|
.inside
|
||||||
|
= vignette_tag(asset)
|
||||||
|
.actions
|
||||||
|
= link_to image_tag('admin/list/icons/cross.png'), admin_theme_asset_path(asset), :class => 'remove', :confirm => t('admin.messages.confirm'), :method => :delete
|
36
app/views/admin/theme_assets/_form.html.haml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
- content_for :head do
|
||||||
|
= javascript_include_tag 'admin/plugins/codemirror/codemirror', 'admin/theme_assets.js'
|
||||||
|
|
||||||
|
= f.hidden_field :performing_plain_text
|
||||||
|
|
||||||
|
#file-selector{ :class => "selector #{'hidden' if @asset.performing_plain_text?}" }
|
||||||
|
= f.inputs :name => :information do
|
||||||
|
= f.input :source
|
||||||
|
|
||||||
|
- if @asset.new_record? || !@asset.image?
|
||||||
|
%span.alt
|
||||||
|
= t('admin.theme_assets.form.choose_plain_text')
|
||||||
|
|
||||||
|
- if allow_plain_text_editing?(@asset)
|
||||||
|
#text-selector{ :class => "selector #{'hidden' if !@asset.performing_plain_text?}", :style => "#{'display: none' if !@asset.performing_plain_text?}" }
|
||||||
|
= f.inputs :name => :code, :class => 'inputs code' do
|
||||||
|
|
||||||
|
- if @asset.new_record?
|
||||||
|
= f.input :slug
|
||||||
|
|
||||||
|
= f.custom_input :content_type do
|
||||||
|
= f.select :content_type, ["stylesheet", "javascript"]
|
||||||
|
|
||||||
|
= f.custom_input :plain_text, :css => 'full', :with_label => false do
|
||||||
|
%code{ :class => (@asset.new_record? || (@asset.size && @asset.size > 40000) ? 'nude' : @asset.content_type) }
|
||||||
|
= f.text_area :plain_text
|
||||||
|
|
||||||
|
%span.alt
|
||||||
|
= t('admin.theme_assets.form.choose_file')
|
||||||
|
|
||||||
|
- if @asset.image?
|
||||||
|
= f.foldable_inputs :name => "#{t('formtastic.titles.preview')} #{image_dimensions_and_size(@asset)}", :class => 'preview' do
|
||||||
|
%li
|
||||||
|
.image
|
||||||
|
.inside
|
||||||
|
= image_tag(@asset.source.url(:preview))
|
15
app/views/admin/theme_assets/edit.html.haml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
- title t('.title', :file => @asset.source_filename)
|
||||||
|
|
||||||
|
- content_for :submenu do
|
||||||
|
= render 'admin/shared/menu/settings'
|
||||||
|
|
||||||
|
- content_for :buttons do
|
||||||
|
= admin_button_tag t('admin.theme_assets.index.new'), new_admin_theme_asset_url, :class => 'add'
|
||||||
|
|
||||||
|
%p= t('.help')
|
||||||
|
|
||||||
|
= semantic_form_for @asset, :url => admin_theme_asset_url(@asset), :html => { :multipart => true } do |form|
|
||||||
|
|
||||||
|
= render 'form', :f => form
|
||||||
|
|
||||||
|
= render 'admin/shared/form_actions', :back_url => admin_theme_assets_url, :button_label => :update
|
27
app/views/admin/theme_assets/index.html.haml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
- title t('.title')
|
||||||
|
|
||||||
|
- content_for :submenu do
|
||||||
|
= render 'admin/shared/menu/settings'
|
||||||
|
|
||||||
|
- content_for :buttons do
|
||||||
|
= admin_button_tag :new, new_admin_theme_asset_url, :class => 'add'
|
||||||
|
|
||||||
|
%p= t('.help')
|
||||||
|
|
||||||
|
%h3= t('.css_and_js')
|
||||||
|
- if @non_image_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
|
||||||
|
|
||||||
|
%br
|
||||||
|
|
||||||
|
%h3= t('.images')
|
||||||
|
- if @image_assets.empty?
|
||||||
|
%p.no-items= t('.no_items', :url => new_admin_theme_asset_url)
|
||||||
|
- else
|
||||||
|
%ul.assets
|
||||||
|
= render :partial => 'asset', :collection => @image_assets
|
||||||
|
%li.clear
|
12
app/views/admin/theme_assets/new.html.haml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
- title t('.title')
|
||||||
|
|
||||||
|
- content_for :submenu do
|
||||||
|
= render 'admin/shared/menu/settings'
|
||||||
|
|
||||||
|
%p= t('.help')
|
||||||
|
|
||||||
|
= semantic_form_for @asset, :url => admin_theme_assets_url, :html => { :multipart => true } do |form|
|
||||||
|
|
||||||
|
= render 'form', :f => form
|
||||||
|
|
||||||
|
= render 'admin/shared/form_actions', :back_url => admin_theme_assets_url, :button_label => :create
|
@ -27,3 +27,9 @@ Locomotive::Application.configure do
|
|||||||
:domain => "example.com"
|
:domain => "example.com"
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
CarrierWave.configure do |config|
|
||||||
|
config.storage = :file
|
||||||
|
config.root = File.join(Rails.root, 'public')
|
||||||
|
end
|
||||||
|
|
||||||
|
@ -27,3 +27,7 @@ Locomotive::Application.configure do
|
|||||||
# like if you have constraints or database-specific column types
|
# like if you have constraints or database-specific column types
|
||||||
# config.active_record.schema_format = :sql
|
# config.active_record.schema_format = :sql
|
||||||
end
|
end
|
||||||
|
|
||||||
|
CarrierWave.configure do |config|
|
||||||
|
config.storage = :file
|
||||||
|
end
|
48
config/initializers/carrierwave.rb
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
require 'carrierwave/orm/mongoid'
|
||||||
|
|
||||||
|
module CarrierWave
|
||||||
|
|
||||||
|
class SanitizedFile
|
||||||
|
|
||||||
|
def original_filename=(filename)
|
||||||
|
@original_filename = filename
|
||||||
|
end
|
||||||
|
|
||||||
|
def content_type=(content_type)
|
||||||
|
@content_type = content_type
|
||||||
|
end
|
||||||
|
|
||||||
|
# http://github.com/jnicklas/carrierwave/issuesearch?state=closed&q=content+type#issue/48
|
||||||
|
def copy_to_with_content_type(new_path, permissions=nil)
|
||||||
|
new_file = self.copy_to_without_content_type(new_path, permissions)
|
||||||
|
new_file.content_type = self.content_type
|
||||||
|
new_file
|
||||||
|
end
|
||||||
|
|
||||||
|
alias_method_chain :copy_to, :content_type
|
||||||
|
|
||||||
|
# FIXME (Did) CarrierWave speaks mime type now
|
||||||
|
def content_type
|
||||||
|
return @content_type if @content_type
|
||||||
|
if @file.respond_to?(:content_type) and @file.content_type
|
||||||
|
@file.content_type.chomp
|
||||||
|
else
|
||||||
|
File.mime_type?(@file) if @file.is_a?(String)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
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")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -23,6 +23,7 @@ en:
|
|||||||
snippets: Snippets
|
snippets: Snippets
|
||||||
account: My account
|
account: My account
|
||||||
site: Site
|
site: Site
|
||||||
|
theme_assets: Theme files
|
||||||
footer:
|
footer:
|
||||||
developed_by: Developed by
|
developed_by: Developed by
|
||||||
powered_by: and Powered by
|
powered_by: and Powered by
|
||||||
@ -97,6 +98,20 @@ en:
|
|||||||
en: English
|
en: English
|
||||||
fr: French
|
fr: French
|
||||||
|
|
||||||
|
theme_assets:
|
||||||
|
index:
|
||||||
|
title: Listing theme files
|
||||||
|
new: new file
|
||||||
|
css_and_js: Style and javascript
|
||||||
|
images: Images
|
||||||
|
no_items: "There are no files for now. Just click <a href=\"{{url}}\">here</a> to create the first one."
|
||||||
|
new:
|
||||||
|
title: New file
|
||||||
|
edit:
|
||||||
|
title: "Editing {{file}}"
|
||||||
|
form:
|
||||||
|
choose_file: Choose file
|
||||||
|
choose_plain_text: Choose plain text
|
||||||
|
|
||||||
formtastic:
|
formtastic:
|
||||||
titles:
|
titles:
|
||||||
@ -109,6 +124,14 @@ en:
|
|||||||
access_points: Access points
|
access_points: Access points
|
||||||
memberships: Accounts
|
memberships: Accounts
|
||||||
membership_email: Account email
|
membership_email: Account email
|
||||||
|
file: File
|
||||||
|
preview: Preview
|
||||||
|
labels:
|
||||||
|
theme_asset:
|
||||||
|
new:
|
||||||
|
source: File
|
||||||
|
edit:
|
||||||
|
source: Replace file
|
||||||
hints:
|
hints:
|
||||||
page:
|
page:
|
||||||
keywords: "Meta keywords used within the head tag of the page. They are separeted by an empty space. Required for SEO."
|
keywords: "Meta keywords used within the head tag of the page. They are separeted by an empty space. Required for SEO."
|
||||||
@ -117,4 +140,8 @@ en:
|
|||||||
slug: "You need to know it in order to insert the snippet inside a page or a layout"
|
slug: "You need to know it in order to insert the snippet inside a page or a layout"
|
||||||
site:
|
site:
|
||||||
domain_name: "ex: locomotiveapp.org"
|
domain_name: "ex: locomotiveapp.org"
|
||||||
|
theme_asset:
|
||||||
|
slug: "You do not need to add the extension file (.css or .js)"
|
||||||
|
edit:
|
||||||
|
source: "You can replace it by a file of the same extension"
|
||||||
|
|
||||||
|
4
config/locales/carrierwave_en.yml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
en:
|
||||||
|
carrierwave:
|
||||||
|
errors:
|
||||||
|
integrity: 'is not an allowed type of file.'
|
4
config/locales/carrierwave_fr.yml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
fr:
|
||||||
|
carrierwave:
|
||||||
|
errors:
|
||||||
|
integrity: "n'est pas un type de fichier autorisé"
|
@ -6,6 +6,7 @@ en:
|
|||||||
missing_content_for_layout: "should contain 'content_for_layout' liquid tag"
|
missing_content_for_layout: "should contain 'content_for_layout' liquid tag"
|
||||||
needs_admin_account: "One admin account is required at least"
|
needs_admin_account: "One admin account is required at least"
|
||||||
protected_page: "You can not remove index or 404 pages"
|
protected_page: "You can not remove index or 404 pages"
|
||||||
|
extname_changed: "New file does not have the original extension"
|
||||||
|
|
||||||
attributes:
|
attributes:
|
||||||
defaults:
|
defaults:
|
||||||
|
@ -36,8 +36,11 @@ Locomotive::Application.routes.draw do |map|
|
|||||||
resource :my_account
|
resource :my_account
|
||||||
|
|
||||||
resources :memberships
|
resources :memberships
|
||||||
|
|
||||||
|
resources :theme_assets
|
||||||
end
|
end
|
||||||
|
|
||||||
# magic url
|
# magic url
|
||||||
match '/' => 'pages#show'
|
match '/' => 'pages#show'
|
||||||
|
match '*path' => 'pages#show'
|
||||||
end
|
end
|
||||||
|
9
doc/TODO
@ -34,6 +34,15 @@ x create 404 + index pages once a site is created
|
|||||||
x can not delete index + 404 pages
|
x can not delete index + 404 pages
|
||||||
x validates_uniqueness_of :slug, :scope => :id
|
x validates_uniqueness_of :slug, :scope => :id
|
||||||
x domain scoping when authenticating
|
x domain scoping when authenticating
|
||||||
|
- theme assets
|
||||||
|
x create / update
|
||||||
|
x slug
|
||||||
|
x filename from slug
|
||||||
|
x can not replace a javascript by a stylesheet
|
||||||
|
- disable version if not image
|
||||||
|
- asset collections
|
||||||
|
- assets
|
||||||
|
- custom resizing
|
||||||
|
|
||||||
|
|
||||||
BACKLOG:
|
BACKLOG:
|
||||||
|
@ -5,7 +5,7 @@ class String
|
|||||||
# end
|
# end
|
||||||
|
|
||||||
def slugify(options = {})
|
def slugify(options = {})
|
||||||
options = { :sep => '_', :without_extension => false, :downcase => false }.merge(options)
|
options = { :sep => '_', :without_extension => false, :downcase => false, :underscore => false }.merge(options)
|
||||||
# replace accented chars with ther ascii equivalents
|
# replace accented chars with ther ascii equivalents
|
||||||
s = ActiveSupport::Inflector.transliterate(self).to_s
|
s = ActiveSupport::Inflector.transliterate(self).to_s
|
||||||
# No more than one slash in a row
|
# No more than one slash in a row
|
||||||
@ -20,6 +20,8 @@ class String
|
|||||||
s.downcase! if options[:downcase]
|
s.downcase! if options[:downcase]
|
||||||
# Turn unwanted chars into the seperator
|
# Turn unwanted chars into the seperator
|
||||||
s.gsub!(/[^a-zA-Z0-9\-_\+\/]+/i, options[:sep])
|
s.gsub!(/[^a-zA-Z0-9\-_\+\/]+/i, options[:sep])
|
||||||
|
# Underscore
|
||||||
|
s.gsub!(/[\-]/i, '') if options[:underscore]
|
||||||
s
|
s
|
||||||
end
|
end
|
||||||
|
|
||||||
|
BIN
public/images/admin/icons/filetype/medium/AC3.png
Executable file
After Width: | Height: | Size: 6.7 KiB |
BIN
public/images/admin/icons/filetype/medium/ACE.png
Executable file
After Width: | Height: | Size: 8.1 KiB |
BIN
public/images/admin/icons/filetype/medium/ADE.png
Executable file
After Width: | Height: | Size: 8.0 KiB |
BIN
public/images/admin/icons/filetype/medium/ADP.png
Executable file
After Width: | Height: | Size: 8.9 KiB |
BIN
public/images/admin/icons/filetype/medium/AI.png
Executable file
After Width: | Height: | Size: 7.8 KiB |
BIN
public/images/admin/icons/filetype/medium/AIFF.png
Executable file
After Width: | Height: | Size: 9.6 KiB |
BIN
public/images/admin/icons/filetype/medium/AU.png
Executable file
After Width: | Height: | Size: 9.6 KiB |
BIN
public/images/admin/icons/filetype/medium/AVI.png
Executable file
After Width: | Height: | Size: 8.9 KiB |
BIN
public/images/admin/icons/filetype/medium/BAT.png
Executable file
After Width: | Height: | Size: 8.4 KiB |
BIN
public/images/admin/icons/filetype/medium/BIN.png
Executable file
After Width: | Height: | Size: 10 KiB |
BIN
public/images/admin/icons/filetype/medium/BMP.png
Executable file
After Width: | Height: | Size: 11 KiB |
BIN
public/images/admin/icons/filetype/medium/BUP.png
Executable file
After Width: | Height: | Size: 8.0 KiB |
BIN
public/images/admin/icons/filetype/medium/CAB.png
Executable file
After Width: | Height: | Size: 7.7 KiB |
BIN
public/images/admin/icons/filetype/medium/CAT.png
Executable file
After Width: | Height: | Size: 9.3 KiB |
BIN
public/images/admin/icons/filetype/medium/CHM.png
Executable file
After Width: | Height: | Size: 8.9 KiB |
BIN
public/images/admin/icons/filetype/medium/CSS.png
Executable file
After Width: | Height: | Size: 7.7 KiB |
BIN
public/images/admin/icons/filetype/medium/CUE.png
Executable file
After Width: | Height: | Size: 7.2 KiB |
BIN
public/images/admin/icons/filetype/medium/DAT.png
Executable file
After Width: | Height: | Size: 8.4 KiB |
BIN
public/images/admin/icons/filetype/medium/DCR.png
Executable file
After Width: | Height: | Size: 6.6 KiB |
BIN
public/images/admin/icons/filetype/medium/DER.png
Executable file
After Width: | Height: | Size: 7.1 KiB |
BIN
public/images/admin/icons/filetype/medium/DIC.png
Executable file
After Width: | Height: | Size: 13 KiB |
BIN
public/images/admin/icons/filetype/medium/DIVX.png
Executable file
After Width: | Height: | Size: 11 KiB |
BIN
public/images/admin/icons/filetype/medium/DIZ.png
Executable file
After Width: | Height: | Size: 8.2 KiB |
BIN
public/images/admin/icons/filetype/medium/DLL.png
Executable file
After Width: | Height: | Size: 7.4 KiB |
BIN
public/images/admin/icons/filetype/medium/DOC.png
Executable file
After Width: | Height: | Size: 8.3 KiB |
BIN
public/images/admin/icons/filetype/medium/DOCX.png
Executable file
After Width: | Height: | Size: 11 KiB |
BIN
public/images/admin/icons/filetype/medium/DOS.png
Executable file
After Width: | Height: | Size: 8.7 KiB |
BIN
public/images/admin/icons/filetype/medium/DVD.png
Executable file
After Width: | Height: | Size: 9.3 KiB |
BIN
public/images/admin/icons/filetype/medium/DWG.png
Executable file
After Width: | Height: | Size: 9.8 KiB |
BIN
public/images/admin/icons/filetype/medium/DWT.png
Executable file
After Width: | Height: | Size: 9.9 KiB |
BIN
public/images/admin/icons/filetype/medium/EMF.png
Executable file
After Width: | Height: | Size: 9.4 KiB |
BIN
public/images/admin/icons/filetype/medium/EXC.png
Executable file
After Width: | Height: | Size: 7.9 KiB |
BIN
public/images/admin/icons/filetype/medium/FON.png
Executable file
After Width: | Height: | Size: 7.5 KiB |
BIN
public/images/admin/icons/filetype/medium/GIF.png
Executable file
After Width: | Height: | Size: 8.5 KiB |
BIN
public/images/admin/icons/filetype/medium/HLP.png
Executable file
After Width: | Height: | Size: 8.1 KiB |
BIN
public/images/admin/icons/filetype/medium/HTML.png
Executable file
After Width: | Height: | Size: 10 KiB |
BIN
public/images/admin/icons/filetype/medium/IFO.png
Executable file
After Width: | Height: | Size: 8.3 KiB |
BIN
public/images/admin/icons/filetype/medium/INF.png
Executable file
After Width: | Height: | Size: 8.3 KiB |
BIN
public/images/admin/icons/filetype/medium/INI.png
Executable file
After Width: | Height: | Size: 8.1 KiB |
BIN
public/images/admin/icons/filetype/medium/INS.png
Executable file
After Width: | Height: | Size: 10 KiB |
BIN
public/images/admin/icons/filetype/medium/IP.png
Executable file
After Width: | Height: | Size: 9.3 KiB |
BIN
public/images/admin/icons/filetype/medium/ISO.png
Executable file
After Width: | Height: | Size: 8.8 KiB |
BIN
public/images/admin/icons/filetype/medium/ISP.png
Executable file
After Width: | Height: | Size: 10 KiB |
BIN
public/images/admin/icons/filetype/medium/JAVA.png
Executable file
After Width: | Height: | Size: 8.2 KiB |
BIN
public/images/admin/icons/filetype/medium/JFIF.png
Executable file
After Width: | Height: | Size: 9.3 KiB |
BIN
public/images/admin/icons/filetype/medium/JPEG.png
Executable file
After Width: | Height: | Size: 9.8 KiB |
BIN
public/images/admin/icons/filetype/medium/JPG.png
Executable file
After Width: | Height: | Size: 11 KiB |
BIN
public/images/admin/icons/filetype/medium/LOG.png
Executable file
After Width: | Height: | Size: 7.9 KiB |
BIN
public/images/admin/icons/filetype/medium/M4A.png
Executable file
After Width: | Height: | Size: 8.8 KiB |
BIN
public/images/admin/icons/filetype/medium/MID.png
Executable file
After Width: | Height: | Size: 8.4 KiB |
BIN
public/images/admin/icons/filetype/medium/MMF.png
Executable file
After Width: | Height: | Size: 7.1 KiB |
BIN
public/images/admin/icons/filetype/medium/MMM.png
Executable file
After Width: | Height: | Size: 11 KiB |
BIN
public/images/admin/icons/filetype/medium/MOV.png
Executable file
After Width: | Height: | Size: 9.7 KiB |
BIN
public/images/admin/icons/filetype/medium/MOVIE.png
Executable file
After Width: | Height: | Size: 11 KiB |
BIN
public/images/admin/icons/filetype/medium/MP2.png
Executable file
After Width: | Height: | Size: 8.5 KiB |
BIN
public/images/admin/icons/filetype/medium/MP2V.png
Executable file
After Width: | Height: | Size: 11 KiB |
BIN
public/images/admin/icons/filetype/medium/MP3.png
Executable file
After Width: | Height: | Size: 7.6 KiB |
BIN
public/images/admin/icons/filetype/medium/MP4.png
Executable file
After Width: | Height: | Size: 12 KiB |
BIN
public/images/admin/icons/filetype/medium/MPE.png
Executable file
After Width: | Height: | Size: 9.6 KiB |
BIN
public/images/admin/icons/filetype/medium/MPEG.png
Executable file
After Width: | Height: | Size: 12 KiB |
BIN
public/images/admin/icons/filetype/medium/MPG.png
Executable file
After Width: | Height: | Size: 11 KiB |
BIN
public/images/admin/icons/filetype/medium/MPV2.png
Executable file
After Width: | Height: | Size: 11 KiB |
BIN
public/images/admin/icons/filetype/medium/NFO.png
Executable file
After Width: | Height: | Size: 8.1 KiB |
BIN
public/images/admin/icons/filetype/medium/PDD.png
Executable file
After Width: | Height: | Size: 7.3 KiB |
BIN
public/images/admin/icons/filetype/medium/PDF.png
Executable file
After Width: | Height: | Size: 7.3 KiB |
BIN
public/images/admin/icons/filetype/medium/PHP.png
Executable file
After Width: | Height: | Size: 7.8 KiB |
BIN
public/images/admin/icons/filetype/medium/PNG.png
Executable file
After Width: | Height: | Size: 11 KiB |
BIN
public/images/admin/icons/filetype/medium/PPT.png
Executable file
After Width: | Height: | Size: 7.5 KiB |
BIN
public/images/admin/icons/filetype/medium/PPTX.png
Executable file
After Width: | Height: | Size: 9.7 KiB |
BIN
public/images/admin/icons/filetype/medium/PSD.png
Executable file
After Width: | Height: | Size: 7.4 KiB |
BIN
public/images/admin/icons/filetype/medium/RAR.png
Executable file
After Width: | Height: | Size: 9.5 KiB |
BIN
public/images/admin/icons/filetype/medium/REG.png
Executable file
After Width: | Height: | Size: 9.1 KiB |
BIN
public/images/admin/icons/filetype/medium/RTF.png
Executable file
After Width: | Height: | Size: 6.8 KiB |
BIN
public/images/admin/icons/filetype/medium/SCP.png
Executable file
After Width: | Height: | Size: 7.9 KiB |