diff --git a/Gemfile b/Gemfile index 24aeeb5a..b1a235d6 100644 --- a/Gemfile +++ b/Gemfile @@ -20,7 +20,8 @@ gem 'inherited_resources', '~> 1.1.2' gem 'rmagick', '2.12.2' gem 'locomotive_carrierwave', '0.5.0.1.beta3', :require => 'carrierwave' -gem 'custom_fields', '1.0.0.beta.11' +# gem 'custom_fields', '1.0.0.beta.11' +gem 'custom_fields', :path => '../gems/custom_fields' gem 'fog', '0.3.7' gem 'mimetype-fu' gem 'actionmailer-with-request', :require => 'actionmailer_with_request' diff --git a/Gemfile.lock b/Gemfile.lock index 63f50938..1287de43 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -11,6 +11,14 @@ GIT xpath (0.1.2) nokogiri (~> 1.4) +PATH + remote: ../gems/custom_fields + specs: + custom_fields (1.0.0.beta.11) + activesupport (>= 3.0.7) + locomotive_carrierwave + mongoid (~> 2.0.1) + GEM remote: http://rubygems.org/ specs: @@ -51,7 +59,7 @@ GEM activesupport (= 3.0.7) activesupport (3.0.7) archive-tar-minitar (0.5.2) - arel (2.0.9) + arel (2.0.10) autotest (4.4.6) ZenTest (>= 4.4.1) bcrypt-ruby (2.1.4) @@ -87,10 +95,6 @@ GEM cucumber-rails (0.3.2) cucumber (>= 0.8.0) culerity (0.2.15) - custom_fields (1.0.0.beta.11) - activesupport (>= 3.0.7) - locomotive_carrierwave - mongoid (~> 2.0.1) daemons (1.1.3) database_cleaner (0.6.7) delayed_job (2.1.4) @@ -275,7 +279,7 @@ DEPENDENCIES capybara cucumber (= 0.8.5) cucumber-rails - custom_fields (= 1.0.0.beta.11) + custom_fields! database_cleaner delayed_job (= 2.1.4) delayed_job_mongoid (= 1.0.2) diff --git a/app/helpers/admin/content_types_helper.rb b/app/helpers/admin/content_types_helper.rb index aa6cd289..e59d06bc 100644 --- a/app/helpers/admin/content_types_helper.rb +++ b/app/helpers/admin/content_types_helper.rb @@ -7,7 +7,7 @@ module Admin::ContentTypesHelper @content_types = current_site.content_types.ordered. limit(:contents => Locomotive.config.lastest_items_nb). - only(:name, :slug, :highlighted_field_name, :content_custom_fields_version).to_a + only(:name, :slug, :highlighted_field_name, :content_custom_fields_version, :order_by).to_a if @content_type && @content_type.persisted? && @content_types.index(@content_type) >= MAX_DISPLAYED_CONTENTS @content_types.delete(@content_type) diff --git a/app/helpers/admin/custom_fields_helper.rb b/app/helpers/admin/custom_fields_helper.rb index 7766e21d..2c8a9d2f 100644 --- a/app/helpers/admin/custom_fields_helper.rb +++ b/app/helpers/admin/custom_fields_helper.rb @@ -1,7 +1,7 @@ module Admin::CustomFieldsHelper def options_for_field_kind - %w(string text category boolean date file).map do |kind| + %w(string text category boolean date file has_one has_many).map do |kind| [t("custom_fields.kind.#{kind}"), kind] end end @@ -39,4 +39,19 @@ module Admin::CustomFieldsHelper end end + def options_for_association_target + current_site.content_types.collect { |c| [c.name, c.content_klass.to_s] } + end + + def options_for_has_one(field) + target_contents_from_field(field).collect { |c| [c._label, c._id] } + end + + alias :options_for_has_many :options_for_has_one + + def target_contents_from_field(field) + content_type = field.target.constantize._parent + content_type.ordered_contents + end + end diff --git a/app/models/content_instance.rb b/app/models/content_instance.rb index d4104d4c..08b48964 100644 --- a/app/models/content_instance.rb +++ b/app/models/content_instance.rb @@ -40,9 +40,11 @@ class ContentInstance end def highlighted_field_value - self.send(self.content_type.highlighted_field._name) + self.send(self.content_type.highlighted_field_name) end + alias :_label :highlighted_field_value + def visible? self._visible || self._visible.nil? end diff --git a/app/views/admin/custom_fields/_custom_form.html.haml b/app/views/admin/custom_fields/_custom_form.html.haml index d43766b4..97e710b1 100644 --- a/app/views/admin/custom_fields/_custom_form.html.haml +++ b/app/views/admin/custom_fields/_custom_form.html.haml @@ -35,4 +35,40 @@ != t('.delete_file') = form.check_box :"remove_#{field._name}" + - elsif field.has_one? + = form.input field._alias.to_sym, :label => field.label, :hint => field.hint, :input_html => { :class => 'has_one' }, :as => :select, :collection => options_for_has_one(field), :selected => form.object.send(field._alias.to_sym).try(:_id) + + - elsif field.has_many? + = form.custom_input field._alias.to_sym, :label => field.label, :hint => field.hint, :css => 'has-many' do + + .has-many-selector + + %p{ :style => form.object.send(field._alias.to_sym).empty? ? '' : 'display: none' } + = t('.empty') + + %ul + + %script{ :type => 'text/x-mustache-template', :name => 'template', :'data-base-input-name' => "content[#{field._alias.to_sym}]" } + %li{ :class => "item {{behaviour_flag}}" } + %span.handle + = image_tag 'admin/form/icons/drag.png' + + {{^if_template}} + %input{ :name => '{{base_name}}[]', :value => '{{{id}}}', :type => 'hidden', :'data-field' => 'id' } + {{/if_template}} + + %strong {{label}} + + {{#if_template}} + = select_tag 'label', '' + {{/if_template}} + + %span.actions + = link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove' + %button{ :class => 'button light mini add', :type => 'button' } + %span!= t('admin.buttons.new_item') + + %script{ :type => 'text/javascript', :name => 'data' } + != collection_to_js(options_for_has_many(field), :taken_ids => form.object.send(field._alias.to_sym).ids) + = render '/admin/custom_fields/category_tmpl' \ No newline at end of file diff --git a/app/views/admin/custom_fields/_edit_field.html.haml b/app/views/admin/custom_fields/_edit_field.html.haml index 48cfd42c..7884f219 100644 --- a/app/views/admin/custom_fields/_edit_field.html.haml +++ b/app/views/admin/custom_fields/_edit_field.html.haml @@ -8,6 +8,7 @@ = g.input :_alias = g.input :hint = g.input :text_formatting, :as => 'select', :collection => options_for_text_formatting, :include_blank => false, :wrapper_html => { :style => 'display: none' } + = g.input :target, :as => 'select', :collection => options_for_association_target, :include_blank => false, :wrapper_html => { :style => 'display: none' } .popup-actions %p diff --git a/app/views/admin/custom_fields/_index.html.haml b/app/views/admin/custom_fields/_index.html.haml index 36dbe998..c7c60283 100644 --- a/app/views/admin/custom_fields/_index.html.haml +++ b/app/views/admin/custom_fields/_index.html.haml @@ -23,6 +23,8 @@ %input{ :name => '{{base_name}}[text_formatting]', :value => '{{{text_formatting}}}', :type => 'hidden', :'data-field' => 'text_formatting' } + %input{ :name => '{{base_name}}[target]', :value => '{{{target}}}', :type => 'hidden', :'data-field' => 'target' } + %input{ :name => '{{base_name}}[label]', :value => '{{{label}}}', :type => 'text', :'data-field' => 'label' } — diff --git a/config/assets.yml b/config/assets.yml index c42bd1d3..d2943364 100644 --- a/config/assets.yml +++ b/config/assets.yml @@ -34,6 +34,7 @@ javascripts: - public/javascripts/admin/plugins/fancybox.js - public/javascripts/admin/plugins/mustache.js - public/javascripts/admin/custom_fields/category.js + - public/javascripts/admin/custom_fields/has_many.js asset_collections: - public/javascripts/admin/plugins/fancybox.js - public/javascripts/admin/plugins/mustache.js diff --git a/public/javascripts/admin/custom_fields.js b/public/javascripts/admin/custom_fields.js index 0b7715b2..fd9e4b64 100644 --- a/public/javascripts/admin/custom_fields.js +++ b/public/javascripts/admin/custom_fields.js @@ -50,7 +50,7 @@ $(document).ready(function() { // edit domField.find('a.edit').click(function(e) { var link = $(this); - var attributes = ['_alias', 'hint', 'text_formatting']; + var attributes = ['_alias', 'hint', 'text_formatting', 'target']; $.fancybox({ titleShow: false, @@ -76,6 +76,8 @@ $(document).ready(function() { domBoxAttrVal(name, val); }); if (domFieldVal(domField, 'kind').toLowerCase() == 'text') domBoxAttr('text_formatting').parents('li').show(); + if (domFieldVal(domField, 'kind').toLowerCase() == 'has_one' || + domFieldVal(domField, 'kind').toLowerCase() == 'has_many') domBoxAttr('target').parents('li').show(); } }); e.preventDefault(); e.stopPropagation(); @@ -200,161 +202,5 @@ $(document).ready(function() { } } - setup(); // <- let's the show begin -}); - -// $(document).ready(function() { -// -// $('fieldset.fields').parents('form').submit(function() { -// $('fieldset.fields li.template input, fieldset.fields li.template select').attr('disabled', 'disabled'); -// }); -// -// var defaultValue = $('fieldset.fields li.template input[type=text]').val(); -// var selectOnChange = function(select) { -// select.hide(); -// select.prev() -// .show() -// .html(select[0].options[select[0].options.selectedIndex].text); -// } -// -// var refreshPosition = function() { -// jQuery.each($('fieldset.fields li.added input.position'), function(index) { -// $(this).val(index); -// }); -// } -// -// /* __ fields ___ */ -// $('fieldset.fields li.added select').each(function() { -// var select = $(this) -// .hover(function() { -// clearTimeout(select.attr('timer')); -// }, function() { -// select.attr('timer', setTimeout(function() { -// select.hide(); -// select.prev().show(); -// }, 1000)); -// }) -// .change(function() { selectOnChange(select); }); -// -// select.prev().click(function() { -// $(this).hide(); -// select.show(); -// }); -// }); -// -// $('fieldset.fields li.template input[type=text]').focus(function() { -// if ($(this).hasClass('void') && $(this).parents('li').hasClass('template')) -// $(this).val('').removeClass('void'); -// }); -// -// $('fieldset.fields li.template button').click(function() { -// var lastRow = $(this).parents('li.template'); -// -// var label = lastRow.find('input.label').val().trim(); -// if (label == '' || label == defaultValue) return false; -// -// 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)); -// }); -// -// var select = newRow.find('select') -// .val(lastRow.find('select').val()) -// .change(function() { selectOnChange(select); }) -// .hover(function() { -// clearTimeout(select.attr('timer')); -// }, function() { -// select.attr('timer', setTimeout(function() { -// select.hide(); -// select.prev().show(); -// }, 1000)); -// }); -// select.prev() -// .html(select[0].options[select[0].options.selectedIndex].text) -// .click(function() { -// $(this).hide(); -// select.show(); -// }); -// -// // then "reset" the form -// lastRow.find('input.label').val(defaultValue).addClass('void'); -// -// // warn the sortable widget about the new row -// $("fieldset.fields ol").sortable('refresh'); -// -// refreshPosition(); -// }); -// -// $('fieldset.fields 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(); -// }); -// -// // sortable list -// $("fieldset.fields ol").sortable({ -// handle: 'span.handle', -// items: 'li:not(.template)', -// axis: 'y', -// update: refreshPosition -// }); -// -// // edit in depth custom field -// $('fieldset.fields li.item span.actions a.edit').click(function() { -// var link = $(this); -// $.fancybox({ -// titleShow: false, -// content: $(link.attr('href')).parent().html(), -// onComplete: function() { -// $('#fancybox-wrap form').submit(function(e) { -// $.fancybox.close(); -// e.preventDefault(); -// e.stopPropagation(); -// }); -// -// var parent = link.parent(); -// -// if (parent.prevAll('select').val() == 'Text') { -// var formatting = parent.prevAll('.text-formatting').val(); -// $('#fancybox-wrap #custom_fields_field_text_formatting').val(formatting); -// $('#fancybox-wrap #custom_fields_field_text_formatting_input').show(); -// } else { -// $('#fancybox-wrap #custom_fields_field_text_formatting_input').hide(); -// } -// -// var alias = parent.prevAll('.alias').val().trim(); -// if (alias == '') alias = makeSlug(link.parent().prevAll('.label').val()); -// $('#fancybox-wrap #custom_fields_field__alias').val(alias); -// -// var hint = parent.prevAll('.hint').val(); -// $('#fancybox-wrap #custom_fields_field_hint').val(hint); -// }, -// onCleanup: function() { -// var parent = link.parent(); -// -// var alias = $('#fancybox-wrap #custom_fields_field__alias').val().trim(); -// if (alias != '') parent.prevAll('.alias').val(alias); -// var hint = $('#fancybox-wrap #custom_fields_field_hint').val().trim(); -// if (hint != '') parent.prevAll('.hint').val(hint); -// var formatting = $('#fancybox-wrap #custom_fields_field_text_formatting').val(); -// parent.prevAll('.text-formatting').val(formatting); -// } -// }) -// }); -// }); + setup(); // <- let the show begin +}); \ No newline at end of file diff --git a/public/javascripts/admin/custom_fields/has_many.js b/public/javascripts/admin/custom_fields/has_many.js new file mode 100644 index 00000000..f84ab114 --- /dev/null +++ b/public/javascripts/admin/custom_fields/has_many.js @@ -0,0 +1,155 @@ +$(document).ready(function() { + // add/remove/sort items in a has_many relationship + $('.has-many-selector').hasManySelector(); +}); + +(function($){ + $.fn.hasManySelector = function(options) { + + var populateSelect = function(context) { + context.select.find('option').remove(); + + for (var i = 0; i < context.data.collection.length; i++) { + var obj = context.data.collection[i]; + if ($.inArray(obj[1], context.data.taken_ids) == -1) + context.select.append(new Option(obj[0], obj[1], true, true)); + } + + if (context.select.find('option').size() == 0) + context.list.find('li.template').hide(); + else + context.list.find('li.template').show(); + } + + var addId = function(context, id) { + context.data.taken_ids.push(id); + + populateSelect(context); + + if (context.data.taken_ids.length > 0) { + context.empty.hide(); + context.list.next('input[type=hidden]').remove(); + } + + if (context.data.taken_ids.length == context.data.collection.length) + context.sep.hide(); + } + + var removeId = function(context, id) { + context.data.taken_ids = jQuery.grep(context.data.taken_ids, function(value) { + return value != id; + }); + + populateSelect(context); + + if (context.data.taken_ids.length == 0) { + context.empty.show(); + context.list.after(''); + } + + context.sep.show(); + } + + var registerElementEvents = function(context, data, domElement) { + // remove + domElement.find('a.remove').click(function(e) { + domElement.remove(); + + removeId(context, data.id); + + context.list.sortable('refresh'); + + e.preventDefault(); e.stopPropagation(); + }); + } + + var registerElementTemplateEvents = function(context, domElement) { + // bind the "Add field" button + domElement.find('button').click(function(e) { + var newElement = { + id: context.select.val(), + label: context.select.find('option:selected').text() + }; + + addId(context, newElement.id); + + addElement(context, newElement, { refreshPosition: true }); + + context.list.sortable('refresh'); + + e.preventDefault(); e.stopPropagation(); + }); + } + + /* ___ Add an element into the list ___ */ + var addElement = function(context, data, options) { + options = $.extend({ + 'is_template': false, + 'refreshPosition': false + }, options); + + data = $.extend({ + behaviour_flag: function() { return options.is_template ? 'template' : 'added' }, + base_name: function() { return options.is_template ? '' : context.baseInputName }, + if_template: function() { return options.is_template } + }, data); + + var html = Mustache.to_html(context.template, data); + + var domElement = null; + + if (options.is_template) { + domElement = context.list.append('