new editable element for a page: the control

This commit is contained in:
Didier Lafforgue 2012-03-22 00:50:34 +01:00
parent ab5a4755b8
commit b3b0a5ac16
14 changed files with 132 additions and 235 deletions

View File

@ -32,6 +32,9 @@ class Locomotive.Views.EditableElements.EditAllView extends Backbone.View
view.model = @collection.get(view.model.get('id')) view.model = @collection.get(view.model.get('id'))
view.refresh() view.refresh()
unbind_model: ->
_.each @_editable_elements_views, (view) => Backbone.ModelBinding.unbind(view)
render_elements: -> render_elements: ->
index = 0 index = 0
@ -45,6 +48,7 @@ class Locomotive.Views.EditableElements.EditAllView extends Backbone.View
when 'EditableShortText' then Locomotive.Views.EditableElements.ShortTextView when 'EditableShortText' then Locomotive.Views.EditableElements.ShortTextView
when 'EditableLongText' then Locomotive.Views.EditableElements.LongTextView when 'EditableLongText' then Locomotive.Views.EditableElements.LongTextView
when 'EditableFile' then Locomotive.Views.EditableElements.FileView when 'EditableFile' then Locomotive.Views.EditableElements.FileView
when 'EditableControl' then Locomotive.Views.EditableElements.ControlView
view = new view_class(model: element) view = new view_class(model: element)
@$("#block-#{block.index} > fieldset > ol").append(view.render().el) @$("#block-#{block.index} > fieldset > ol").append(view.render().el)

View File

@ -90,6 +90,7 @@ class Locomotive.Views.Pages.FormView extends Locomotive.Views.Shared.FormView
# Just re-connect the model and the views (+ redraw the file fields) # Just re-connect the model and the views (+ redraw the file fields)
refresh_editable_elements: -> refresh_editable_elements: ->
@editable_elements_view.unbind_model()
@editable_elements_view.collection = @model.get('editable_elements') @editable_elements_view.collection = @model.get('editable_elements')
@editable_elements_view.refresh() @editable_elements_view.refresh()

View File

@ -88,8 +88,12 @@ module Locomotive
} }
end end
# Update the value (or content) of the elements matching the same block/slug
# as the current element in all the pages inheriting from the current page.
# This method is called only if the element has the "fixed" property set to true.
# It also needs to be overridden for each kind of elements (file, short text, ...etc)
#
def propagate_content def propagate_content
# needs to be overridden for each kind of elements (file, short text, ...etc)
true true
end end

View File

@ -1,12 +1,15 @@
module Locomotive module Locomotive
class EditableFile < EditableElement class EditableFile < EditableElement
## behaviours ##
mount_uploader 'source', EditableFileUploader mount_uploader 'source', EditableFileUploader
replace_field 'source', ::String, true replace_field 'source', ::String, true
## fields ##
field :default_source_url, :localize => true field :default_source_url, :localize => true
## callbacks ##
after_save :propagate_content after_save :propagate_content
## methods ## ## methods ##

View File

@ -1,6 +1,8 @@
module Locomotive module Locomotive
class EditableLongText < EditableShortText class EditableLongText < EditableShortText
## methods ##
def as_json(options = {}) def as_json(options = {})
Locomotive::EditableLongTextPresenter.new(self).as_json Locomotive::EditableLongTextPresenter.new(self).as_json
end end

View File

@ -26,7 +26,7 @@ module Locomotive
end end
def enabled_editable_elements def enabled_editable_elements
self.editable_elements.by_priority.find_all(&:editable?) # { |el| !el.editable? } self.editable_elements.by_priority.find_all(&:editable?)
end end
def editable_elements_grouped_by_blocks def editable_elements_grouped_by_blocks
@ -70,7 +70,7 @@ module Locomotive
new_el = self.editable_elements.build({}, el.class) new_el = self.editable_elements.build({}, el.class)
new_el.copy_attributes_from(el) new_el.copy_attributes_from(el)
else else
existing_el.disabled = false # = { :disabled => false } existing_el.disabled = false
end end
end end
end end

View File

@ -50,3 +50,15 @@
{{/if}} {{/if}}
= hidden_field_tag 'page[editable_elements_attributes][{{index}}][id]', '{{id}}', :id => 'page_editable_elements_attributes_{{index}}_id' = hidden_field_tag 'page[editable_elements_attributes][{{index}}][id]', '{{id}}', :id => 'page_editable_elements_attributes_{{index}}_id'
%script{ :type => 'text/html', :id => 'editable_control_input' }
%label{ :for => 'page_editable_elements_attributes_{{index}}_content' } {{label}}
= select_tag 'page[editable_elements_attributes][{{index}}][content]', raw('{{#each options}}<option value="{{this.value}}" {{#if this.selected}}selected="selected"{{/if}}>{{this.text}}</option>{{/each}}'), :id => 'page_editable_elements_attributes_{{index}}_content', :class => 'content'
{{#if hint}}
%p.inline-hints {{hint}}
{{/if}}
= hidden_field_tag 'page[editable_elements_attributes][{{index}}][id]', '{{id}}', :id => 'page_editable_elements_attributes_{{index}}_id'

View File

@ -20,7 +20,7 @@ x edit my site
x domains x domains
x roles x roles
x save x save
- fix other sections x fix other sections
x edit my account x edit my account
x create a new site x create a new site
x create a new accounts x create a new accounts
@ -32,7 +32,7 @@ x edit my site
x import/export x import/export
x export x export
x site picker x site picker
- content types x content types
x move content instances into their own collection x move content instances into their own collection
x manage custom_fields x manage custom_fields
x automatic name x automatic name
@ -65,7 +65,7 @@ x edit my site
x bug text formatting x bug text formatting
x custom_fields: use the appropriate icon to drag select options x custom_fields: use the appropriate icon to drag select options
x bug ui with contents popup x bug ui with contents popup
- use list_or_group_entries instead of ordered_entries x use list_or_group_entries instead of ordered_entries
x i18n x i18n
x add locales a site responds to x add locales a site responds to
x locale switcher x locale switcher
@ -90,7 +90,7 @@ x i18n
x deployment x deployment
x fix integration problems x fix integration problems
x pre-compile assets x pre-compile assets
- API x API
x authentication from a token + controller to deliver a token x authentication from a token + controller to deliver a token
x api routes x api routes
x change api location x change api location
@ -115,6 +115,8 @@ x heroku module for locomotive
x remove the import / export scripts x remove the import / export scripts
x remove the cross domain authentication (use auth_token instead) x remove the cross domain authentication (use auth_token instead)
- where to put Locomotive::InlineEditorMiddleware ? - where to put Locomotive::InlineEditorMiddleware ?
x global regions: keyword in editable element (http://www.mongodb.org/display/DOCS/Updating)
x override sort for contents
- bugs / ui tweaks - bugs / ui tweaks
x unable to toggle the "required" check_boxes for content types x unable to toggle the "required" check_boxes for content types
@ -139,7 +141,6 @@ BACKLOG:
- html view in the aloha popup - html view in the aloha popup
- editable elements should wrap a tag: div, h1, ...etc (default span) - editable elements should wrap a tag: div, h1, ...etc (default span)
- edit images (upload new ones, ...etc) => wait for aloha or send them an email ? - edit images (upload new ones, ...etc) => wait for aloha or send them an email ?
- global regions: keyword in editable element (http://www.mongodb.org/display/DOCS/Updating)
- cucumber features for admin pages (in progress) - cucumber features for admin pages (in progress)
(- duostack/doutcloud version) (- duostack/doutcloud version)
- write my first tutorial about locomotive - write my first tutorial about locomotive
@ -151,7 +152,7 @@ BACKLOG:
- sync data - sync data
- import only theme assets - import only theme assets
- endless pagination - endless pagination
- override sort for contents
- tooltip to explain the difference between 1.) Admin 2.) Author 3.) Designer? - tooltip to explain the difference between 1.) Admin 2.) Author 3.) Designer?
- [bushido] guiders / welcome page / devise cas authentication (SSO) - [bushido] guiders / welcome page / devise cas authentication (SSO)

View File

@ -139,3 +139,13 @@ Scenario: Render liquid variable used as default editable file name
My application file is /different-default.pdf My application file is /different-default.pdf
""" """
Scenario: Simple select element
Given a page named "hello-world" with the template:
"""
{% block menuecontent %}{% editable_control 'menueposition', options: 'top=Top of the Page,bottom=Bottom of the Page' %}bottom{% endeditable_control %}{% endblock %}
"""
When I view the rendered page at "/hello-world"
Then the rendered output should look like:
"""
bottom
"""

View File

@ -31,3 +31,11 @@ Then /^"([^"]*)" should( not)? be an option for "([^"]*)"(?: within "([^\"]*)")?
field_labeled(field).first(:xpath, ".//option[text() = '#{value}']").send(expectation, be_present) field_labeled(field).first(:xpath, ".//option[text() = '#{value}']").send(expectation, be_present)
end end
end end
Then /^"([^"]*)" should be selected for "([^"]*)"$/ do |value, field|
assert page.has_xpath?("//select[@name='#{field}' and option[@selected and contains(text(), '#{value}')]]")
end
When /^I reload the page$/ do
visit current_path
end

View File

@ -2,4 +2,4 @@ require 'locomotive/liquid/tags/editable/base'
require 'locomotive/liquid/tags/editable/short_text' require 'locomotive/liquid/tags/editable/short_text'
require 'locomotive/liquid/tags/editable/long_text' require 'locomotive/liquid/tags/editable/long_text'
require 'locomotive/liquid/tags/editable/file' require 'locomotive/liquid/tags/editable/file'
require 'locomotive/liquid/tags/editable/content' require 'locomotive/liquid/tags/editable/control'

View File

@ -1,49 +0,0 @@
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

View File

@ -6,8 +6,6 @@ module Locomotive
protected protected
protected
def default_element_attributes def default_element_attributes
if @nodelist.first.is_a?(String) if @nodelist.first.is_a?(String)
super.merge(:default_source_url => @nodelist.first.try(:to_s)) super.merge(:default_source_url => @nodelist.first.try(:to_s))

View File

@ -1,97 +0,0 @@
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
Locomotive::EditableElement.any_instance.stubs(:content).returns("test string")
end
context 'inheriting from a parent' do
before :each do
@parent = FactoryGirl.build(:page)
@child = FactoryGirl.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 = FactoryGirl.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