listing all entries (done) + fix bugs + tweak ui

This commit is contained in:
did 2012-01-04 02:07:53 +01:00
parent 81fc524fdc
commit 0f1b4f59d3
33 changed files with 290 additions and 269 deletions

View File

@ -31,7 +31,7 @@ gem 'flash_cookie_session', '~> 1.1.1'
gem 'locomotive_liquid', '2.2.2', :require => 'liquid' gem 'locomotive_liquid', '2.2.2', :require => 'liquid'
gem 'formtastic', '~> 2.0.2' gem 'formtastic', '~> 2.0.2'
gem 'responders', '~> 0.6.0' gem 'responders', '~> 0.6.4'
gem 'cells', '~> 3.7.0' gem 'cells', '~> 3.7.0'
gem 'RedCloth', '~> 4.2.8' gem 'RedCloth', '~> 4.2.8'
gem 'sanitize', '~> 2.0.3' gem 'sanitize', '~> 2.0.3'

View File

@ -341,7 +341,7 @@ DEPENDENCIES
rails (~> 3.1.3) rails (~> 3.1.3)
rails-backbone (= 0.5.4) rails-backbone (= 0.5.4)
rake (= 0.9.2) rake (= 0.9.2)
responders (~> 0.6.0) responders (~> 0.6.4)
rmagick (= 2.12.2) rmagick (= 2.12.2)
rspec-cells rspec-cells
rspec-rails (= 2.6.1) rspec-rails (= 2.6.1)

View File

@ -20,6 +20,7 @@ class Locomotive.Models.ContentEntry extends Backbone.Model
toJSON: -> toJSON: ->
_.tap super, (hash) => _.tap super, (hash) =>
hash['_slug'] = '' if hash['_slug'] == null # avoid empty hash
_.each _.keys(hash), (key) => _.each _.keys(hash), (key) =>
unless _.include(@get('safe_attributes'), key) unless _.include(@get('safe_attributes'), key)
delete hash[key] delete hash[key]

View File

@ -0,0 +1,36 @@
Locomotive.Views.ContentEntries ||= {}
class Locomotive.Views.ContentEntries.IndexView extends Backbone.View
el: '#content'
render: ->
@make_sortable()
return @
make_sortable: ->
self = @
@$('ul#entries-list.sortable').sortable
handle: 'span.handle'
items: 'li.item'
axis: 'y'
update: (event, ui) -> self.call_sort $(@)
call_sort: (folder) ->
$.rails.ajax
url: folder.attr('data-url')
type: 'post'
dataType: 'json'
data:
entries: (_.map folder.sortable('toArray'), (el) -> el.replace('entry-', ''))
_method: 'put'
success: @.on_successful_sort
error: @.on_failed_sort
on_successful_sort: (data, status, xhr) ->
$.growl('success', xhr.getResponseHeader('X-Message'))
on_failed_sort: (data, status, xhr) ->
$.growl('error', xhr.getResponseHeader('X-Message'))

View File

@ -1,4 +1,4 @@
Locomotive.Views.Contents ||= {} Locomotive.Views.ContentEntries ||= {}
class Locomotive.Views.ContentEntries.NewView extends Locomotive.Views.ContentEntries.FormView class Locomotive.Views.ContentEntries.NewView extends Locomotive.Views.ContentEntries.FormView

View File

@ -33,7 +33,6 @@ class Locomotive.Views.Pages.ListView extends Backbone.View
success: @.on_successful_sort success: @.on_successful_sort
error: @.on_failed_sort error: @.on_failed_sort
# on_sort: (data) ->
on_successful_sort: (data, status, xhr) -> on_successful_sort: (data, status, xhr) ->
$.growl('success', xhr.getResponseHeader('X-Message')) $.growl('success', xhr.getResponseHeader('X-Message'))

View File

@ -5,7 +5,7 @@ class Locomotive.Views.Shared.ListItemView extends Backbone.View
tagName: 'li' tagName: 'li'
events: events:
'click a.remove': 'remove_snippet' 'click a.remove': 'remove_item'
template: -> template: ->
# please overide template # please overide template
@ -15,7 +15,7 @@ class Locomotive.Views.Shared.ListItemView extends Backbone.View
return @ return @
remove_snippet: (event) -> remove_item: (event) ->
event.stopPropagation() & event.preventDefault() event.stopPropagation() & event.preventDefault()
if confirm $(event.target).attr('data-confirm') if confirm $(event.target).attr('data-confirm')

View File

@ -58,7 +58,7 @@
height: 30px; height: 30px;
line-height: 30px; line-height: 30px;
padding: 0 10px; padding: 0 13px;
background: #fff; background: #fff;
@include border-radius(16px); @include border-radius(16px);
@ -70,6 +70,14 @@
font-weight: normal; font-weight: normal;
} }
span.handle {
display: none;
position: relative;
top: 3px;
margin-right: 5px;
cursor: move;
}
strong { strong {
color: #17171D; color: #17171D;
font-size: 14px; font-size: 14px;
@ -100,7 +108,7 @@
div.more, span.actions { div.more, span.actions {
position: absolute; position: absolute;
top: 0px; top: 0px;
right: 10px; right: 13px;
color: #8B8D9A; color: #8B8D9A;
font-size: 11px; font-size: 11px;
@ -137,6 +145,14 @@
} }
} // li } // li
&.sortable {
li {
span.handle {
display: inline-block;
}
}
}
> hr { > hr {
margin: 10px 0px; margin: 10px 0px;
height: 1px; height: 1px;

View File

@ -37,7 +37,7 @@
@mixin light-button { @mixin light-button {
display: inline-block; display: inline-block;
font-family: "Lucida Grande"; // font-family: "Lucida Grande";
position: relative; position: relative;
cursor: pointer; cursor: pointer;
@ -65,6 +65,20 @@
} }
} }
@mixin red-button {
@include light-button;
@include background-image(linear-gradient(top, #EE5F5B, #C43C35));
@include box-shadow(rgba(0, 0, 0, 0.4) 1px 1px 0px 0px);
@include text-shadow(rgba(0, 0, 0, 0.7) 0px -1px 0px);
color: #fff;
&:hover, &.hover {
background: #C43C35;
}
}
@mixin gray-button { @mixin gray-button {
position: relative; position: relative;
padding: 2px 10px 3px 31px; padding: 2px 10px 3px 31px;

View File

@ -102,36 +102,6 @@ ul.list {
outline: none; outline: none;
} }
// em {
// display: block;
// float: left;
// height: 31px;
// width: 18px;
// }
// strong {
// display: block;
// height: 31px;
// margin-left: 18px;
//
// a {
// position: relative;
// top: 2px;
// left: 15px;
//
// text-decoration: none;
// color: #1f82bc;
// font-size: 13px;
// @include single-text-shadow(#fff, 1px, 1px, 1px);
//
// &:hover {
// text-decoration: underline;
// }
// }
// }
// &.sortable li strong a { left: 10px; }
div.more { div.more {
position: absolute; position: absolute;
top: 0px; top: 0px;
@ -146,41 +116,68 @@ ul.list {
margin-left: 10px; margin-left: 10px;
} }
// span.handle {
// position: relative;
// top: 5px;
// margin: 0 0 0 15px;
// cursor: move;
// }
} // li div.more } // li div.more
} // ul.list li } // ul.list li
} }
// ul.theme-assets { #entries-list.list {
// margin-left: 40px;
//
// li.hidden strong a { font-style: italic; color: #8B8D9A; font-weight: normal; }
// }
// #contents-list li { li.item {
// background: none; a {
// @include single-text-shadow(#fff, 1px, 1px, 1px);
// li { }
// em {
// background-position: left -31px; span.handle {
// cursor: move; display: none;
// } }
//
// strong { .more {
// display: block;
// height: 31px; a.remove {
// display: inline-block;
// margin-left: 18px; width: 16px;
// height: 16px;
// background: transparent image-url("locomotive/list/item-right.png") no-repeat right 0;
// } margin-left: 7px;
// } outline: none;
// }
background: transparent image-url("locomotive/list/icons/trash_off.png") repeat 0 0;
text-indent: -9999px;
&:hover {
background-image: image-url("locomotive/list/icons/trash.png");
}
}
} // li div.more
} // li.item
&.sortable {
li.item {
span.handle {
display: block;
position: absolute;
top: 5px;
left: 0px;
height: 22px;
width: 18px;
text-indent: -9999px;
background: transparent image-url("locomotive/list/item-left.png") no-repeat 0 0;
cursor: move;
}
a {
margin-left: 26px;
}
} // .sortable li.item
} // .list.sortable
} // #entries-list.list
#pages-list { #pages-list {
margin: 0px 0 20px 0; margin: 0px 0 20px 0;

View File

@ -336,6 +336,13 @@ form.formtastic {
} }
&.no-label {
> textarea, .CodeMirror, .CodeMirror-scroll {
margin-top: 12px;
width: 868px;
}
}
} // li.code } // li.code
&.toggle { &.toggle {
@ -423,10 +430,14 @@ form.formtastic {
input[type=text] { input[type=text] {
width: 868px; width: 868px;
} }
}
div.inline-errors { > .inline-hints {
margin-left: 0px; margin-left: 0px !important;
} }
> .inline-errors {
margin-left: 0px !important;
} }
} // li.no-label } // li.no-label

View File

@ -93,7 +93,7 @@ body {
> div.inner { > div.inner {
position: relative; position: relative;
margin: 0px 8px; margin: 0px 8px;
padding: 10px 15px 20px 15px; padding: 10px 15px 66px 15px;
// z-index: 100; // z-index: 100;
@ -102,7 +102,7 @@ body {
@include box-shadow(rgba(0, 0, 0, 0.3) 0px 0px 6px 4px); @include box-shadow(rgba(0, 0, 0, 0.3) 0px 0px 6px 4px);
@include border-bottom-radius(4px); @include border-bottom-radius(4px);
min-height: 150px; min-height: 290px;
h2 { h2 {
@include locomotive-link; @include locomotive-link;
@ -120,11 +120,9 @@ body {
} // > div.inner h2 } // > div.inner h2
h3 { h3 {
background: transparent image-url("locomotive/list/item.png") no-repeat 0 0;
padding: 7px 0 10px 20px; padding: 7px 0 10px 20px;
font-size: 13px; font-size: 14px;
font-weight: bold; font-weight: bold;
color: #1e1f26; color: #1e1f26;
@include single-text-shadow(#fff, 1px, 1px, 1px); @include single-text-shadow(#fff, 1px, 1px, 1px);
@ -149,9 +147,10 @@ body {
} // #content #local-actions-bar } // #content #local-actions-bar
#local-actions-bottom-bar { #local-actions-bottom-bar {
position: relative; position: absolute;
top: 20px; bottom: 0px;
left: -15px; left: 0px;
height: 62px;
width: 950px; width: 950px;
background: #8b8d9a; background: #8b8d9a;
@ -162,8 +161,6 @@ body {
padding: 15px; padding: 15px;
margin: 0px; margin: 0px;
line-height: 13px;
a { a {
position: relative; position: relative;
top: 4px; top: 4px;
@ -172,7 +169,10 @@ body {
color: #fff; color: #fff;
font-size: 12px; font-size: 12px;
&.remove { color: #ff092c; } &.remove {
@include red-button;
top: 0px;
}
} }
} }

View File

@ -12,7 +12,7 @@ module Locomotive
before_filter :authorize_content before_filter :authorize_content
def index def index
@content_entries = @content_type.entries @content_entries = @content_type.list_or_group_entries
respond_with @content_entries respond_with @content_entries
end end
@ -38,17 +38,14 @@ module Locomotive
end end
def sort def sort
# TODO @content_type.klass_with_custom_fields(:entries).sort_entries!(params[:entries])
# @content_type.sort_contents!(params[:children])
# @page = current_site.pages.find(params[:id])
# @page.sort_children!(params[:children])
respond_with @content_type respond_with @content_type
end end
def destroy def destroy
@content_entry = @content_type.entries.find(params[:id]) @content_entry = @content_type.entries.find(params[:id])
@content_entry.destroy @content_entry.destroy
respond_with @content_entry, :location => pages_url respond_with @content_entry, :location => content_entries_url(@content_type.slug)
end end
protected protected

View File

@ -18,6 +18,22 @@ module Locomotive::ContentTypesHelper
end end
end end
def entry_label(content_type, entry)
if content_type.raw_item_template.blank?
entry._label # default one
else
assigns = { 'site' => current_site, 'entry' => entry }
registers = {
:controller => self,
:site => current_site,
:current_locomotive_account => current_locomotive_account
}
preserve(content_type.item_template.render(::Liquid::Context.new({}, assigns, registers)))
end
end
# MAX_DISPLAYED_CONTENTS = 4 # MAX_DISPLAYED_CONTENTS = 4
# #
# def fetch_content_types # def fetch_content_types

View File

@ -23,7 +23,7 @@ module Locomotive
before_validation :set_slug before_validation :set_slug
before_save :set_visibility before_save :set_visibility
before_create :add_to_list_bottom before_create :add_to_list_bottom
# after_create :send_notifications after_create :send_notifications
## named scopes ## ## named scopes ##
scope :visible, :where => { :_visible => true } scope :visible, :where => { :_visible => true }
@ -51,8 +51,17 @@ module Locomotive
next_or_previous :lt next_or_previous :lt
end end
def self.sort_entries!(ids)
list = self.any_in(:_id => ids.map { |id| BSON::ObjectId.from_string(id.to_s) }).to_a
ids.each_with_index do |id, position|
if entry = list.detect { |e| e._id.to_s == id.to_s }
entry.update_attributes :_position => position
end
end
end
def to_liquid def to_liquid
Locomotive::Liquid::Drops::Content.new(self) Locomotive::Liquid::Drops::ContentEntry.new(self)
end end
def to_presenter def to_presenter
@ -66,37 +75,35 @@ module Locomotive
protected protected
def next_or_previous(matcher = :gt) def next_or_previous(matcher = :gt)
attribute = self.content_type.order_by.to_sym order_by = self.content_type.order_by_definition
direction = self.content_type.order_direction || 'asc'
criterion = attribute.send(matcher) criterion = attribute.send(matcher)
self.class.where(criterion => self.send(attribute)).order_by([[attribute, direction]]).limit(1).first self.class.where(criterion => self.send(attribute)).order_by([order_by]).limit(1).first
end end
# Sets the slug of the instance by using the value of the highlighted field # Sets the slug of the instance by using the value of the highlighted field
# (if available). If a sibling content instance has the same permalink then a # (if available). If a sibling content instance has the same permalink then a
# unique one will be generated # unique one will be generated
def set_slug def set_slug
# self._slug = highlighted_field_value.dup if _slug.blank? && highlighted_field_value.present? self._slug = self._label.dup if self._slug.blank? && self._label.present?
#
# if _slug.present? if self._slug.present?
# self._slug.permalink! self._slug.permalink!
# self._slug = next_unique_slug if slug_already_taken? self._slug = self.next_unique_slug if self.slug_already_taken?
# end end
end end
# Return the next available unique slug as a string # Return the next available unique slug as a string
def next_unique_slug def next_unique_slug
# slug = _slug.gsub(/-\d*$/, '') slug = self._slug.gsub(/-\d*$/, '')
# last_slug = _parent.contents.where(:_id.ne => _id, :_slug => /^#{slug}-?\d*?$/i).order_by(:_slug).last._slug last_slug = self.class.where(:_id.ne => self._id, :_slug => /^#{slug}-?\d*?$/i).order_by(:_slug).last._slug
# next_number = last_slug.scan(/-(\d)$/).flatten.first.to_i + 1 next_number = last_slug.scan(/-(\d)$/).flatten.first.to_i + 1
# [slug, next_number].join('-')
# [slug, next_number].join('-')
end end
# def slug_already_taken? def slug_already_taken?
# _parent.contents.where(:_id.ne => _id, :_slug => _slug).any? self.class.where(:_id.ne => self._id, :_slug => self._slug).any?
# end end
def set_visibility def set_visibility
[:visible, :active].each do |meth| [:visible, :active].each do |meth|
@ -111,19 +118,15 @@ module Locomotive
self._position = self.class.max(:_position).to_i + 1 self._position = self.class.max(:_position).to_i + 1
end end
# def send_notifications def send_notifications
# return unless self.content_type.api_enabled? && !self.content_type.api_accounts.blank? return if !self.content_type.public_form_enabled? || self.content_type.public_form_accounts.blank?
#
# accounts = self.content_type.site.accounts.to_a self.content_type.site.accounts.each do |account|
# next unless self.content_type.public_form_accounts.include?(account._id.to_s)
# self.content_type.api_accounts.each do |account_id|
# next if account_id.blank? Locomotive::Notifications.new_content_entry(account, self).deliver
# end
# account = accounts.detect { |a| a.id.to_s == account_id.to_s } end
#
# Locomotive::Notifications.new_content_instance(account, self).deliver
# end
# end
end end
end end

View File

@ -44,20 +44,33 @@ module Locomotive
## methods ## ## methods ##
# def groupable?
# self.group_by_field && group_by_field.category?
# end
def group_by_field
self.entries_custom_fields.find(self.group_by_field_id)
end
def order_manually? def order_manually?
self.order_by == '_position' self.order_by == '_position'
end end
def asc_order? def order_by_definition
self.order_direction.blank? || self.order_direction == 'asc' direction = self.order_manually? ? 'asc' : self.order_direction || 'asc'
[order_by_attribute, direction]
end
def ordered_entries
self.entries.order_by([order_by_definition])
end
def groupable?
!!self.group_by_field && group_by_field.type == 'select'
end
def group_by_field
self.entries_custom_fields.find(self.group_by_field_id) rescue nil
end
def list_or_group_entries
if self.groupable?
self.entries.group_by_select_option(self.group_by_field.name, self.order_by_definition)
else
self.ordered_entries
end
end end
def to_presenter def to_presenter
@ -135,6 +148,11 @@ module Locomotive
protected protected
def order_by_attribute
return self.order_by if %w(created_at updated_at _position).include?(self.order_by)
self.entries_custom_fields.find(self.order_by).name rescue 'created_at'
end
def set_default_values def set_default_values
self.order_by ||= 'created_at' self.order_by ||= 'created_at'
field = self.entries_custom_fields.find(self.label_field_id) rescue self.entries_custom_fields.first field = self.entries_custom_fields.find(self.label_field_id) rescue self.entries_custom_fields.first

View File

@ -38,7 +38,7 @@ module Locomotive
end end
def accounts def accounts
Account.criteria.in(:_id => self.memberships.collect(&:account_id)) Account.criteria.in(:_id => self.memberships.map(&:account_id))
end end
def admin_memberships def admin_memberships

View File

@ -1,15 +1,15 @@
- if contents.empty? - if entries.empty?
%p.no-items!= t('.no_items', :url => new_content_entry_url(@content_type.slug)) %p.no-items!= t('.no_items', :url => new_content_entry_url(content_type.slug))
- else - else
%ul{ :id => 'contents-list', :class => "list #{'sortable' if @content_type.order_by == '_position'}", :'data-url' => sort_admin_contents_path(@content_type.slug, :json) } %ul{ :id => 'entries-list', :class => "#{'list' unless content_type.groupable?} #{'sortable' if content_type.order_manually?}", :'data-url' => sort_content_entries_url(content_type.slug, :json) }
- contents.each do |content| - entries.each do |entry|
%li.content{ :id => "content-#{content._id}" } %li.item{ :id => "entry-#{entry._id}" }
%em %span.handle
%strong = image_tag 'locomotive/form/icons/drag.png'
= link_to content_label_for(content), edit_admin_content_path(@content_type.slug, content) %strong= link_to entry_label(content_type, entry), edit_content_entry_url(content_type.slug, entry)
.more .more
%span %span
!= t('locomotive.contents.index.updated_at') != t('locomotive.content_entries.index.updated_at')
= l content.updated_at, :format => :short rescue 'n/a' = l entry.updated_at, :format => :short rescue 'n/a'
= link_to image_tag('admin/list/icons/trash.png', :alt => t('locomotive.buttons.delete')), admin_content_path(@content_type.slug, content), :class => 'remove', :confirm => t('locomotive.messages.confirm'), :method => :delete = link_to 'x', content_entry_url(content_type.slug, entry), :class => 'remove', :confirm => t('locomotive.messages.confirm'), :method => :delete

View File

@ -6,9 +6,6 @@
- content_for :actions do - content_for :actions do
= render 'locomotive/shared/actions/contents' = render 'locomotive/shared/actions/contents'
- content_for :head do
= include_javascripts :contents
- content_for :buttons do - content_for :buttons do
- if can?(:manage, Locomotive::ContentType) - if can?(:manage, Locomotive::ContentType)
= local_action_button :edit, edit_content_type_url(@content_type), :class => 'edit' = local_action_button :edit, edit_content_type_url(@content_type), :class => 'edit'
@ -19,14 +16,15 @@
%p= @content_type.description %p= @content_type.description
- if @content_type.groupable? - if @content_type.groupable?
- @contents.each do |group| - @content_entries.each do |group|
%h3= group[:name] || t('.category_noname') .box
= render 'list', :contents => group[:items] %h3= group[:name] || t('.category_noname')
%br .inner
= render 'list', :content_type => @content_type, :entries => group[:entries]
- else - else
= render 'list', :contents => @contents = render 'list', :content_type => @content_type, :entries => @content_entries
- if can?(:manage, Locomotive::ContentType) - if can?(:manage, Locomotive::ContentType)
#local-actions-bottom-bar #local-actions-bottom-bar
%p.tleft %p.tleft
= link_to(content_tag(:em, escape_once(' ')) + t('.destroy'), content_type_url(@content_type), :confirm => t('locomotive.messages.confirm'), :method => :delete, :class => 'button small remove') = link_to t('.destroy'), content_type_url(@content_type), :confirm => t('locomotive.messages.confirm'), :method => :delete, :class => 'button remove'

View File

@ -30,4 +30,4 @@
- if can?(:manage, current_site) - if can?(:manage, current_site)
= f.inputs :name => :robots_txt, :class => "inputs foldable #{'folded' if inputs_folded?(@site)}" do = f.inputs :name => :robots_txt, :class => "inputs foldable #{'folded' if inputs_folded?(@site)}" do
= f.input :robots_txt, :as => :'Locomotive::Code', :picker => false, :wrapper_html => { :class => 'small' } = f.input :robots_txt, :as => :'Locomotive::Code', :picker => false, :wrapper_html => { :class => 'small no-label' }

View File

@ -2,7 +2,7 @@
!!! !!!
%html{ :xmlns => 'http://www.w3.org/1999/xhtml' } %html{ :xmlns => 'http://www.w3.org/1999/xhtml' }
%head %head
%title= yield(:head_title) || escape_once("#{Locomotive.config.name} — #{current_site.name}") %title= title || escape_once("#{Locomotive.config.name} — #{current_site.name}")
= javascript_include_tag 'jquery.js' = javascript_include_tag 'jquery.js'
= stylesheet_link_tag 'locomotive/not_logged_in', :media => 'screen' = stylesheet_link_tag 'locomotive/not_logged_in', :media => 'screen'

View File

@ -250,7 +250,7 @@ en:
lastest_entries: "Lastest entries" lastest_entries: "Lastest entries"
updated_at: "Updated at" updated_at: "Updated at"
list: list:
no_entries: "There are no entries for now. Just click <a href=\"%{url}\">here</a> to create the first one." no_items: "There are no entries for now. Just click <a href=\"%{url}\">here</a> to create the first one."
new: new:
title: '%{type} &mdash; new entry' title: '%{type} &mdash; new entry'
edit: edit:

View File

@ -94,7 +94,7 @@ en:
content_type: content_type:
name: "We suggest you to type the plural form of the model. Ex: Projects, Recipes, Posts, Articles, ...etc" name: "We suggest you to type the plural form of the model. Ex: Projects, Recipes, Posts, Articles, ...etc"
slug: "It will be used as the name of the collection in the liquid templates. Ex: <span class='code'>{{ contents.my_projects }}</span>" slug: "It will be used as the name of the collection in the liquid templates. Ex: <span class='code'>{{ contents.my_projects }}</span>"
raw_item_template: "You can customize the text displayed for each item in the list. Simply use Liquid. Ex: <span class='code'>{{ content.name }})</span>" raw_item_template: "You can customize the text displayed for each item in the list. Simply use Liquid. Ex: <span class='code'>{{ entry.name }})</span>"
public_form_enabled: "It is used to let people from outside to create new instances (example: messages in a contact form)" public_form_enabled: "It is used to let people from outside to create new instances (example: messages in a contact form)"
public_form_accounts: "A notification email will be sent to each of the accounts listed above when a new instance is created" public_form_accounts: "A notification email will be sent to each of the accounts listed above when a new instance is created"
"custom_fields/field": "custom_fields/field":

View File

@ -79,6 +79,6 @@ es:
samples: "Si se activa, la importación también copiará contenido multimedia y páginas" samples: "Si se activa, la importación también copiará contenido multimedia y páginas"
reset: "Si se activa, toda la información del sitio será eliminada antes de importar" reset: "Si se activa, toda la información del sitio será eliminada antes de importar"
content_type: content_type:
raw_item_template: "Puede personalizar el texto mostrado para cada elemento de la lista. Simplemente utilice Liquid. Ej: {{ content.name }})" raw_item_template: "Puede personalizar el texto mostrado para cada elemento de la lista. Simplemente utilice Liquid. Ej: {{ entry.name }})"
api_enabled: "Se utiliza para dejar crear elementos a gente externa a la aplicación (ejemplo: mensajes en un formulario de contacto)" api_enabled: "Se utiliza para dejar crear elementos a gente externa a la aplicación (ejemplo: mensajes en un formulario de contacto)"
api_accounts: "Un email de notificación será enviado a las cuentas listadas más arriba cuando un nuevo elemento se cree" api_accounts: "Un email de notificación será enviado a las cuentas listadas más arriba cuando un nuevo elemento se cree"

View File

@ -94,6 +94,6 @@ fr:
reset: "Si activé, toutes les données de votre site seront détruites avant l'import du nouveau site" reset: "Si activé, toutes les données de votre site seront détruites avant l'import du nouveau site"
content_type: content_type:
slug: Nom utilisé dans les templates liquid afin d'accéder aux enregistrements de ce modèle slug: Nom utilisé dans les templates liquid afin d'accéder aux enregistrements de ce modèle
item_template: "Personnaliser le texte affiché pour chaque élément de la liste. Utilisez simplement du code Liquid. Ex: {{ content.name }}" item_template: "Personnaliser le texte affiché pour chaque élément de la liste. Utilisez simplement du code Liquid. Ex: {{ entry.name }}"
api_enabled: "Utilisé pour autoriser la création de nouvelles instances de l'extérieur (ex.: les messages dans un formulaire de contact)" api_enabled: "Utilisé pour autoriser la création de nouvelles instances de l'extérieur (ex.: les messages dans un formulaire de contact)"
api_accounts: "Un email de notification sera envoyé à chaque compte listé ci-dessus lors de la création d'une nouvelle instance" api_accounts: "Un email de notification sera envoyé à chaque compte listé ci-dessus lors de la création d'une nouvelle instance"

View File

@ -93,7 +93,7 @@ it:
samples: "Se attivato, il processo di import copierà anche contenuti e risorse" samples: "Se attivato, il processo di import copierà anche contenuti e risorse"
reset: "Se attivato, tutti i dati del tuo sito saranno cancellati prima di importare il nuovo sito" reset: "Se attivato, tutti i dati del tuo sito saranno cancellati prima di importare il nuovo sito"
content_type: content_type:
item_template: "Puoi personalizzare il testo visualizzato per ciascun elemento della lista semplicemente usando Liquid. Ex: {{ content.name }})" item_template: "Puoi personalizzare il testo visualizzato per ciascun elemento della lista semplicemente usando Liquid. Ex: {{ entry.name }})"
api_enabled: "E' usato per lasciare che i visitatori, da fuori, possano creare nuove istanze (per esempio: i messaggi da un form 'contattaci')" api_enabled: "E' usato per lasciare che i visitatori, da fuori, possano creare nuove istanze (per esempio: i messaggi da un form 'contattaci')"
api_accounts: "Quando viene creata una nuova istanza, una mail di notifica verrà inviata a tutti gli account elencati qui sopra" api_accounts: "Quando viene creata una nuova istanza, una mail di notifica verrà inviata a tutti gli account elencati qui sopra"

View File

@ -79,7 +79,7 @@ nl:
samples: "Het importeren zal ook de contents en bronbestanden copiëren als deze optie aanstaat" samples: "Het importeren zal ook de contents en bronbestanden copiëren als deze optie aanstaat"
reset: "Alle data van uw website zal verwijderd worden voordat de nieuwe website wordt geimporteerd als deze optie aanstaat" reset: "Alle data van uw website zal verwijderd worden voordat de nieuwe website wordt geimporteerd als deze optie aanstaat"
content_type: content_type:
raw_item_template: "U kunt de tekst voor elk item in de lijst aanpassen. Ie: {{ content.name }})" raw_item_template: "U kunt de tekst voor elk item in de lijst aanpassen. Ie: {{ entry.name }})"
api_enabled: "It is used to let people from outside to create new instances (example: messages in a contact form)" api_enabled: "It is used to let people from outside to create new instances (example: messages in a contact form)"
api_enabled: "Wordt gebruikt om mensen van buiten nieuwe instanties te laten creëren (voorbeeld: berichten in een contactformulier)" api_enabled: "Wordt gebruikt om mensen van buiten nieuwe instanties te laten creëren (voorbeeld: berichten in een contactformulier)"
api_accounts: "Een e-mail met een aankondiging zal worden verstuurd naar de bovenstaande accounts wanneer een nieuwe instantie wordt gecreëerd" api_accounts: "Een e-mail met een aankondiging zal worden verstuurd naar de bovenstaande accounts wanneer een nieuwe instantie wordt gecreëerd"

View File

@ -93,7 +93,7 @@
samples: "Vil gjøre at importen kopierer innhold og assets" samples: "Vil gjøre at importen kopierer innhold og assets"
reset: "Vil gjøre at alle data slettes for den nye siden importeres." reset: "Vil gjøre at alle data slettes for den nye siden importeres."
content_type: content_type:
item_template: "Du kan justere teksten som vises for hvert element i listen. Bruk liquid, f.eks: {{ content.name }}" item_template: "Du kan justere teksten som vises for hvert element i listen. Bruk liquid, f.eks: {{ entry.name }}"
api_enabled: "Brukes for å la sidebrukere opprette ny elementer (f.eks: meldinger i et kontaktskjema)" api_enabled: "Brukes for å la sidebrukere opprette ny elementer (f.eks: meldinger i et kontaktskjema)"
api_accounts: "En varslingsepost vil bli sendt til alle kontoene ovenfor når et nytt element blir opprettet." api_accounts: "En varslingsepost vil bli sendt til alle kontoene ovenfor når et nytt element blir opprettet."

View File

@ -93,7 +93,7 @@ ru:
samples: "Если включено, процесс импорта также скопирует содержимое и файлы" samples: "Если включено, процесс импорта также скопирует содержимое и файлы"
reset: "Если включено, все данные вашего сайта будут уничтожены перед импортом нового сайта" reset: "Если включено, все данные вашего сайта будут уничтожены перед импортом нового сайта"
content_type: content_type:
item_template: "Вы можете задавать текст, отображаемый для каждого элемента в списке. Просто используйте Liquid. Пр.: {{ content.name }})" item_template: "Вы можете задавать текст, отображаемый для каждого элемента в списке. Просто используйте Liquid. Пр.: {{ entry.name }})"
api_enabled: "Это используется для того, чтобы дать людям извне возможность создавать новые экземляры (пример: сообщения в форме контакта)" api_enabled: "Это используется для того, чтобы дать людям извне возможность создавать новые экземляры (пример: сообщения в форме контакта)"
api_accounts: "Письмо с уведомлением будет отправлено на каждый аккаунт из списка выше, когда создан новый экземпляр" api_accounts: "Письмо с уведомлением будет отправлено на каждый аккаунт из списка выше, когда создан новый экземпляр"

View File

@ -34,7 +34,7 @@ x edit my site
x site picker x site picker
- content types - content types
x move content instances into their own collection x move content instances into their own collection
- manage custom_fields x manage custom_fields
x automatic name x automatic name
x required x required
x editable plugin: add class depending on the type => surrounding span instead x editable plugin: add class depending on the type => surrounding span instead
@ -50,17 +50,17 @@ x edit my site
x select: add/edit/remove options x select: add/edit/remove options
x text: formatting x text: formatting
- change in main menu - change in main menu
- manage contents x manage contents
- list (highlighted field) x list (highlighted field)
- slugify x slugify
- crud x crud
x new x new
x date x date
x checkbox x checkbox
x html x html
x file x file
x edit x edit
- destroy x destroy
- public_form (previously api something) - public_form (previously api something)
- disallow to click twice on the submit form button (spinner ?) - disallow to click twice on the submit form button (spinner ?)

View File

@ -1,14 +1,14 @@
module Locomotive module Locomotive
module Liquid module Liquid
module Drops module Drops
class Content < Base class ContentEntry < Base
delegate :seo_title, :meta_keywords, :meta_description, :to => '_source' delegate :_slug, :_permalink, :seo_title, :meta_keywords, :meta_description, :to => '_source'
def _id def _id
self._source._id.to_s self._source._id.to_s
end end
# Returns the next content for the parent content type. # Returns the next content for the parent content type.
# If no content is found, nil is returned. # If no content is found, nil is returned.
# #
@ -21,7 +21,7 @@ module Locomotive
def next def next
self._source.next.to_liquid self._source.next.to_liquid
end end
# Returns the previous content for the parent content type. # Returns the previous content for the parent content type.
# If no content is found, nil is returned. # If no content is found, nil is returned.
# #
@ -43,8 +43,8 @@ module Locomotive
end end
end end
def highlighted_field_value def _label
self._source.highlighted_field_value self._label
end end
end end

View File

@ -15,91 +15,6 @@ end
# Limit feature for embedded documents # Limit feature for embedded documents
module Mongoid #:nodoc: module Mongoid #:nodoc:
module Criterion #:nodoc:
module Exclusion
def only(*args)
clone.tap do |crit|
crit.options[:fields] ||= {}
crit.options[:fields][:only] = args.flatten if args.any?
end
end
end
module Optional
# Adds a criterion to the +Criteria+ that specifies the maximum number of
# results to return. This is mostly used in conjunction with <tt>skip()</tt>
# to handle paginated results.
#
# Options:
#
# value: An +Integer+ specifying the max number of results. Defaults to 20.
# hash: A +Hash+ specifying the max number of results for the embedded collections.
#
# Example:
#
# <tt>criteria.limit(100)</tt>
# <tt>criteria.limit(100, { :contents => 5 })</tt>
# <tt>criteria.limit(:contents => 5)</tt>
#
# Returns: <tt>self</tt>
def limit(*args)
clone.tap do |crit|
arguments = args.first || 20
fields = nil # hash of embedded collections
case arguments
when Integer
crit.options[:limit] = arguments
fields = args[1] if args.size > 1
when Hash
fields = arguments
end
if fields
crit.options[:fields] ||= {}
crit.options[:fields][:limit] = fields
end
end
end
end
end
module Contexts #:nodoc:
class Mongo
# Filters the field list. If no fields have been supplied, then it will be
# empty. If fields have been defined then _type will be included as well.
def process_options
fields = options[:fields]
only = fields.delete(:only) if fields
limits = fields.delete(:limit) if fields
# only ?
if only && only.size > 0
only << :_type if !only.include?(:_type)
only.each do |field|
options[:fields].merge!(field => 1)
end
end
# limit for embedded collections ?
if limits && limits.size > 0
limits.each do |field, limit|
next if limit.blank?
options[:fields][field] = { '$slice' => limit }
end
end
options.dup
end
end
end
# without callback feature # without callback feature
module Callbacks module Callbacks

View File

@ -46,16 +46,16 @@ describe Locomotive::Import::Job do
content_type = @site.content_types.where(:slug => 'projects').first content_type = @site.content_types.where(:slug => 'projects').first
content_type.entries.size.should == 5 content_type.entries.size.should == 5
content = content_type.entries.first entry = content_type.entries.first
content._permalink.should == 'locomotivecms' entry._permalink.should == 'locomotivecms'
content.seo_title.should == 'My open source CMS' entry.seo_title.should == 'My open source CMS'
content.meta_description.should == 'bla bla bla' entry.meta_description.should == 'bla bla bla'
content.meta_keywords.should == 'cms ruby engine mongodb' entry.meta_keywords.should == 'cms ruby engine mongodb'
content.name.should == 'Locomotive App' entry.name.should == 'Locomotive App'
content.thumbnail.url.should_not be_nil entry.thumbnail.url.should_not be_nil
content.featured.should == true entry.featured.should == true
content.client.name.should == 'My client #1' entry.client.name.should == 'My client #1'
content.team.first.name.should == 'Michael Scott' entry.team.first.name.should == 'Michael Scott'
end end
it 'inserts theme assets' do it 'inserts theme assets' do