fix bug about page parts when creating or modifying layout + begin to work on the custom content types feature (50% done)
This commit is contained in:
parent
1ed613ede8
commit
61958d9452
52
app/controllers/admin/content_types_controller.rb
Normal file
52
app/controllers/admin/content_types_controller.rb
Normal file
@ -0,0 +1,52 @@
|
||||
module Admin
|
||||
class ContentTypesController < BaseController
|
||||
|
||||
sections 'contents'
|
||||
|
||||
def new
|
||||
@content_type = current_site.content_types.build
|
||||
end
|
||||
|
||||
def edit
|
||||
@content_type = current_site.content_types.find(params[:id])
|
||||
end
|
||||
|
||||
def create
|
||||
@content_type = current_site.content_types.build(params[:content_type])
|
||||
|
||||
if @content_type.save
|
||||
flash_success!
|
||||
redirect_to edit_admin_content_type_url(@content_type)
|
||||
else
|
||||
flash_error!
|
||||
render :action => 'new'
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
@content_type = current_site.content_types.find(params[:id])
|
||||
|
||||
if @content_type.update_attributes(params[:content_type])
|
||||
flash_success!
|
||||
redirect_to edit_admin_content_type_url(@content_type)
|
||||
else
|
||||
flash_error!
|
||||
render :action => "edit"
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@content_type = current_site.content_types.find(params[:id])
|
||||
|
||||
begin
|
||||
@content_type.destroy
|
||||
flash_success!
|
||||
rescue Exception => e
|
||||
flash[:error] = e.to_s
|
||||
end
|
||||
|
||||
redirect_to admin_content_types_url
|
||||
end
|
||||
|
||||
end
|
||||
end
|
64
app/controllers/admin/contents_controller.rb
Normal file
64
app/controllers/admin/contents_controller.rb
Normal file
@ -0,0 +1,64 @@
|
||||
module Admin
|
||||
class ContentsController < BaseController
|
||||
|
||||
sections 'contents'
|
||||
|
||||
before_filter :set_content_type
|
||||
|
||||
def index
|
||||
@contents = @content_type.contents
|
||||
end
|
||||
|
||||
def new
|
||||
@content = @content_type.contents.build
|
||||
end
|
||||
|
||||
def edit
|
||||
@content = @content_type.contents.find(params[:id])
|
||||
end
|
||||
|
||||
def create
|
||||
@content = @content_type.contents.build(params[:content])
|
||||
|
||||
if @content.save
|
||||
flash_success!
|
||||
redirect_to edit_admin_content_url(@content_type.slug, @content)
|
||||
else
|
||||
flash_error!
|
||||
render :action => 'new'
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
@content = @content_type.contents.find(params[:id])
|
||||
|
||||
if @content.update_attributes(params[:content])
|
||||
flash_success!
|
||||
redirect_to edit_admin_content_url(@content_type.slug, @content)
|
||||
else
|
||||
flash_error!
|
||||
render :action => "edit"
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@content = @content_type.contents.find(params[:id])
|
||||
|
||||
begin
|
||||
@content.destroy
|
||||
flash_success!
|
||||
rescue Exception => e
|
||||
flash[:error] = e.to_s
|
||||
end
|
||||
|
||||
redirect_to admin_contents_url(@content_type.slug)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def set_content_type
|
||||
@content_type = current_site.content_types.where(:slug => params[:slug]).first
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -13,10 +13,10 @@ module Admin::BaseHelper
|
||||
end
|
||||
|
||||
def admin_submenu_item(name, url, options = {}, &block)
|
||||
default_options = { :i18n => true, :css => '' }
|
||||
default_options = { :i18n => true, :css => name.dasherize.downcase }
|
||||
default_options.merge!(options)
|
||||
|
||||
css = "#{name.dasherize.downcase} #{'on' if name == sections(:sub)} #{'links' if block_given?} #{options[:css]}"
|
||||
css = "#{'on' if name == sections(:sub)} #{'links' if block_given?} #{options[:css]}"
|
||||
|
||||
label_link = default_options[:i18n] ? t("admin.shared.menu.#{name}") : name
|
||||
# if block_given?
|
||||
|
8
app/models/content_instance.rb
Normal file
8
app/models/content_instance.rb
Normal file
@ -0,0 +1,8 @@
|
||||
class ContentInstance
|
||||
include Mongoid::Document
|
||||
include Mongoid::Timestamps
|
||||
|
||||
# fields ##
|
||||
field :name
|
||||
|
||||
end
|
35
app/models/content_type.rb
Normal file
35
app/models/content_type.rb
Normal file
@ -0,0 +1,35 @@
|
||||
class ContentType
|
||||
include Mongoid::Document
|
||||
include Mongoid::Timestamps
|
||||
# include Mongoid::CustomFields
|
||||
|
||||
## fields ##
|
||||
field :name
|
||||
field :description
|
||||
field :slug
|
||||
field :order_by
|
||||
|
||||
## associations ##
|
||||
belongs_to_related :site
|
||||
embeds_many :contents, :class_name => 'ContentInstance'
|
||||
|
||||
## callbacks ##
|
||||
before_validate :normalize_slug
|
||||
|
||||
## validations ##
|
||||
validates_presence_of :site, :name, :slug
|
||||
validates_uniqueness_of :slug, :scope => :site
|
||||
|
||||
## behaviours ##
|
||||
# custom_fields_for :contents
|
||||
|
||||
## methods ##
|
||||
|
||||
protected
|
||||
|
||||
def normalize_slug
|
||||
self.slug = self.name.clone if self.slug.blank? && self.name.present?
|
||||
self.slug.slugify! if self.slug.present?
|
||||
end
|
||||
|
||||
end
|
@ -17,24 +17,23 @@ class Layout < LiquidTemplate
|
||||
|
||||
def build_parts_from_value
|
||||
if self.value_changed? || self.new_record?
|
||||
self.parts.clear
|
||||
|
||||
body = nil
|
||||
|
||||
self.value.scan(Locomotive::Regexps::CONTENT_FOR).each do |part|
|
||||
part[1].strip!
|
||||
part[1] = nil if part[1].empty?
|
||||
self.value.scan(Locomotive::Regexps::CONTENT_FOR).each do |attributes|
|
||||
slug = attributes[0].strip.downcase
|
||||
name = attributes[1].strip.gsub("\"", '')
|
||||
name = nil if name.empty?
|
||||
name ||= I18n.t('attributes.defaults.page_parts.name') if slug == 'layout'
|
||||
|
||||
slug = part[0].strip.downcase
|
||||
|
||||
if slug == 'layout'
|
||||
body = PagePart.new :slug => slug, :name => I18n.t('attributes.defaults.page_parts.name')
|
||||
if part = self.parts.detect { |p| p.slug == slug }
|
||||
part.name = name if name.present?
|
||||
else
|
||||
self.parts.build :slug => slug, :name => (part[1] || slug).gsub("\"", '')
|
||||
end
|
||||
self.parts.build :slug => slug, :name => name || slug
|
||||
end
|
||||
end
|
||||
|
||||
self.parts.insert(0, body) if body
|
||||
# body always first
|
||||
body = self.parts.detect { |p| p.slug == 'layout' }
|
||||
self.parts.delete(body)
|
||||
self.parts.insert(0, body)
|
||||
|
||||
@_update_pages = true if self.value_changed?
|
||||
end
|
||||
|
@ -15,7 +15,7 @@ class LiquidTemplate
|
||||
|
||||
## validations ##
|
||||
validates_presence_of :site, :name, :slug, :value
|
||||
validates_uniqueness_of :slug, :scope => [:site_id, :_type]
|
||||
validates_uniqueness_of :slug, :scope => :site_id #[:site_id, :_type]
|
||||
|
||||
protected
|
||||
|
||||
|
@ -13,6 +13,7 @@ class Site
|
||||
has_many_related :snippets
|
||||
has_many_related :theme_assets
|
||||
has_many_related :asset_collections
|
||||
has_many_related :content_types
|
||||
embeds_many :memberships
|
||||
|
||||
## validations ##
|
||||
@ -83,7 +84,7 @@ class Site
|
||||
end
|
||||
|
||||
def destroy_in_cascade!
|
||||
%w{pages layouts snippets theme_assets asset_collections}.each do |association|
|
||||
%w{pages layouts snippets theme_assets asset_collections content_types}.each do |association|
|
||||
self.send(association).destroy_all
|
||||
end
|
||||
end
|
||||
|
4
app/views/admin/content_types/_form.html.haml
Normal file
4
app/views/admin/content_types/_form.html.haml
Normal file
@ -0,0 +1,4 @@
|
||||
= f.inputs :name => :information do
|
||||
= f.input :name
|
||||
= f.input :slug, :required => false
|
||||
= f.input :description, :as => 'text'
|
16
app/views/admin/content_types/edit.html.haml
Normal file
16
app/views/admin/content_types/edit.html.haml
Normal file
@ -0,0 +1,16 @@
|
||||
- title t('.title')
|
||||
|
||||
- content_for :submenu do
|
||||
= render 'admin/shared/menu/contents'
|
||||
|
||||
- content_for :buttons do
|
||||
= admin_button_tag :show_items, admin_contents_url(@content_type.slug), :class => 'show'
|
||||
= admin_button_tag :new_item, new_admin_content_url(@content_type.slug), :class => 'show'
|
||||
|
||||
%p= t('.help')
|
||||
|
||||
= semantic_form_for @content_type, :url => admin_content_type_url(@content_type) do |form|
|
||||
|
||||
= render 'form', :f => form
|
||||
|
||||
= render 'admin/shared/form_actions', :back_url => admin_contents_url(@content_type.slug), :button_label => :update
|
15
app/views/admin/content_types/new.html.haml
Normal file
15
app/views/admin/content_types/new.html.haml
Normal file
@ -0,0 +1,15 @@
|
||||
- title t('.title')
|
||||
|
||||
- content_for :head do
|
||||
= javascript_include_tag 'admin/content_types.js'
|
||||
|
||||
- content_for :submenu do
|
||||
= render 'admin/shared/menu/contents'
|
||||
|
||||
%p= t('.help')
|
||||
|
||||
= semantic_form_for @content_type, :url => admin_content_types_url do |f|
|
||||
|
||||
= render 'form', :f => f
|
||||
|
||||
= render 'admin/shared/form_actions', :back_url => admin_pages_url, :button_label => :create
|
17
app/views/admin/contents/index.html.haml
Normal file
17
app/views/admin/contents/index.html.haml
Normal file
@ -0,0 +1,17 @@
|
||||
- title t('.title', :type => @content_type.name)
|
||||
|
||||
- content_for :submenu do
|
||||
= render 'admin/shared/menu/contents'
|
||||
|
||||
- content_for :buttons do
|
||||
= admin_button_tag :edit, edit_admin_content_type_url(@content_type), :class => 'edit'
|
||||
= admin_button_tag :download, '#', :class => 'download'
|
||||
= admin_button_tag :new, new_admin_content_url(@content_type.slug), :class => 'new'
|
||||
|
||||
- if @content_type.description.present?
|
||||
%p= @content_type.description
|
||||
|
||||
- if @contents.empty?
|
||||
%p.no-items= t('.no_items', :url => new_admin_content_url(@content_type.slug))
|
||||
- else
|
||||
foo bar
|
@ -1,2 +1,9 @@
|
||||
%ul
|
||||
= admin_submenu_item 'pages', admin_pages_url
|
||||
|
||||
- current_site.content_types.each do |content_type|
|
||||
- item_on = (content_type.slug == @content_type.slug) rescue nil
|
||||
= admin_submenu_item content_type.name, admin_contents_url(content_type.slug), :i18n => false, :css => (item_on ? 'on' : '')
|
||||
|
||||
.action
|
||||
= link_to content_tag(:span, t('admin.content_types.index.new')), new_admin_content_type_url
|
@ -28,11 +28,11 @@ module Mongoid #:nodoc:
|
||||
conditions[scoped_attr] = document.attributes[scoped_attr]
|
||||
end
|
||||
end
|
||||
|
||||
# Rails.logger.debug "conditions = #{conditions.inspect} / #{options[:scope].inspect}"
|
||||
|
||||
Rails.logger.debug "conditions = #{conditions.inspect} / #{options[:scope].inspect}"
|
||||
|
||||
return if document.class.where(conditions).empty?
|
||||
|
||||
|
||||
# if document.new_record? || key_changed?(document)
|
||||
document.errors.add(attribute, :taken, :default => options[:message], :value => value)
|
||||
# end
|
||||
|
@ -138,7 +138,26 @@ en:
|
||||
assets:
|
||||
new:
|
||||
title: New asset
|
||||
|
||||
|
||||
content_types:
|
||||
index:
|
||||
new: new model
|
||||
new:
|
||||
title: New model
|
||||
help: "Create your own data model (Projects, People, ...etc). Your model should have one field at least. The items created from this content type would have their first field mandatory."
|
||||
edit:
|
||||
title: Editing model
|
||||
help: "Your model should have one field at least. The items created from this content type would have their first field mandatory."
|
||||
show_items: show items
|
||||
new_item: new item
|
||||
|
||||
contents:
|
||||
index:
|
||||
title: 'Listing "{{type}}"'
|
||||
edit: edit model
|
||||
download: download items
|
||||
new: new item
|
||||
no_items: "There are no items for now. Just click <a href=\"{{url}}\">here</a> to create the first one."
|
||||
|
||||
formtastic:
|
||||
titles:
|
||||
|
@ -41,7 +41,11 @@ Locomotive::Application.routes.draw do |map|
|
||||
|
||||
resources :asset_collections
|
||||
|
||||
resources :assets, :path => "asset_collections/:collection_id"
|
||||
resources :assets, :path => "asset_collections/:collection_id/assets"
|
||||
|
||||
resources :content_types
|
||||
|
||||
resources :contents, :path => "content_types/:slug/contents"
|
||||
|
||||
end
|
||||
|
||||
|
52
doc/TODO
52
doc/TODO
@ -1,3 +1,25 @@
|
||||
BOARD:
|
||||
- content types / models (CRUD)
|
||||
- contents (CRUD)
|
||||
|
||||
BACKLOG:
|
||||
- liquid rendering engine
|
||||
- theme assets
|
||||
- assets collection
|
||||
- custom models
|
||||
- asset collections: custom resizing if image
|
||||
|
||||
- devise messages in French
|
||||
- localize devise emails
|
||||
- refactoring admin crud (pages + layouts + snippets)
|
||||
- refactoring page.rb => create module pagetree
|
||||
- refactoring: CustomFields::CustomField => CustomFields::Field
|
||||
|
||||
BUGS:
|
||||
- theme assets: disable version if not image
|
||||
- assets uploader: remove old files if new one
|
||||
|
||||
DONE:
|
||||
x admin layout
|
||||
x logout button
|
||||
x slugify page
|
||||
@ -34,22 +56,18 @@ x create 404 + index pages once a site is created
|
||||
x can not delete index + 404 pages
|
||||
x validates_uniqueness_of :slug, :scope => :id
|
||||
x domain scoping when authenticating
|
||||
- theme assets
|
||||
x theme assets
|
||||
x create / update
|
||||
x slug
|
||||
x filename from slug
|
||||
x can not replace a javascript by a stylesheet
|
||||
- disable version if not image
|
||||
- asset collections
|
||||
x asset collections
|
||||
x create / update
|
||||
x sort assets
|
||||
x removing assets
|
||||
- assets
|
||||
- destroy
|
||||
- custom resizing
|
||||
- assets uploader:
|
||||
- remove old files if new one
|
||||
- custom fields:
|
||||
x assets
|
||||
x destroy
|
||||
x custom fields:
|
||||
x renaming fields
|
||||
x extract a plugin from custom fields
|
||||
x ui
|
||||
@ -57,18 +75,4 @@ x domain scoping when authenticating
|
||||
x rename asset_field
|
||||
x nested attributes
|
||||
x keep tracks of all custom fields (adding / editing assets) + order them
|
||||
x duplicate fields
|
||||
- apply in asset_field (in order to handle Date, File, ...etc)
|
||||
|
||||
BACKLOG:
|
||||
- liquid rendering engine
|
||||
- theme assets
|
||||
- assets collection
|
||||
- custom models
|
||||
|
||||
- devise messages in French
|
||||
- localize devise emails
|
||||
- refactoring admin crud (pages + layouts + snippets)
|
||||
- refactoring page.rb => create module pagetree
|
||||
|
||||
|
||||
x duplicate fields
|
@ -1,6 +1,6 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
// automatic slug from snippet name
|
||||
// automatic slug from collection name
|
||||
$('#asset_collection_name').keypress(function() {
|
||||
var input = $(this);
|
||||
var slug = $('#asset_collection_slug');
|
||||
@ -21,7 +21,7 @@ $(document).ready(function() {
|
||||
var ids = jQuery.map(list.sortable('toArray'), function(e) {
|
||||
return e.match(/asset-(\w+)/)[1];
|
||||
}).join(',');
|
||||
$('#asset_collection_assets_order').val(ids || '0');
|
||||
$('#asset_collection_assets_order').val(ids || '');
|
||||
}
|
||||
|
||||
$('ul.assets.sortable').sortable({
|
||||
|
16
public/javascripts/admin/content_types.js
Normal file
16
public/javascripts/admin/content_types.js
Normal file
@ -0,0 +1,16 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
// automatic slug from name
|
||||
$('#content_type_name').keypress(function() {
|
||||
var input = $(this);
|
||||
var slug = $('#content_type_slug');
|
||||
|
||||
if (!slug.hasClass('filled')) {
|
||||
setTimeout(function() {
|
||||
slug.val(input.val().replace(/\s/g, '_').toLowerCase());
|
||||
}, 50);
|
||||
}
|
||||
});
|
||||
|
||||
$('#content_type_slug').keypress(function() { $(this).addClass('filled'); });
|
||||
});
|
@ -63,8 +63,15 @@ Factory.define :theme_asset do |a|
|
||||
a.association :site
|
||||
end
|
||||
|
||||
## Asset collection ##
|
||||
## Asset collections ##
|
||||
Factory.define :asset_collection do |s|
|
||||
s.association :site, :factory => :site
|
||||
s.name 'Trip to Chicago'
|
||||
end
|
||||
|
||||
## Content types ##
|
||||
Factory.define :content_type do |t|
|
||||
t.association :site, :factory => :site
|
||||
t.name 'My project'
|
||||
end
|
||||
|
||||
|
@ -9,6 +9,7 @@ describe AssetCollection do
|
||||
describe 'custom fields (beta)' do
|
||||
|
||||
before(:each) do
|
||||
Site.any_instance.stubs(:create_default_pages!).returns(true)
|
||||
site = Factory.build(:site)
|
||||
Site.stubs(:find).returns(site)
|
||||
@collection = Factory.build(:asset_collection, :site => site)
|
||||
@ -139,13 +140,7 @@ describe AssetCollection do
|
||||
end
|
||||
|
||||
context 'managing from hash' do
|
||||
|
||||
# before(:each) do
|
||||
# site = Factory.build(:site)
|
||||
# Site.stubs(:find).returns(site)
|
||||
# @collection.site = site
|
||||
# end
|
||||
|
||||
|
||||
it 'should add new field' do
|
||||
@collection.asset_custom_fields.clear
|
||||
@collection.asset_custom_fields.build :label => 'Title'
|
||||
|
35
spec/models/content_type_spec.rb
Normal file
35
spec/models/content_type_spec.rb
Normal file
@ -0,0 +1,35 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe ContentType do
|
||||
|
||||
before(:each) do
|
||||
Site.any_instance.stubs(:create_default_pages!).returns(true)
|
||||
end
|
||||
|
||||
it 'should have a valid factory' do
|
||||
Factory.build(:content_type).should be_valid
|
||||
end
|
||||
|
||||
# Validations ##
|
||||
|
||||
%w{site name}.each do |field|
|
||||
it "should validate presence of #{field}" do
|
||||
content_type = Factory.build(:content_type, field.to_sym => nil)
|
||||
content_type.should_not be_valid
|
||||
content_type.errors[field.to_sym].should == ["can't be blank"]
|
||||
end
|
||||
end
|
||||
|
||||
it 'should validate presence of slug' do
|
||||
content_type = Factory.build(:content_type, :name => nil, :slug => nil)
|
||||
content_type.should_not be_valid
|
||||
content_type.errors[:slug].should == ["can't be blank"]
|
||||
end
|
||||
|
||||
it 'should validate uniqueness of slug' do
|
||||
content_type = Factory(:content_type)
|
||||
(content_type = Factory.build(:content_type, :site => content_type.site)).should_not be_valid
|
||||
content_type.errors[:slug].should == ["is already taken"]
|
||||
end
|
||||
|
||||
end
|
@ -38,7 +38,7 @@ describe Layout do
|
||||
@layout.pages << page
|
||||
@layout.save
|
||||
end
|
||||
|
||||
|
||||
it 'should add parts to pages if layout changes' do
|
||||
@layout.value = @layout.value + "..."
|
||||
page = Factory.build(:page, :layout => @layout, :site => nil)
|
||||
|
Loading…
Reference in New Issue
Block a user