diff --git a/app/controllers/admin/api_contents_controller.rb b/app/controllers/admin/api_contents_controller.rb new file mode 100644 index 00000000..3349ded2 --- /dev/null +++ b/app/controllers/admin/api_contents_controller.rb @@ -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 \ No newline at end of file diff --git a/app/controllers/admin/custom_fields_controller.rb b/app/controllers/admin/custom_fields_controller.rb new file mode 100644 index 00000000..3119d299 --- /dev/null +++ b/app/controllers/admin/custom_fields_controller.rb @@ -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 \ No newline at end of file diff --git a/app/views/admin/custom_fields/edit_category.html.haml b/app/views/admin/custom_fields/edit_category.html.haml new file mode 100644 index 00000000..5cd07d29 --- /dev/null +++ b/app/views/admin/custom_fields/edit_category.html.haml @@ -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 + +   + + %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' + +   + + %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') \ No newline at end of file diff --git a/app/views/admin/shared/_custom_fields.html.haml.old b/app/views/admin/shared/_custom_fields.html.haml.old new file mode 100644 index 00000000..057d7541 --- /dev/null +++ b/app/views/admin/shared/_custom_fields.html.haml.old @@ -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 + + — + + %em= t("admin.custom_fields.kind.#{field.kind.downcase}") + + = g.select :kind, options_for_field_kind + +   + + %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' + + — + + %em + + = g.select :kind, options_for_field_kind + +   + + %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') + + \ No newline at end of file diff --git a/public/images/admin/form/big_item-popup.png b/public/images/admin/form/big_item-popup.png new file mode 100644 index 00000000..329000fe Binary files /dev/null and b/public/images/admin/form/big_item-popup.png differ diff --git a/public/images/admin/form/footer-popup.png b/public/images/admin/form/footer-popup.png new file mode 100644 index 00000000..278e8c17 Binary files /dev/null and b/public/images/admin/form/footer-popup.png differ diff --git a/public/images/admin/form/header-popup.png b/public/images/admin/form/header-popup.png new file mode 100644 index 00000000..84719ea5 Binary files /dev/null and b/public/images/admin/form/header-popup.png differ diff --git a/public/images/admin/form/item-popup.png b/public/images/admin/form/item-popup.png new file mode 100644 index 00000000..cd2d7731 Binary files /dev/null and b/public/images/admin/form/item-popup.png differ diff --git a/public/javascripts/admin/custom_fields/category.js b/public/javascripts/admin/custom_fields/category.js new file mode 100644 index 00000000..50420328 --- /dev/null +++ b/public/javascripts/admin/custom_fields/category.js @@ -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 += ''; + } + 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(); + }); +} \ No newline at end of file diff --git a/public/javascripts/admin/utils.js b/public/javascripts/admin/utils.js new file mode 100644 index 00000000..2aa3ddc6 --- /dev/null +++ b/public/javascripts/admin/utils.js @@ -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(); +} diff --git a/vendor/plugins/custom_fields/spec/integration/custom_fields_for_spec.rb b/vendor/plugins/custom_fields/spec/integration/custom_fields_for_spec.rb new file mode 100644 index 00000000..68b1ecac --- /dev/null +++ b/vendor/plugins/custom_fields/spec/integration/custom_fields_for_spec.rb @@ -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 \ No newline at end of file diff --git a/vendor/plugins/custom_fields/spec/integration/types/category_spec.rb b/vendor/plugins/custom_fields/spec/integration/types/category_spec.rb new file mode 100644 index 00000000..c107dc0c --- /dev/null +++ b/vendor/plugins/custom_fields/spec/integration/types/category_spec.rb @@ -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 \ No newline at end of file