listing all entries (done) + fix bugs + tweak ui
This commit is contained in:
parent
81fc524fdc
commit
0f1b4f59d3
2
Gemfile
2
Gemfile
@ -31,7 +31,7 @@ gem 'flash_cookie_session', '~> 1.1.1'
|
||||
|
||||
gem 'locomotive_liquid', '2.2.2', :require => 'liquid'
|
||||
gem 'formtastic', '~> 2.0.2'
|
||||
gem 'responders', '~> 0.6.0'
|
||||
gem 'responders', '~> 0.6.4'
|
||||
gem 'cells', '~> 3.7.0'
|
||||
gem 'RedCloth', '~> 4.2.8'
|
||||
gem 'sanitize', '~> 2.0.3'
|
||||
|
@ -341,7 +341,7 @@ DEPENDENCIES
|
||||
rails (~> 3.1.3)
|
||||
rails-backbone (= 0.5.4)
|
||||
rake (= 0.9.2)
|
||||
responders (~> 0.6.0)
|
||||
responders (~> 0.6.4)
|
||||
rmagick (= 2.12.2)
|
||||
rspec-cells
|
||||
rspec-rails (= 2.6.1)
|
||||
|
@ -20,6 +20,7 @@ class Locomotive.Models.ContentEntry extends Backbone.Model
|
||||
|
||||
toJSON: ->
|
||||
_.tap super, (hash) =>
|
||||
hash['_slug'] = '' if hash['_slug'] == null # avoid empty hash
|
||||
_.each _.keys(hash), (key) =>
|
||||
unless _.include(@get('safe_attributes'), key)
|
||||
delete hash[key]
|
||||
|
@ -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'))
|
@ -1,4 +1,4 @@
|
||||
Locomotive.Views.Contents ||= {}
|
||||
Locomotive.Views.ContentEntries ||= {}
|
||||
|
||||
class Locomotive.Views.ContentEntries.NewView extends Locomotive.Views.ContentEntries.FormView
|
||||
|
||||
|
@ -33,7 +33,6 @@ class Locomotive.Views.Pages.ListView extends Backbone.View
|
||||
success: @.on_successful_sort
|
||||
error: @.on_failed_sort
|
||||
|
||||
# on_sort: (data) ->
|
||||
on_successful_sort: (data, status, xhr) ->
|
||||
$.growl('success', xhr.getResponseHeader('X-Message'))
|
||||
|
||||
|
@ -5,7 +5,7 @@ class Locomotive.Views.Shared.ListItemView extends Backbone.View
|
||||
tagName: 'li'
|
||||
|
||||
events:
|
||||
'click a.remove': 'remove_snippet'
|
||||
'click a.remove': 'remove_item'
|
||||
|
||||
template: ->
|
||||
# please overide template
|
||||
@ -15,7 +15,7 @@ class Locomotive.Views.Shared.ListItemView extends Backbone.View
|
||||
|
||||
return @
|
||||
|
||||
remove_snippet: (event) ->
|
||||
remove_item: (event) ->
|
||||
event.stopPropagation() & event.preventDefault()
|
||||
|
||||
if confirm $(event.target).attr('data-confirm')
|
||||
|
@ -58,7 +58,7 @@
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
|
||||
padding: 0 10px;
|
||||
padding: 0 13px;
|
||||
|
||||
background: #fff;
|
||||
@include border-radius(16px);
|
||||
@ -70,6 +70,14 @@
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
span.handle {
|
||||
display: none;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
margin-right: 5px;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
strong {
|
||||
color: #17171D;
|
||||
font-size: 14px;
|
||||
@ -100,7 +108,7 @@
|
||||
div.more, span.actions {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 10px;
|
||||
right: 13px;
|
||||
|
||||
color: #8B8D9A;
|
||||
font-size: 11px;
|
||||
@ -137,6 +145,14 @@
|
||||
}
|
||||
} // li
|
||||
|
||||
&.sortable {
|
||||
li {
|
||||
span.handle {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> hr {
|
||||
margin: 10px 0px;
|
||||
height: 1px;
|
||||
|
@ -37,7 +37,7 @@
|
||||
@mixin light-button {
|
||||
display: inline-block;
|
||||
|
||||
font-family: "Lucida Grande";
|
||||
// font-family: "Lucida Grande";
|
||||
|
||||
position: relative;
|
||||
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 {
|
||||
position: relative;
|
||||
padding: 2px 10px 3px 31px;
|
||||
|
@ -102,36 +102,6 @@ ul.list {
|
||||
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 {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
@ -146,41 +116,68 @@ ul.list {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
// span.handle {
|
||||
// position: relative;
|
||||
// top: 5px;
|
||||
// margin: 0 0 0 15px;
|
||||
// cursor: move;
|
||||
// }
|
||||
} // li div.more
|
||||
} // ul.list li
|
||||
}
|
||||
|
||||
// ul.theme-assets {
|
||||
// margin-left: 40px;
|
||||
//
|
||||
// li.hidden strong a { font-style: italic; color: #8B8D9A; font-weight: normal; }
|
||||
// }
|
||||
#entries-list.list {
|
||||
|
||||
// #contents-list li {
|
||||
// background: none;
|
||||
//
|
||||
// li {
|
||||
// em {
|
||||
// background-position: left -31px;
|
||||
// cursor: move;
|
||||
// }
|
||||
//
|
||||
// strong {
|
||||
// display: block;
|
||||
// height: 31px;
|
||||
//
|
||||
// margin-left: 18px;
|
||||
//
|
||||
// background: transparent image-url("locomotive/list/item-right.png") no-repeat right 0;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
li.item {
|
||||
a {
|
||||
@include single-text-shadow(#fff, 1px, 1px, 1px);
|
||||
}
|
||||
|
||||
span.handle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.more {
|
||||
|
||||
a.remove {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
|
||||
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 {
|
||||
margin: 0px 0 20px 0;
|
||||
|
@ -336,6 +336,13 @@ form.formtastic {
|
||||
|
||||
}
|
||||
|
||||
&.no-label {
|
||||
> textarea, .CodeMirror, .CodeMirror-scroll {
|
||||
margin-top: 12px;
|
||||
width: 868px;
|
||||
}
|
||||
}
|
||||
|
||||
} // li.code
|
||||
|
||||
&.toggle {
|
||||
@ -423,10 +430,14 @@ form.formtastic {
|
||||
input[type=text] {
|
||||
width: 868px;
|
||||
}
|
||||
}
|
||||
|
||||
div.inline-errors {
|
||||
margin-left: 0px;
|
||||
}
|
||||
> .inline-hints {
|
||||
margin-left: 0px !important;
|
||||
}
|
||||
|
||||
> .inline-errors {
|
||||
margin-left: 0px !important;
|
||||
}
|
||||
} // li.no-label
|
||||
|
||||
|
@ -93,7 +93,7 @@ body {
|
||||
> div.inner {
|
||||
position: relative;
|
||||
margin: 0px 8px;
|
||||
padding: 10px 15px 20px 15px;
|
||||
padding: 10px 15px 66px 15px;
|
||||
|
||||
// z-index: 100;
|
||||
|
||||
@ -102,7 +102,7 @@ body {
|
||||
@include box-shadow(rgba(0, 0, 0, 0.3) 0px 0px 6px 4px);
|
||||
@include border-bottom-radius(4px);
|
||||
|
||||
min-height: 150px;
|
||||
min-height: 290px;
|
||||
|
||||
h2 {
|
||||
@include locomotive-link;
|
||||
@ -120,11 +120,9 @@ body {
|
||||
} // > div.inner h2
|
||||
|
||||
h3 {
|
||||
background: transparent image-url("locomotive/list/item.png") no-repeat 0 0;
|
||||
|
||||
padding: 7px 0 10px 20px;
|
||||
|
||||
font-size: 13px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #1e1f26;
|
||||
@include single-text-shadow(#fff, 1px, 1px, 1px);
|
||||
@ -149,9 +147,10 @@ body {
|
||||
} // #content #local-actions-bar
|
||||
|
||||
#local-actions-bottom-bar {
|
||||
position: relative;
|
||||
top: 20px;
|
||||
left: -15px;
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
height: 62px;
|
||||
width: 950px;
|
||||
|
||||
background: #8b8d9a;
|
||||
@ -162,8 +161,6 @@ body {
|
||||
padding: 15px;
|
||||
margin: 0px;
|
||||
|
||||
line-height: 13px;
|
||||
|
||||
a {
|
||||
position: relative;
|
||||
top: 4px;
|
||||
@ -172,7 +169,10 @@ body {
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
|
||||
&.remove { color: #ff092c; }
|
||||
&.remove {
|
||||
@include red-button;
|
||||
top: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ module Locomotive
|
||||
before_filter :authorize_content
|
||||
|
||||
def index
|
||||
@content_entries = @content_type.entries
|
||||
@content_entries = @content_type.list_or_group_entries
|
||||
respond_with @content_entries
|
||||
end
|
||||
|
||||
@ -38,17 +38,14 @@ module Locomotive
|
||||
end
|
||||
|
||||
def sort
|
||||
# TODO
|
||||
# @content_type.sort_contents!(params[:children])
|
||||
# @page = current_site.pages.find(params[:id])
|
||||
# @page.sort_children!(params[:children])
|
||||
@content_type.klass_with_custom_fields(:entries).sort_entries!(params[:entries])
|
||||
respond_with @content_type
|
||||
end
|
||||
|
||||
def destroy
|
||||
@content_entry = @content_type.entries.find(params[:id])
|
||||
@content_entry.destroy
|
||||
respond_with @content_entry, :location => pages_url
|
||||
respond_with @content_entry, :location => content_entries_url(@content_type.slug)
|
||||
end
|
||||
|
||||
protected
|
||||
|
@ -18,6 +18,22 @@ module Locomotive::ContentTypesHelper
|
||||
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
|
||||
#
|
||||
# def fetch_content_types
|
||||
|
@ -23,7 +23,7 @@ module Locomotive
|
||||
before_validation :set_slug
|
||||
before_save :set_visibility
|
||||
before_create :add_to_list_bottom
|
||||
# after_create :send_notifications
|
||||
after_create :send_notifications
|
||||
|
||||
## named scopes ##
|
||||
scope :visible, :where => { :_visible => true }
|
||||
@ -51,8 +51,17 @@ module Locomotive
|
||||
next_or_previous :lt
|
||||
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
|
||||
Locomotive::Liquid::Drops::Content.new(self)
|
||||
Locomotive::Liquid::Drops::ContentEntry.new(self)
|
||||
end
|
||||
|
||||
def to_presenter
|
||||
@ -66,37 +75,35 @@ module Locomotive
|
||||
protected
|
||||
|
||||
def next_or_previous(matcher = :gt)
|
||||
attribute = self.content_type.order_by.to_sym
|
||||
direction = self.content_type.order_direction || 'asc'
|
||||
order_by = self.content_type.order_by_definition
|
||||
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
|
||||
|
||||
# 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
|
||||
# unique one will be generated
|
||||
def set_slug
|
||||
# self._slug = highlighted_field_value.dup if _slug.blank? && highlighted_field_value.present?
|
||||
#
|
||||
# if _slug.present?
|
||||
# self._slug.permalink!
|
||||
# self._slug = next_unique_slug if slug_already_taken?
|
||||
# end
|
||||
self._slug = self._label.dup if self._slug.blank? && self._label.present?
|
||||
|
||||
if self._slug.present?
|
||||
self._slug.permalink!
|
||||
self._slug = self.next_unique_slug if self.slug_already_taken?
|
||||
end
|
||||
end
|
||||
|
||||
# Return the next available unique slug as a string
|
||||
def next_unique_slug
|
||||
# slug = _slug.gsub(/-\d*$/, '')
|
||||
# last_slug = _parent.contents.where(:_id.ne => _id, :_slug => /^#{slug}-?\d*?$/i).order_by(:_slug).last._slug
|
||||
# next_number = last_slug.scan(/-(\d)$/).flatten.first.to_i + 1
|
||||
#
|
||||
# [slug, next_number].join('-')
|
||||
slug = self._slug.gsub(/-\d*$/, '')
|
||||
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
|
||||
[slug, next_number].join('-')
|
||||
end
|
||||
|
||||
# def slug_already_taken?
|
||||
# _parent.contents.where(:_id.ne => _id, :_slug => _slug).any?
|
||||
# end
|
||||
def slug_already_taken?
|
||||
self.class.where(:_id.ne => self._id, :_slug => self._slug).any?
|
||||
end
|
||||
|
||||
def set_visibility
|
||||
[:visible, :active].each do |meth|
|
||||
@ -111,19 +118,15 @@ module Locomotive
|
||||
self._position = self.class.max(:_position).to_i + 1
|
||||
end
|
||||
|
||||
# def send_notifications
|
||||
# return unless self.content_type.api_enabled? && !self.content_type.api_accounts.blank?
|
||||
#
|
||||
# accounts = self.content_type.site.accounts.to_a
|
||||
#
|
||||
# self.content_type.api_accounts.each do |account_id|
|
||||
# next if account_id.blank?
|
||||
#
|
||||
# account = accounts.detect { |a| a.id.to_s == account_id.to_s }
|
||||
#
|
||||
# Locomotive::Notifications.new_content_instance(account, self).deliver
|
||||
# end
|
||||
# end
|
||||
def send_notifications
|
||||
return if !self.content_type.public_form_enabled? || self.content_type.public_form_accounts.blank?
|
||||
|
||||
self.content_type.site.accounts.each do |account|
|
||||
next unless self.content_type.public_form_accounts.include?(account._id.to_s)
|
||||
|
||||
Locomotive::Notifications.new_content_entry(account, self).deliver
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -44,20 +44,33 @@ module Locomotive
|
||||
|
||||
## 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?
|
||||
self.order_by == '_position'
|
||||
end
|
||||
|
||||
def asc_order?
|
||||
self.order_direction.blank? || self.order_direction == 'asc'
|
||||
def order_by_definition
|
||||
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
|
||||
|
||||
def to_presenter
|
||||
@ -135,6 +148,11 @@ module Locomotive
|
||||
|
||||
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
|
||||
self.order_by ||= 'created_at'
|
||||
field = self.entries_custom_fields.find(self.label_field_id) rescue self.entries_custom_fields.first
|
||||
|
@ -38,7 +38,7 @@ module Locomotive
|
||||
end
|
||||
|
||||
def accounts
|
||||
Account.criteria.in(:_id => self.memberships.collect(&:account_id))
|
||||
Account.criteria.in(:_id => self.memberships.map(&:account_id))
|
||||
end
|
||||
|
||||
def admin_memberships
|
||||
|
@ -1,15 +1,15 @@
|
||||
- if contents.empty?
|
||||
%p.no-items!= t('.no_items', :url => new_content_entry_url(@content_type.slug))
|
||||
- if entries.empty?
|
||||
%p.no-items!= t('.no_items', :url => new_content_entry_url(content_type.slug))
|
||||
- else
|
||||
%ul{ :id => 'contents-list', :class => "list #{'sortable' if @content_type.order_by == '_position'}", :'data-url' => sort_admin_contents_path(@content_type.slug, :json) }
|
||||
- contents.each do |content|
|
||||
%li.content{ :id => "content-#{content._id}" }
|
||||
%em
|
||||
%strong
|
||||
= link_to content_label_for(content), edit_admin_content_path(@content_type.slug, content)
|
||||
%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) }
|
||||
- entries.each do |entry|
|
||||
%li.item{ :id => "entry-#{entry._id}" }
|
||||
%span.handle
|
||||
= image_tag 'locomotive/form/icons/drag.png'
|
||||
%strong= link_to entry_label(content_type, entry), edit_content_entry_url(content_type.slug, entry)
|
||||
.more
|
||||
%span
|
||||
!= t('locomotive.contents.index.updated_at')
|
||||
= l content.updated_at, :format => :short rescue 'n/a'
|
||||
!= t('locomotive.content_entries.index.updated_at')
|
||||
= 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
|
@ -6,9 +6,6 @@
|
||||
- content_for :actions do
|
||||
= render 'locomotive/shared/actions/contents'
|
||||
|
||||
- content_for :head do
|
||||
= include_javascripts :contents
|
||||
|
||||
- content_for :buttons do
|
||||
- if can?(:manage, Locomotive::ContentType)
|
||||
= local_action_button :edit, edit_content_type_url(@content_type), :class => 'edit'
|
||||
@ -19,14 +16,15 @@
|
||||
%p= @content_type.description
|
||||
|
||||
- if @content_type.groupable?
|
||||
- @contents.each do |group|
|
||||
%h3= group[:name] || t('.category_noname')
|
||||
= render 'list', :contents => group[:items]
|
||||
%br
|
||||
- @content_entries.each do |group|
|
||||
.box
|
||||
%h3= group[:name] || t('.category_noname')
|
||||
.inner
|
||||
= render 'list', :content_type => @content_type, :entries => group[:entries]
|
||||
- else
|
||||
= render 'list', :contents => @contents
|
||||
= render 'list', :content_type => @content_type, :entries => @content_entries
|
||||
|
||||
- if can?(:manage, Locomotive::ContentType)
|
||||
#local-actions-bottom-bar
|
||||
%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'
|
||||
|
@ -30,4 +30,4 @@
|
||||
- if can?(:manage, current_site)
|
||||
|
||||
= 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' }
|
||||
|
@ -2,7 +2,7 @@
|
||||
!!!
|
||||
%html{ :xmlns => 'http://www.w3.org/1999/xhtml' }
|
||||
%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'
|
||||
= stylesheet_link_tag 'locomotive/not_logged_in', :media => 'screen'
|
||||
|
@ -250,7 +250,7 @@ en:
|
||||
lastest_entries: "Lastest entries"
|
||||
updated_at: "Updated at"
|
||||
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:
|
||||
title: '%{type} — new entry'
|
||||
edit:
|
||||
|
@ -94,7 +94,7 @@ en:
|
||||
content_type:
|
||||
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>"
|
||||
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_accounts: "A notification email will be sent to each of the accounts listed above when a new instance is created"
|
||||
"custom_fields/field":
|
||||
|
@ -79,6 +79,6 @@ es:
|
||||
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"
|
||||
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_accounts: "Un email de notificación será enviado a las cuentas listadas más arriba cuando un nuevo elemento se cree"
|
||||
|
@ -94,6 +94,6 @@ fr:
|
||||
reset: "Si activé, toutes les données de votre site seront détruites avant l'import du nouveau site"
|
||||
content_type:
|
||||
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_accounts: "Un email de notification sera envoyé à chaque compte listé ci-dessus lors de la création d'une nouvelle instance"
|
||||
|
@ -93,7 +93,7 @@ it:
|
||||
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"
|
||||
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_accounts: "Quando viene creata una nuova istanza, una mail di notifica verrà inviata a tutti gli account elencati qui sopra"
|
||||
|
||||
|
@ -79,7 +79,7 @@ nl:
|
||||
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"
|
||||
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: "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"
|
||||
|
@ -93,7 +93,7 @@
|
||||
samples: "Vil gjøre at importen kopierer innhold og assets"
|
||||
reset: "Vil gjøre at alle data slettes for den nye siden importeres."
|
||||
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_accounts: "En varslingsepost vil bli sendt til alle kontoene ovenfor når et nytt element blir opprettet."
|
||||
|
||||
|
@ -93,7 +93,7 @@ ru:
|
||||
samples: "Если включено, процесс импорта также скопирует содержимое и файлы"
|
||||
reset: "Если включено, все данные вашего сайта будут уничтожены перед импортом нового сайта"
|
||||
content_type:
|
||||
item_template: "Вы можете задавать текст, отображаемый для каждого элемента в списке. Просто используйте Liquid. Пр.: {{ content.name }})"
|
||||
item_template: "Вы можете задавать текст, отображаемый для каждого элемента в списке. Просто используйте Liquid. Пр.: {{ entry.name }})"
|
||||
api_enabled: "Это используется для того, чтобы дать людям извне возможность создавать новые экземляры (пример: сообщения в форме контакта)"
|
||||
api_accounts: "Письмо с уведомлением будет отправлено на каждый аккаунт из списка выше, когда создан новый экземпляр"
|
||||
|
||||
|
12
doc/TODO
12
doc/TODO
@ -34,7 +34,7 @@ x edit my site
|
||||
x site picker
|
||||
- content types
|
||||
x move content instances into their own collection
|
||||
- manage custom_fields
|
||||
x manage custom_fields
|
||||
x automatic name
|
||||
x required
|
||||
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 text: formatting
|
||||
- change in main menu
|
||||
- manage contents
|
||||
- list (highlighted field)
|
||||
- slugify
|
||||
- crud
|
||||
x manage contents
|
||||
x list (highlighted field)
|
||||
x slugify
|
||||
x crud
|
||||
x new
|
||||
x date
|
||||
x checkbox
|
||||
x html
|
||||
x file
|
||||
x edit
|
||||
- destroy
|
||||
x destroy
|
||||
- public_form (previously api something)
|
||||
|
||||
- disallow to click twice on the submit form button (spinner ?)
|
||||
|
@ -1,14 +1,14 @@
|
||||
module Locomotive
|
||||
module Liquid
|
||||
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
|
||||
self._source._id.to_s
|
||||
end
|
||||
|
||||
|
||||
# Returns the next content for the parent content type.
|
||||
# If no content is found, nil is returned.
|
||||
#
|
||||
@ -21,7 +21,7 @@ module Locomotive
|
||||
def next
|
||||
self._source.next.to_liquid
|
||||
end
|
||||
|
||||
|
||||
# Returns the previous content for the parent content type.
|
||||
# If no content is found, nil is returned.
|
||||
#
|
||||
@ -43,8 +43,8 @@ module Locomotive
|
||||
end
|
||||
end
|
||||
|
||||
def highlighted_field_value
|
||||
self._source.highlighted_field_value
|
||||
def _label
|
||||
self._label
|
||||
end
|
||||
|
||||
end
|
@ -15,91 +15,6 @@ end
|
||||
# Limit feature for embedded documents
|
||||
|
||||
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
|
||||
module Callbacks
|
||||
|
@ -46,16 +46,16 @@ describe Locomotive::Import::Job do
|
||||
content_type = @site.content_types.where(:slug => 'projects').first
|
||||
content_type.entries.size.should == 5
|
||||
|
||||
content = content_type.entries.first
|
||||
content._permalink.should == 'locomotivecms'
|
||||
content.seo_title.should == 'My open source CMS'
|
||||
content.meta_description.should == 'bla bla bla'
|
||||
content.meta_keywords.should == 'cms ruby engine mongodb'
|
||||
content.name.should == 'Locomotive App'
|
||||
content.thumbnail.url.should_not be_nil
|
||||
content.featured.should == true
|
||||
content.client.name.should == 'My client #1'
|
||||
content.team.first.name.should == 'Michael Scott'
|
||||
entry = content_type.entries.first
|
||||
entry._permalink.should == 'locomotivecms'
|
||||
entry.seo_title.should == 'My open source CMS'
|
||||
entry.meta_description.should == 'bla bla bla'
|
||||
entry.meta_keywords.should == 'cms ruby engine mongodb'
|
||||
entry.name.should == 'Locomotive App'
|
||||
entry.thumbnail.url.should_not be_nil
|
||||
entry.featured.should == true
|
||||
entry.client.name.should == 'My client #1'
|
||||
entry.team.first.name.should == 'Michael Scott'
|
||||
end
|
||||
|
||||
it 'inserts theme assets' do
|
||||
|
Loading…
Reference in New Issue
Block a user