very simple api for contents (just create for now) + fix a lot of bugs in the custom fields plugin and some enhancements as well + add an ui for manage categories + fix bugs

This commit is contained in:
dinedine 2010-06-10 15:30:32 +02:00
parent 7ccc3d4548
commit d0ff08c9a1
12 changed files with 318 additions and 0 deletions

View File

@ -0,0 +1,29 @@
module Admin
class ApiContentsController < ActionController::Base
include Locomotive::Routing::SiteDispatcher
before_filter :require_site
before_filter :set_content_type
def create
@content = @content_type.contents.build(params[:content])
respond_to do |format|
if @content.save
format.json { render :json => { :content => @content } }
else
format.json { render :json => { :content => @content, :errors => @content.errors } }
end
end
end
protected
def set_content_type
@content_type = current_site.content_types.where(:slug => params[:slug]).first
end
end
end

View File

@ -0,0 +1,33 @@
module Admin
class CustomFieldsController < BaseController
layout false
before_filter :set_content_type
def edit
@field = @content_type.content_custom_fields.find(params[:id])
render :action => "edit_#{@field.kind.downcase}"
end
def update
@field = @content_type.content_custom_fields.find(params[:id])
@field.updated_at = Time.now # forces mongoid to save the object
params[:custom_field][:category_items_attributes].delete('-1')
if @field.update_attributes(params[:custom_field])
render :json => @field.attributes
else
render :json => { :error => translate_flash_msg(:successful) }
end
end
protected
def set_content_type
@content_type = current_site.content_types.where(:slug => params[:slug]).first
end
end
end

View File

@ -0,0 +1,43 @@
#edit-custom-field-category
.inner
%h2= t('.title')
%p= t('.help')
= semantic_form_for @field, :as => :custom_field, :url => admin_custom_field_url(@content_type.slug, @field) do |f|
= f.foldable_inputs :name => t('.collection_label'), :class => 'editable-list off' do
- @field.ordered_category_items.each do |item|
= f.fields_for :category_items, item, :child_index => item._index do |g|
%li{ :class => "item added #{'error' unless item.errors.empty?}"}
%span.handle
= image_tag 'admin/form/icons/drag.png'
= g.hidden_field :position, :class => 'position'
= g.text_field :name
&nbsp;
%span.actions
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove', :confirm => t('admin.messages.confirm')
= f.fields_for :category_items, @field.category_items.build, :child_index => '-1' do |g|
%li{ :class => 'item template' }
%span.handle
= image_tag 'admin/form/icons/drag.png'
= g.hidden_field :position, :class => 'position'
= g.text_field :name, :class => 'string name'
&nbsp;
%span.actions
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove', :confirm => t('admin.messages.confirm')
%button{ :class => 'button light add', :type => 'button' }
%span= t('admin.buttons.new_item')
.popup-actions
%p
%button.button.light{ :type => 'button' }
%span= t('admin.shared.form_actions.update')

View File

@ -0,0 +1,59 @@
- collection_name = "#{collection_name.singularize}_custom_fields"
- custom_fields = f.object.send(collection_name.to_sym)
- ordered_custom_fields = f.object.send(:"ordered_#{collection_name}")
= f.foldable_inputs :name => :custom_fields, :class => 'editable-list fields' do
- ordered_custom_fields.each do |field|
= f.fields_for collection_name.to_sym, field, :child_index => field._index do |g|
%li{ :class => "item added #{'error' unless field.errors.empty?}"}
%span.handle
= image_tag 'admin/form/icons/drag.png'
= g.hidden_field :position, :class => 'position'
= g.hidden_field :_alias, :class => 'alias'
= g.hidden_field :hint, :class => 'hint'
= g.text_field :label
&mdash;
%em= t("admin.custom_fields.kind.#{field.kind.downcase}")
= g.select :kind, options_for_field_kind
&nbsp;
%span.actions
= link_to image_tag('admin/form/pen.png'), '#', :class => 'edit first'
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove', :confirm => t('admin.messages.confirm')
= f.fields_for collection_name.to_sym, custom_fields.build(:label => 'field name'), :child_index => '-1' do |g|
%li{ :class => 'item template' }
%span.handle
= image_tag 'admin/form/icons/drag.png'
= g.hidden_field :position, :class => 'position'
= g.hidden_field :_alias, :class => 'alias'
= g.hidden_field :hint, :class => 'hint'
= g.text_field :label, :class => 'string label void'
&mdash;
%em
= g.select :kind, options_for_field_kind
&nbsp;
%span.actions
= link_to image_tag('admin/form/pen.png'), '#', :class => 'edit first'
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove', :confirm => t('admin.messages.confirm')
%button{ :class => 'button light add', :type => 'button' }
%span= t('admin.buttons.new_item')

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 979 B

View File

@ -0,0 +1,91 @@
// edit category collection
var SetupCustomFieldCategoryEditor = function(target) {
var refreshPosition = function() {
jQuery.each($('#edit-custom-field-category .editable-list li.added input.position'), function(index) {
$(this).val(index);
});
};
$('#edit-custom-field-category .editable-list li.template button').click(function() {
var lastRow = $(this).parents('li.template');
if (lastRow.find('input.name').val() == '') return ;
var newRow = lastRow.clone(true).removeClass('template').addClass('added new').insertBefore(lastRow);
var dateFragment = '[' + new Date().getTime() + ']';
newRow.find('input, select').each(function(index) {
$(this).attr('name', $(this).attr('name').replace('[-1]', dateFragment));
});
// then reset the form
lastRow.find('input').val('');
// warn the sortable widget about the new row
$("#edit-custom-field-category .editable-list ol").sortable('refresh');
refreshPosition();
// resize popup
$.fancybox.resize();
});
$('#edit-custom-field-category .editable-list li a.remove').click(function(e) {
if (confirm($(this).attr('data-confirm'))) {
var parent = $(this).parents('li');
if (parent.hasClass('new'))
parent.remove();
else {
var field = parent.find('input.position')
field.attr('name', field.attr('name').replace('[position]', '[_destroy]'));
parent.hide().removeClass('added');
}
refreshPosition();
}
e.preventDefault();
e.stopPropagation();
});
$("#edit-custom-field-category .editable-list ol").sortable({
handle: 'span.handle',
items: 'li:not(.template)',
axis: 'y',
update: refreshPosition
});
/* ___ submit ___ */
var updateSelectOptions = function(list) {
console.log('updateSelectOptions [begin]');
var options = '';
var selectedValue = target.val();
for (var i = 0; i < list.length; i++) {
options += '<option value="' + list[i]._id + '" >' + list[i].name + '</option>';
}
target.html(options);
target.val(selectedValue);
console.log('updateSelectOptions [end]');
};
$('#edit-custom-field-category .popup-actions button').click(function(e) {
var form = $('#edit-custom-field-category form');
$.ajax({
type: 'PUT',
dataType: 'json',
data: form.serialize(),
url: form.attr('action'),
success: function(data) {
console.log("success");
if (data.error == null) {
list = data.category_items.sort(function(a, b) { return (a.position - b.position); });
updateSelectOptions(list);
$.fancybox.close();
} else
$.growl("error", data.error);
}
});
e.preventDefault();
e.stopPropagation();
});
}

View File

@ -0,0 +1,9 @@
function makeSlug(val, sep) { // code largely inspired by http://www.thewebsitetailor.com/jquery-slug-plugin/
if (typeof sep == 'undefined') sep = '_';
var alphaNumRegexp = new RegExp('[^a-zA-Z0-9\\' + sep + ']', 'g');
var avoidDuplicateRegexp = new RegExp('[\\' + sep + ']{2,}', 'g');
val = val.replace(/\s/g, sep);
val = val.replace(alphaNumRegexp, '');
val = val.replace(avoidDuplicateRegexp, sep);
return val.toLowerCase();
}

View File

@ -0,0 +1,28 @@
require 'spec_helper'
describe CustomFields::CustomFieldsFor do
describe 'Saving' do
before(:each) do
@project = Project.new(:name => 'Locomotive')
@project.person_custom_fields.build(:label => 'E-mail', :_alias => 'email', :kind => 'String')
@project.person_custom_fields.build(:label => 'Age', :_alias => 'age', :kind => 'String')
end
context '@create' do
it 'persists parent object' do
lambda { @project.save }.should change(Project, :count).by(1)
end
it 'persists custom fields' do
@project.save && @project.reload
@project.person_custom_fields.count.should == 2
end
end
end
end

View File

@ -0,0 +1,26 @@
require 'spec_helper'
describe CustomFields::Types::Category do
before(:each) do
@project = Project.new(:name => 'Locomotive')
@field = @project.task_custom_fields.build(:label => 'Main category', :_alias => 'main_category', :kind => 'Category')
end
context 'saving category items' do
before(:each) do
@field.category_items.build :name => 'Development'
@field.category_items.build :name => 'Design'
@field.updated_at = Time.now
end
it 'persists items' do
@field.save.should be_true
@project.reload
@project.task_custom_fields.first.category_items.size.should == 2
end
end
end