diff --git a/Gemfile b/Gemfile
index a002defd..63b0a639 100644
--- a/Gemfile
+++ b/Gemfile
@@ -52,6 +52,7 @@ group :test do
gem 'rspec-rails', '2.3.1'
gem 'factory_girl_rails'
gem 'pickle'
+ gem 'xpath', :git => 'https://github.com/wunderbread/xpath.git'
gem 'capybara'
gem 'database_cleaner'
diff --git a/Gemfile.lock b/Gemfile.lock
index e646dbdc..305eebd4 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -4,6 +4,13 @@ GIT
specs:
mocha (0.9.12.20110213002255)
+GIT
+ remote: https://github.com/wunderbread/xpath.git
+ revision: d04da707886287e7dfe82705fda5b3d4f65e94c3
+ specs:
+ xpath (0.1.2)
+ nokogiri (~> 1.4)
+
GEM
remote: http://rubygems.org/
specs:
@@ -45,7 +52,7 @@ GEM
bson (1.2.4)
bson_ext (1.2.4)
builder (2.1.2)
- capybara (0.4.1.2)
+ capybara (0.4.0)
celerity (>= 0.7.9)
culerity (>= 0.2.4)
mime-types (>= 1.16)
@@ -53,7 +60,7 @@ GEM
rack (>= 1.0.0)
rack-test (>= 0.5.4)
selenium-webdriver (>= 0.0.27)
- xpath (~> 0.1.3)
+ xpath (~> 0.1.2)
celerity (0.8.8)
childprocess (0.1.7)
ffi (~> 0.6.3)
@@ -242,8 +249,6 @@ GEM
warden (0.10.7)
rack (>= 1.0.0)
will_paginate (3.0.pre2)
- xpath (0.1.3)
- nokogiri (~> 1.3)
yard (0.6.4)
yui-compressor (0.9.4)
@@ -291,3 +296,4 @@ DEPENDENCIES
unicorn
warden
will_paginate
+ xpath!
diff --git a/app/controllers/admin/imports_controller.rb b/app/controllers/admin/imports_controller.rb
index c611ce23..ab717bf1 100644
--- a/app/controllers/admin/imports_controller.rb
+++ b/app/controllers/admin/imports_controller.rb
@@ -34,7 +34,7 @@ module Admin
rescue Exception => e
logger.error "[Locomotive import] #{e.message} / #{e.backtrace}"
- @error = t('errors.messages.invalid_theme_file')
+ @error = e.message
flash[:alert] = t('flash.admin.imports.create.alert')
render 'new'
diff --git a/app/models/editable_element.rb b/app/models/editable_element.rb
index 109bc121..60c563c8 100644
--- a/app/models/editable_element.rb
+++ b/app/models/editable_element.rb
@@ -6,8 +6,10 @@ class EditableElement
field :slug
field :block
field :default_content
+ field :default_attribute
field :hint
field :disabled, :type => Boolean, :default => false
+ field :assignable, :type => Boolean, :default => true
field :from_parent, :type => Boolean, :default => false
## associations ##
diff --git a/app/models/extensions/page/editable_elements.rb b/app/models/extensions/page/editable_elements.rb
index 8398f4cc..e0a6d746 100644
--- a/app/models/extensions/page/editable_elements.rb
+++ b/app/models/extensions/page/editable_elements.rb
@@ -62,17 +62,23 @@ module Models
def merge_editable_elements_from_page(source)
source.editable_elements.each do |el|
- next if el.disabled?
+ next if el.disabled? or !el.assignable?
existing_el = self.find_editable_element(el.block, el.slug)
if existing_el.nil? # new one from parents
new_attributes = el.attributes.merge(:from_parent => true)
- new_attributes[:default_content] = el.content
-
+ if new_attributes['default_attribute'].present?
+ new_attributes['default_content'] = self.send(new_attributes['default_attribute']) || el.content
+ else
+ new_attributes['default_content'] = el.content
+ end
+
self.editable_elements.build(new_attributes, el.class)
- else
+ elsif existing_el.default_attribute.nil?
existing_el.attributes = { :disabled => false, :default_content => el.content }
+ else
+ existing_el.attributes = { :disabled => false }
end
end
end
diff --git a/app/models/extensions/page/parse.rb b/app/models/extensions/page/parse.rb
index 7395b241..ec304ee5 100644
--- a/app/models/extensions/page/parse.rb
+++ b/app/models/extensions/page/parse.rb
@@ -37,9 +37,9 @@ module Models
begin
self._parse_and_serialize_template
rescue ::Liquid::SyntaxError => error
- @parsing_errors << :liquid_syntax
+ @parsing_errors << I18n.t(:liquid_syntax, :fullpath => self.fullpath, :error => error.to_s,:scope => [:errors, :messages])
rescue ::Locomotive::Liquid::PageNotFound => error
- @parsing_errors << :liquid_extend
+ @parsing_errors << I18n.t(:liquid_extend, :fullpath => self.fullpath,:scope => [:errors, :messages])
end
end
end
diff --git a/config/locales/default.de.yml b/config/locales/default.de.yml
index 1b82a2bf..99615424 100644
--- a/config/locales/default.de.yml
+++ b/config/locales/default.de.yml
@@ -32,8 +32,8 @@ de:
protected_page: "Du kannst keine Index oder 404 Seiten löschen"
extname_changed: "Die neue Datei hat nicht die originale Dateiendung"
array_too_short: "ist zu kurz (minimale Element-Zahl ist %{count})"
- liquid_syntax: "Liquid Syntax-Fehler, bitte überprüfe die Syntax"
- liquid_extend: "Die Seite verwendet eine Vorlage, die gar nicht existiert"
+ liquid_syntax: "Liquid Syntax-Fehler, bitte überprüfe die Syntax ('%{error}'/'%{fullpath}')"
+ liquid_extend: "Die Seite '%{fullpath}' verwendet eine Vorlage, die gar nicht existiert"
invalid_theme_file: "darf nicht leer sein oder ist keine zip-Datei"
attributes:
diff --git a/config/locales/default.en.yml b/config/locales/default.en.yml
index 9b892cbb..9793b90e 100644
--- a/config/locales/default.en.yml
+++ b/config/locales/default.en.yml
@@ -11,8 +11,8 @@ en:
protected_page: "You can not remove index or 404 pages"
extname_changed: "New file does not have the original extension"
array_too_short: "is too small (minimum element number is %{count})"
- liquid_syntax: "Liquid Syntax error, please check the syntax"
- liquid_extend: "The page extends a template which does not exist"
+ liquid_syntax: "Liquid Syntax error ('%{error}' on '%{fullpath}')"
+ liquid_extend: "The page '%{fullpath}' extends a template which does not exist"
invalid_theme_file: "can't be blank or isn't a zip file"
attributes:
diff --git a/config/locales/default.fr.yml b/config/locales/default.fr.yml
index 20bb5c5b..9ec2aef7 100644
--- a/config/locales/default.fr.yml
+++ b/config/locales/default.fr.yml
@@ -32,8 +32,8 @@ fr:
protected_page: "Vous ne pouvez pas supprimer les pages index et 404"
extname_changed: "Nouveau fichier n'a pas l'extension original"
array_too_short: "est trop petit (le nombre minimum d'éléments est %{count})"
- liquid_syntax: "Erreur de syntaxe dans les sections de page, veuillez vérifier la syntaxe"
- liquid_extend: "La page étend le contenu d'une page qui n'existe pas"
+ liquid_syntax: "Erreur de syntaxe dans les sections de page, veuillez vérifier la syntaxe ('%{error}'/'%{fullpath}')"
+ liquid_extend: "La page '%{fullpath}' étend le contenu d'une page qui n'existe pas"
invalid_theme_file: "doit être rempli ou n'est pas un fichier zip"
attributes:
diff --git a/lib/locomotive.rb b/lib/locomotive.rb
index d0a782a7..045a7679 100644
--- a/lib/locomotive.rb
+++ b/lib/locomotive.rb
@@ -17,7 +17,7 @@ require 'locomotive/routing'
require 'locomotive/regexps'
require 'locomotive/render'
require 'locomotive/import'
-require 'locomotive/delayed_job'
+#require 'locomotive/delayed_job'
require 'locomotive/middlewares'
require 'locomotive/session_store'
diff --git a/lib/locomotive/engine.rb b/lib/locomotive/engine.rb
index f3254a3f..8f50f106 100644
--- a/lib/locomotive/engine.rb
+++ b/lib/locomotive/engine.rb
@@ -16,7 +16,7 @@ require 'actionmailer_with_request'
require 'heroku'
require 'httparty'
require 'redcloth'
-require 'delayed_job_mongoid'
+#require 'delayed_job_mongoid'
require 'zip/zipfilesystem'
require 'jammit-s3'
diff --git a/lib/locomotive/import/pages.rb b/lib/locomotive/import/pages.rb
index 610ae68f..a10f1db6 100644
--- a/lib/locomotive/import/pages.rb
+++ b/lib/locomotive/import/pages.rb
@@ -91,13 +91,10 @@ module Locomotive
def build_parent_template(template)
# just check if the template contains the extends keyword
- fullpath = template.scan(/\{% extends (\w+) %\}/).flatten.first
+ fullpath = template.scan(/\{% extends \'?([\w|\/]+)\'? %\}/).flatten.first
if fullpath # inheritance detected
- fullpath.gsub!("'", '')
-
return if fullpath == 'parent'
-
self.add_page(fullpath)
end
end
diff --git a/lib/locomotive/liquid/drops/contents.rb b/lib/locomotive/liquid/drops/contents.rb
index cfa58cf6..65a2e1c2 100644
--- a/lib/locomotive/liquid/drops/contents.rb
+++ b/lib/locomotive/liquid/drops/contents.rb
@@ -28,6 +28,18 @@ module Locomotive
def each(&block)
self.collection.each(&block)
end
+
+ def size
+ self.collection.size
+ end
+
+ def empty?
+ self.collection.empty?
+ end
+
+ def any?
+ self.collection.any?
+ end
def api
{ 'create' => @context.registers[:controller].send('admin_api_contents_url', @content_type.slug) }
diff --git a/lib/locomotive/liquid/filters/html.rb b/lib/locomotive/liquid/filters/html.rb
index acfca793..963cfd30 100644
--- a/lib/locomotive/liquid/filters/html.rb
+++ b/lib/locomotive/liquid/filters/html.rb
@@ -43,10 +43,8 @@ module Locomotive
# input: name of file including folder
# example: 'about/myphoto.jpg' | theme_image #
def theme_image_tag(input, *args)
- return '' if input.nil?
- input = "images/#{input}" unless input.starts_with?('/')
image_options = inline_options(args_to_options(args))
- ""
+ ""
end
# Write an image tag
diff --git a/lib/locomotive/liquid/tags/editable.rb b/lib/locomotive/liquid/tags/editable.rb
index 82609f12..ed857c94 100644
--- a/lib/locomotive/liquid/tags/editable.rb
+++ b/lib/locomotive/liquid/tags/editable.rb
@@ -1,4 +1,5 @@
require 'locomotive/liquid/tags/editable/base'
require 'locomotive/liquid/tags/editable/short_text'
require 'locomotive/liquid/tags/editable/long_text'
-require 'locomotive/liquid/tags/editable/file'
\ No newline at end of file
+require 'locomotive/liquid/tags/editable/file'
+require 'locomotive/liquid/tags/editable/content'
\ No newline at end of file
diff --git a/lib/locomotive/liquid/tags/editable/base.rb b/lib/locomotive/liquid/tags/editable/base.rb
index b2621185..aaa04c50 100644
--- a/lib/locomotive/liquid/tags/editable/base.rb
+++ b/lib/locomotive/liquid/tags/editable/base.rb
@@ -9,7 +9,7 @@ module Locomotive
def initialize(tag_name, markup, tokens, context)
if markup =~ Syntax
@slug = $1.gsub('\'', '')
- @options = {}
+ @options = { :assignable => true }
markup.scan(::Liquid::TagAttributes) { |key, value| @options[key.to_sym] = value.gsub(/^'/, '').gsub(/'$/, '') }
else
raise ::Liquid::SyntaxError.new("Syntax Error in 'editable_xxx' - Valid syntax: editable_xxx (, )")
@@ -26,7 +26,9 @@ module Locomotive
:block => @context[:current_block].try(:name),
:slug => @slug,
:hint => @options[:hint],
- :default_content => @nodelist.first.to_s,
+ :default_attribute => @options[:default],
+ :default_content => default_content,
+ :assignable => @options[:assignable],
:disabled => false,
:from_parent => false
}, document_type)
@@ -37,11 +39,11 @@ module Locomotive
current_page = context.registers[:page]
element = current_page.find_editable_element(context['block'].try(:name), @slug)
-
- if element
+
+ if element.present?
render_element(context, element)
else
- Locomotive.logger "[editable element] missing element #{context[:block].name} / #{@slug}"
+ Locomotive.logger "[editable element] missing element `#{context['block'].try(:name)}` / #{@slug} on #{current_page.fullpath}"
''
end
end
@@ -55,6 +57,15 @@ module Locomotive
def document_type
raise 'FIXME: has to be overidden'
end
+
+
+ def default_content
+ if @options[:default].present?
+ @context[:page].send(@options[:default])
+ else
+ @nodelist.first.to_s
+ end
+ end
end
diff --git a/lib/locomotive/liquid/tags/editable/content.rb b/lib/locomotive/liquid/tags/editable/content.rb
new file mode 100644
index 00000000..1964f92a
--- /dev/null
+++ b/lib/locomotive/liquid/tags/editable/content.rb
@@ -0,0 +1,49 @@
+module Locomotive
+ module Liquid
+ module Tags
+ module Editable
+ class Content < ::Liquid::Tag
+
+ Syntax = /(#{::Liquid::Expression}+)?/
+
+ def initialize(tag_name, markup, tokens, context)
+ if markup =~ Syntax
+ @slug = $1
+ @options = { :inherit => false }
+ markup.scan(::Liquid::TagAttributes) { |key, value| @options[key.to_sym] = value.gsub(/"|'/, '') }
+ else
+ raise ::Liquid::SyntaxError.new("Syntax Error in 'content' - Valid syntax: slug")
+ end
+
+ super
+ end
+
+ def render(context)
+ page = context.registers[:page]
+ element = find_element(page)
+
+ if element.nil? && @options[:inherit] != false
+ while page.parent.present? && element.nil?
+ page = page.parent
+ element = find_element(page)
+ end
+ end
+
+ if element.present?
+ return element.content
+ else
+ raise ::Liquid::SyntaxError.new("Error in 'content' - Can't find editable element called `#{@slug}`")
+ end
+ end
+
+ def find_element(page)
+ page.editable_elements.where(:slug => @slug).first
+ end
+
+ end
+
+ ::Liquid::Template.register_tag('content', Content)
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/public/stylesheets/admin/menu.css b/public/stylesheets/admin/menu.css
index 2a3c63a1..fba1dfe3 100644
--- a/public/stylesheets/admin/menu.css
+++ b/public/stylesheets/admin/menu.css
@@ -8,7 +8,8 @@
position: relative;
top: -1px;
z-index: 998;
- height: 60px;
+ min-height: 60px;
+ width: 950px;
margin: 0px;
padding: 0 8px;
background: transparent url(/images/admin/menu/shadow.png) repeat-y 0 0;
@@ -24,12 +25,24 @@
border-top-right-radius: 3px ;
-moz-border-radius-top-right: 3px ;
-webkit-border-top-right-radius: 3px ;
- height: 60px; }
+ width: 826px;
+ padding-right: 124px;
+ padding-top: 8px;
+ padding-bottom: 8px;
+ min-height: 44px; }
+ #submenu > ul:after {
+ content: ".";
+ display: block;
+ height: 0;
+ clear: both;
+ visibility: hidden; }
#submenu > ul a {
text-decoration: none; }
#submenu > ul > li {
- margin: 15px 7px 0 8px;
- float: left; }
+ margin: 7px 7px 7px 8px;
+ height: 30px;
+ float: left;
+ position: relative; }
#submenu > ul > li.hoverable > a span em {
display: inline-block;
background: transparent url(/images/admin/menu/icons.png) no-repeat 0 -16px;
@@ -101,10 +114,9 @@
position: absolute;
top: 0px;
right: 22px;
- height: 60px;
+ height: 100%;
padding-left: 20px;
- z-index: 1;
- background: transparent url(/images/admin/menu/submenu/action-border.png) repeat-y left 0; }
+ z-index: 1; }
#submenu > .action a {
margin-top: 18px;
display: inline-block;
@@ -136,7 +148,7 @@
border-color: black; }
#submenu .popup {
position: absolute;
- top: 42px;
+ top: 26px;
min-width: 250px;
background: #fff;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5);
@@ -311,7 +323,7 @@ body.contents #submenu > ul {
background: -moz-linear-gradient(0% 100% 90deg, #212229, #1e1e24);
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#1e1e24), to(#212229)); }
body.contents #submenu > .action {
- background-image: url(/images/admin/menu/submenu/black-action-border.png) !important; }
+ background: transparent url(/images/admin/menu/submenu/action-border.png) repeat-y left 0; }
#menu li.assets a em {
position: relative;
diff --git a/public/stylesheets/sass/admin/_helpers.scss b/public/stylesheets/sass/admin/_helpers.scss
index c24aeada..278c7fc2 100644
--- a/public/stylesheets/sass/admin/_helpers.scss
+++ b/public/stylesheets/sass/admin/_helpers.scss
@@ -1,5 +1,15 @@
/* ___ rounded ___ */
+@mixin clearfix {
+ &:after {
+ content: ".";
+ display: block;
+ height: 0;
+ clear: both;
+ visibility: hidden;
+ };
+}
+
@mixin rounded($side, $radius: 10px, $important: false) {
@if $important == true {
$important: !important; }
diff --git a/public/stylesheets/sass/admin/menu.scss b/public/stylesheets/sass/admin/menu.scss
index 67443840..230bec14 100644
--- a/public/stylesheets/sass/admin/menu.scss
+++ b/public/stylesheets/sass/admin/menu.scss
@@ -9,7 +9,8 @@
position: relative;
top: -1px;
z-index: 998;
- height: 60px;
+ min-height: 60px;
+ width: 950px;
margin: 0px;
padding: 0 8px;
background: transparent url(/images/admin/menu/shadow.png) repeat-y 0 0;
@@ -17,16 +18,22 @@
/* ___ submenu items ___ */
& > ul {
+ @include clearfix;
@include reset;
border-top: 1px solid rgba(255, 255, 255, 0.4);
background: transparent url(/images/admin/menu/submenu/shadow.png) repeat-x 0 0;
@include rounded(top-right, 3px);
-
- height: 60px;
+ width: 826px;
+ padding-right: 124px;
+ padding-top: 8px;
+ padding-bottom: 8px;
+ min-height: 44px;
& > li {
- margin: 15px 7px 0 8px;
+ margin: 7px 7px 7px 8px;
+ height: 30px;
float: left;
+ position: relative;
&.hoverable > a span {
em {
@@ -105,10 +112,9 @@
& > .action {
@include absolute-position(top, 0px, right, 22px);
- height: 60px;
+ height: 100%;
padding-left: 20px;
z-index: 1;
- background: transparent url(/images/admin/menu/submenu/action-border.png) repeat-y left 0;
a {
margin-top: 18px;
@@ -150,7 +156,7 @@
.popup {
position: absolute;
- top: 42px;
+ top: 26px;
min-width: 250px;
background: #fff;
@include box-shadow(0px, 0px, 10px, rgba(0, 0, 0, 0.5));
@@ -253,7 +259,7 @@
}
& > .action {
- background-image: url(/images/admin/menu/submenu/black-action-border.png) !important;
+ background: transparent url(/images/admin/menu/submenu/action-border.png) repeat-y left 0;
}
}
diff --git a/spec/factories.rb b/spec/factories.rb
index 9f9f253a..23a61783 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -40,7 +40,7 @@ Factory.define "frenchy user", :parent => :account do |a|
end
Factory.define "brazillian user", :parent => :account do |a|
- a.name "José Carlos"
+ a.name "Jose Carlos"
a.email "jose@carlos.com.br"
a.locale 'pt-BR'
end
diff --git a/spec/fixtures/themes/default.zip b/spec/fixtures/themes/default.zip
index 916d4cac..9bf39d8f 100644
Binary files a/spec/fixtures/themes/default.zip and b/spec/fixtures/themes/default.zip differ
diff --git a/spec/lib/locomotive/import_spec.rb b/spec/lib/locomotive/import_spec.rb
index 425ee5d9..485fc379 100644
--- a/spec/lib/locomotive/import_spec.rb
+++ b/spec/lib/locomotive/import_spec.rb
@@ -53,7 +53,7 @@ describe Locomotive::Import::Job do
end
it 'inserts all the pages' do
- @site.pages.count.should == 9
+ @site.pages.count.should == 11
end
it 'inserts the index and 404 pages' do
diff --git a/spec/lib/locomotive/liquid/tags/editable/content_spec.rb b/spec/lib/locomotive/liquid/tags/editable/content_spec.rb
new file mode 100644
index 00000000..d5405545
--- /dev/null
+++ b/spec/lib/locomotive/liquid/tags/editable/content_spec.rb
@@ -0,0 +1,97 @@
+require 'spec_helper'
+
+describe Locomotive::Liquid::Tags::Editable::Content do
+
+ before :each do
+ Locomotive::Liquid::Tags::Editable::Content.any_instance.stubs(:end_tag).returns(true)
+ end
+
+ context 'syntax' do
+
+ it 'should have a valid syntax' do
+ ["slug", "slug, inherit: true"].each do |markup|
+ lambda do
+ Locomotive::Liquid::Tags::Editable::Content.new('content', markup, ["{% content %}"], {})
+ end.should_not raise_error
+ end
+ end
+
+ end
+
+ context 'output' do
+
+ before :each do
+ EditableElement.any_instance.stubs(:content).returns("test string")
+ end
+
+ context 'inheriting from a parent' do
+
+ before :each do
+ @parent = Factory.build(:page)
+ @child = Factory.build(:page)
+
+ @child.stubs(:parent).returns(@parent)
+ end
+
+ it 'should return the parents field if inherit is set' do
+ @element = @parent.editable_elements.create(:slug => 'test')
+ @child.stubs(:raw_template).returns("{% content test, inherit: true %}")
+ template = Liquid::Template.parse(@child.raw_template)
+ text = template.render!(liquid_context(:page => @child))
+ text.should match /test string/
+ end
+
+ it 'should raise an exception if it cant find the field' do
+ @child.stubs(:raw_template).returns("{% content test, inherit: true %}")
+ template = Liquid::Template.parse(@child.raw_template)
+ lambda do
+ template.render!(liquid_context(:page => @child))
+ end.should raise_error
+ end
+
+ after :each do
+ @parent.editable_elements.destroy_all
+ end
+
+ end
+
+ context 'reading from the same page' do
+
+ before :each do
+ @page = Factory.build(:page)
+ end
+
+ it 'should return the previously defined field' do
+ @element = @page.editable_elements.create(:slug => 'test')
+ @page.stubs(:raw_template).returns("{% content test %}")
+ template = Liquid::Template.parse(@page.raw_template)
+ text = template.render!(liquid_context(:page => @page))
+ text.should match /test string/
+ end
+
+ it 'should raise an exception if it wasnt defined' do
+ @page.stubs(:raw_template).returns("{% content test %}")
+ template = Liquid::Template.parse(@page.raw_template)
+ lambda do
+ template.render!(liquid_context(:page => @page))
+ end.should raise_error
+ end
+
+ after :each do
+ @page.editable_elements.destroy_all
+ end
+
+ end
+
+ end
+
+ # ___ helpers methods ___ #
+
+ def liquid_context(options = {})
+ ::Liquid::Context.new({}, {},
+ {
+ :page => options[:page]
+ }, true)
+ end
+
+end