From d0ff08c9a11ea5240dfea61f27dca5c46ce97da4 Mon Sep 17 00:00:00 2001 From: dinedine Date: Thu, 10 Jun 2010 15:30:32 +0200 Subject: [PATCH] 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 --- .../admin/api_contents_controller.rb | 29 ++++++ .../admin/custom_fields_controller.rb | 33 +++++++ .../custom_fields/edit_category.html.haml | 43 +++++++++ .../admin/shared/_custom_fields.html.haml.old | 59 ++++++++++++ public/images/admin/form/big_item-popup.png | Bin 0 -> 1074 bytes public/images/admin/form/footer-popup.png | Bin 0 -> 1039 bytes public/images/admin/form/header-popup.png | Bin 0 -> 525 bytes public/images/admin/form/item-popup.png | Bin 0 -> 979 bytes .../admin/custom_fields/category.js | 91 ++++++++++++++++++ public/javascripts/admin/utils.js | 9 ++ .../integration/custom_fields_for_spec.rb | 28 ++++++ .../spec/integration/types/category_spec.rb | 26 +++++ 12 files changed, 318 insertions(+) create mode 100644 app/controllers/admin/api_contents_controller.rb create mode 100644 app/controllers/admin/custom_fields_controller.rb create mode 100644 app/views/admin/custom_fields/edit_category.html.haml create mode 100644 app/views/admin/shared/_custom_fields.html.haml.old create mode 100644 public/images/admin/form/big_item-popup.png create mode 100644 public/images/admin/form/footer-popup.png create mode 100644 public/images/admin/form/header-popup.png create mode 100644 public/images/admin/form/item-popup.png create mode 100644 public/javascripts/admin/custom_fields/category.js create mode 100644 public/javascripts/admin/utils.js create mode 100644 vendor/plugins/custom_fields/spec/integration/custom_fields_for_spec.rb create mode 100644 vendor/plugins/custom_fields/spec/integration/types/category_spec.rb 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 0000000000000000000000000000000000000000..329000fe63f1f6ce008d264de24143892b15a773 GIT binary patch literal 1074 zcmV-21kL-2P)EmO9h5@Sn~lf_i-@`vSMmT-5Jq8UbR|UxD(X6dC<+X>E{f|PS ziJ5k41%OLcjOjeJei_pq^Yz7kICp^(8y>SL=9!r5WDUUotz0hm=5o20WBXRj@$TT%y1lQuh>##oaLv{^JshQ&?)iPh%Rz3BZ+5Q&Tf8=95C9@ajdE zSQOX?L;m{t5CE>Y`uh51eSL+s7c8+Tu+_0VDl!17$;grQ_wU=+_4YYSEDG$QSe_LX z0M)3m@%n`w9i44wlvotl&{$p<5dhU}(xizm&VTr^v4c-y%VNff2Y_leY}l}d=bu}# zqN#cOK!4@q6qf$5{IqBQ$b!j}Cq6!5LQ8YyB$l4S;eTKNWI}Ci?Wnee3+AWOSf#`O zATy>+xp`(R*Q64=O&kDZNkcG2RAM)Y1Ar_UG2*IpGh$sTv612cAWQQ3{ME4x zPbD@~8~|jj#A;)y$%_Jj%yyX!0LW~Mi2wj41^`M70F)R2N(=y$7yu|S08nB8C@}y~ zVgR7T08nB8pu_+`i2;BT13-xZfD!|MODVD6#Q;E-luD)kN{RJ}1AvT`*wM7468ljc z0A$IrW54Z>rI<>rQyc(f$uEZvr32XURAQfr1Ar{qv}yDDSdQk(6z+g}I%Cl;r$HN|4_XVCyq z%}$;?*}Hhj@{eNMwRg|1fx8ojoH~s?DINf-S$q2zuXT6tFT}Qc;1E`M;f5P0eSG+E z-zy>lpc;L@bJzPzmp%1OYgY=%RiB{8NAd0NOMba+lwWZU6uP07*qoM6N<$f_PU1v;Y7A literal 0 HcmV?d00001 diff --git a/public/images/admin/form/footer-popup.png b/public/images/admin/form/footer-popup.png new file mode 100644 index 0000000000000000000000000000000000000000..278e8c17628fa9e257108c5f68a119871909eaa9 GIT binary patch literal 1039 zcmV+q1n~QbP)n-$0RRB&g#Z9AmH+?{>gT%Z z>i_@)08mU+MeXkO@A3BZ_4)Sq`t9%a{{H{@`uzF%{PXnr`uqI&`TO$o`1SVr|NsB% z?eq^14-gO#5fKp*5)u;=6BHB_6%`d078Vy57Z?~A85tQG8X6lL8yp-Q9UUDW9v&Yb zA0QwgAt50mA|fLrBP1jwB_$;$CMG8*CnzW=DJdx`Dk>{0D=aK5EiElBE-o)GFEB7L zF)=YRGBPtWGc+_bH8nLhHa0gmH#j&rIXO8xIyyT$J3Kr*Jv}`>K0ZG`KR`f0K|w)6 zLPA4BLqtSGMMXtMMn*?RM@UFWNl8gcN=i#hOH52mO-)TsPEJoxPf$=$QBhG+Qc_b> zQ&dz`RaI41R#sP6S6EnBSy@?HT3TCMTU=aRU0q#XUS3~cUtnNhVPRonVq#-sV`OAx zWo2b%W@cw+XJ}|>X=!O{YHDk1Yiw+6ZEbCCZf7mzbEC znVFfInwp!No1C1Sot>SYo}QndpP-Ll?si~=| zs;aB2tE{Z7t*x!DuCA}IuduMNv9YnTva++Yv$V9dwY9ajwzjvox45{txw*Nzy1Ki& zyS%)-y}iA@zP`V|zreu2!NI}8!otJD!^FhI#l^+O#>U6T$H>UY$;rve%F4^j%goHo z&CSiu&d$%z&(P4&(b3V;($dq@)6~?|)z#J3*4Ee8*Vx$D+1c6J+S=RO+uYpT-QC^Z z-rnEe-{9cj;o;%p;^O1ulq(=H}<;=jiC@>FMd}>gwz3>+J08?d|RE?(XmJ z@9^;O@$vEU^78ZZ^Yrxe_4W1k_V)Mp_xSku`T6_cAPh}|G4=Gg0>^{a2$bzA<4ReCyD~svPtV2wj#lj z(i#bttePXil38TXT8>#nj|M|Jf+-&Cmni{N002ov JPDHLkV1g_z3=;qV literal 0 HcmV?d00001 diff --git a/public/images/admin/form/header-popup.png b/public/images/admin/form/header-popup.png new file mode 100644 index 0000000000000000000000000000000000000000..84719ea5f5ee5353005a851795ba2f451d58c5bd GIT binary patch literal 525 zcmV+o0`mQdP)m(VHgMCFYO`F$*EJs zq2vMtFF+6qnS{FNEp#ZZ9XbjYI(G0DbZODaN$?K50C5mnt!an;0YQ+j?@3Y-O{_KN zK$Yi#A1BG-EbsE;Js~HJ?zdm*mS!WJ$Xw)cWO{G}fQRfnvNt&HM7ATlx4E$Kmy&%F zc^P>fd1}r8(9?~)jjTmZN0#i#*Po-#%}3rxrpyumhB}PAifj!#`DnyNtC39w3jjBo z8uaDr&`tJB_u3}A9$7Ru0Qe^xk)_KY6e;D)?^hHo0NhF0pZk$F7n|(y$&Wv;Uqn8b z5de&3A@Z?TvPb=rZAK0vEwcfDv3!a=i<}iH_ih(2D_8)iL~GEi?;4+vzn2e`I7)s8 z3jkFqe@8o6PxoHjnP`PH2vnc>T9m?CqrT_r-l&m2DKrJPE|NxTYv!ouBKa|=pGAG P00000NkvXXu0mjfjjq|% literal 0 HcmV?d00001 diff --git a/public/images/admin/form/item-popup.png b/public/images/admin/form/item-popup.png new file mode 100644 index 0000000000000000000000000000000000000000..cd2d77311918a336d5e952d8c9b3ff70c49b2b4f GIT binary patch literal 979 zcmV;^11$WBP)D1J6XFdPvK+VctJqNxYczFJtZC*S#Kb~=R)Dn|YMh)fltA@dsa-?#lmPy&9GW$9J z0KY3BRnymRNmWSQ8SaO*pM+Sn)HbO-QWKap0N`H>27^9L(++k#Pb5MuN>|OOU$k_xq0wJH#Zw&X4N- z`Vats5f>X9TiDv_zxvY4N{Iwe<4G1w&D3!o?003qd6&2;&x3{=B zDLFNiU%G5z>Icia84Uoy3Z_q=wlOU&B{{r_si$!8J1_u%B}7C-#BJTOIbUsK;Sd7= zz%nv2W-OF8R)yFc#sL7Z5~tIto|!mKh1gWa0RXU)n3&P(W<tm!v z>x=>bU{N*|Vy(;p0AMACVYG)fGN~7g0{~zp9UY&Vqy*E;<0Kn{edU{&sFUVQv^Z8tQQgZ5NxmM0t0036- z_;K9@39wE%e(Ze;u&$Q}0)e-T1^{4Y-QC^39R)=f<>-F>s=)|_Sl>3bo$&ww%&el~ z=24HQ$uCDwXbB6yFnLP)rIwb~!;A<3U`9{t8_w-4+;vxu&(#(-AjFhene&SLe*aZQ z1pqJ;uh)A!H#hH$92+ITeBtZgJa%ek#@tnIx92P)0|1z116#OgX{j9FOMt!X|Jsnx zPF%cX`DRy5?T)UluJ?=&05B5NO&r&+-ze?3fjt@gp6@;Ycy{Kj69olD*^eI89as0{ zGfn`&|DZCbva' + list[i].name + ''; + } + 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