Commit 6c70738c86eee708f050eec365df833a47090abb
1 parent
81fab8d7
Exists in
master
and in
29 other branches
ActionItem498: add ajax power to category selector (not finished yet)
git-svn-id: https://svn.colivre.coop.br/svn/noosfero/trunk@2221 3f533792-8f58-4932-b0fe-aaf55b0a4547
Showing
9 changed files
with
168 additions
and
35 deletions
Show diff stats
app/controllers/my_profile/cms_controller.rb
... | ... | @@ -115,6 +115,12 @@ class CmsController < MyProfileController |
115 | 115 | render :action => params[:action], :layout => false |
116 | 116 | end |
117 | 117 | |
118 | + def update_categories | |
119 | + @current_category = Category.find(params[:category_id]) | |
120 | + @categories = @current_category.children | |
121 | + render :partial => 'shared/select_categories', :locals => {:object_name => 'article'}, :layout => false | |
122 | + end | |
123 | + | |
118 | 124 | protected |
119 | 125 | |
120 | 126 | def redirect_back | ... | ... |
app/controllers/my_profile/profile_editor_controller.rb
... | ... | @@ -38,4 +38,10 @@ class ProfileEditorController < MyProfileController |
38 | 38 | end |
39 | 39 | end |
40 | 40 | |
41 | + def update_categories | |
42 | + @current_category = Category.find(params[:category_id]) | |
43 | + @categories = @current_category.children | |
44 | + render :partial => 'shared/select_categories', :locals => {:object_name => 'profile_data'}, :layout => false | |
45 | + end | |
46 | + | |
41 | 47 | end | ... | ... |
app/helpers/application_helper.rb
... | ... | @@ -216,11 +216,29 @@ module ApplicationHelper |
216 | 216 | end |
217 | 217 | |
218 | 218 | def button_to_function(type, label, js_code, html_options = {}) |
219 | - html_options[:class] = "" unless html_options[:class] | |
220 | - html_options[:class] << " button #{type}" | |
219 | + html_options[:class] = "button with-text" unless html_options[:class] | |
220 | + html_options[:class] << " icon-#{type}" | |
221 | 221 | link_to_function(label, js_code, html_options) |
222 | 222 | end |
223 | 223 | |
224 | + def button_to_function(type, label, js_code, html_options = {}, &block) | |
225 | + html_options[:class] = "button with-text" unless html_options[:class] | |
226 | + html_options[:class] << " icon-#{type}" | |
227 | + link_to_function(label, js_code, html_options, &block) | |
228 | + end | |
229 | + | |
230 | + def button_to_function_without_text(type, label, js_code, html_options = {}) | |
231 | + html_options[:class] = "" unless html_options[:class] | |
232 | + html_options[:class] << " button icon-#{type}" | |
233 | + link_to_function(content_tag('span', label), js_code, html_options) | |
234 | + end | |
235 | + | |
236 | + def button_to_function_without_text(type, label, js_code, html_options = {}, &block) | |
237 | + html_options[:class] = "" unless html_options[:class] | |
238 | + html_options[:class] << " button icon-#{type}" | |
239 | + link_to_function(content_tag('span', label), js_code, html_options, &block) | |
240 | + end | |
241 | + | |
224 | 242 | def icon(icon_name, html_options = {}) |
225 | 243 | the_class = "button #{icon_name}" |
226 | 244 | if html_options.has_key?(:class) |
... | ... | @@ -420,40 +438,29 @@ module ApplicationHelper |
420 | 438 | |
421 | 439 | object = instance_variable_get("@#{object_name}") |
422 | 440 | |
423 | - result = content_tag 'h'+title_size.to_s(), title | |
424 | - result << javascript_tag( 'function open_close_cat( link ) { | |
425 | - var div = link.parentNode.getElementsByTagName("div")[0]; | |
426 | - var end = function(){ | |
427 | - if ( div.style.display == "none" ) { | |
428 | - this.link.className="button icon-button icon-down" | |
429 | - } else { | |
430 | - this.link.className="button icon-button icon-up-red" | |
431 | - } | |
432 | - } | |
433 | - Effect.toggle( div, "slide", { link:link, div:div, afterFinish:end } ) | |
434 | - }') | |
435 | - environment.top_level_categories.select{|i| !i.children.empty?}.each do |toplevel| | |
436 | - next unless object.accept_category?(toplevel) | |
437 | - # FIXME | |
438 | - ([toplevel] + toplevel.children_for_menu).each do |cat| | |
439 | - if cat.top_level? | |
440 | - result << '<div class="categorie_box">' | |
441 | - result << icon_button( :down, _('open'), '#', :onclick => 'open_close_cat(this); return false' ) | |
442 | - result << content_tag('h5', toplevel.name) | |
443 | - result << '<div style="display:none"><ul class="categories">' | |
444 | - else | |
445 | - checkbox_id = "#{object_name}_#{cat.full_name.downcase.gsub(/\s+|\//, '_')}" | |
446 | - result << content_tag('li', labelled_check_box( | |
447 | - cat.full_name_without_leading(1, " → "), | |
448 | - "#{object_name}[category_ids][]", cat.id, | |
449 | - object.category_ids.include?(cat.id), :id => checkbox_id, | |
450 | - :onchange => 'this.parentNode.className=(this.checked?"cat_checked":"")' ), | |
451 | - :class => ( object.category_ids.include?(cat.id) ? 'cat_checked' : '' ) ) + "\n" | |
452 | - end | |
453 | - end | |
454 | - result << '</ul></div></div>' | |
441 | + result = content_tag("h#{title_size}", title) + | |
442 | + content_tag('ul', object.categories.map{|i| content_tag('li', i.full_name + hidden_field_tag("#{object_name}[category_ids][]", i.id) + button_to_function_without_text(:cancel, _('Remove'), nil, :id => "remove-selected-category-#{i.id}-button"){|page| page["selected-category-#{i.id}"].remove}, :id => "selected-category-#{i.id}")}, :id => 'selected-categories') + | |
443 | + content_tag('div', nil, :id => 'select-categories') + | |
444 | + button_to_function(:add, _('Add category'), nil, :id => 'add-category-button') do |page| | |
445 | + page['add-category-button'].hide | |
446 | + page['select-categories'].replace_html :partial => 'shared/select_categories', :locals => {:object_name => object_name} | |
455 | 447 | end |
456 | 448 | |
449 | + #environment.top_level_categories.select{|i| !i.children.empty?}.each do |toplevel| | |
450 | + # next unless object.accept_category?(toplevel) | |
451 | + # ([toplevel] + toplevel.children_for_menu).each do |cat| | |
452 | + # if cat.top_level? | |
453 | + # result << '<div class="categorie_box">' | |
454 | + # result << icon_button( :down, _('open'), '#', :onclick => remote_function(:update => "categories_#{cat.id}", :url => { :action => :update_categories, :id => cat, :object_name => object_name, :object_id => object.id})) | |
455 | + # result << content_tag('h5', toplevel.name) | |
456 | + # result << "<div id='categories_#{cat.id}'>" | |
457 | + # else | |
458 | + # ... | |
459 | + # end | |
460 | + # end | |
461 | + # result << '</div></div>' | |
462 | + #end | |
463 | + | |
457 | 464 | content_tag('div', result) |
458 | 465 | end |
459 | 466 | ... | ... |
app/views/profile_editor/edit.rhtml
... | ... | @@ -38,7 +38,6 @@ |
38 | 38 | |
39 | 39 | <%= select_categories(:profile_data, _('Select the categories of your interest'), 1) %> |
40 | 40 | |
41 | - | |
42 | 41 | <% button_bar do %> |
43 | 42 | <%= submit_button('save', _('Save'), :cancel => {:action => 'index'}) %> |
44 | 43 | <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %> | ... | ... |
... | ... | @@ -0,0 +1,40 @@ |
1 | +<% if !@current_category.nil? %> | |
2 | + <% | |
3 | + categories = [@current_category] | |
4 | + categories.push(@current_category) while @current_category = @current_category.parent | |
5 | + %> | |
6 | + <% if categories.size > 0 %> | |
7 | + <%= categories.compact.reverse.map{|i| | |
8 | + link_to_remote(i.name, | |
9 | + :update => "select-categories", | |
10 | + :url => { :action => 'update_categories', :category_id => i.id, :loaded => visual_effect(:highlight, "select-categories") }, | |
11 | + :class => 'select-current-category-link')}.join(' → ') | |
12 | + %> | |
13 | + <strong> | |
14 | + <%= button_to_function_without_text(:save, _('Save'), nil, :id => 'save-category-button') do |page| | |
15 | + page.replace_html 'select-categories', '' | |
16 | + page['add-category-button'].show | |
17 | + page.insert_html :bottom, 'selected-categories', content_tag('li', categories.first.full_name + | |
18 | + hidden_field_tag("#{object_name}[category_ids][]", categories.first.id) + | |
19 | + button_to_function_without_text(:cancel, _('Remove'), nil, :id => "remove-selected-category-#{categories.first.id}-button") {|page| page["selected-category-#{categories.first.id}"].remove}, :id => "selected-category-#{categories.first.id}") | |
20 | + end %> | |
21 | + <%= button_to_function_without_text(:cancel, _('Cancel'), nil, :id => 'cancel-category-button') do |page| | |
22 | + page.replace_html 'select-categories', '' | |
23 | + page['add-category-button'].show | |
24 | + end %> | |
25 | + </strong> | |
26 | + <% end %> | |
27 | +<br/> | |
28 | +<% end %> | |
29 | +<% if @categories.nil? | |
30 | + @categories = environment.top_level_categories.select{|i| !i.children.empty?} | |
31 | +end %> | |
32 | +<% for category in @categories.each do %> | |
33 | + <%= link_to_remote category.name, { | |
34 | + :update => "select-categories", | |
35 | + :url => { :action => "update_categories", :category_id => category.id }, | |
36 | + :loaded => visual_effect(:highlight, "select-categories") }, | |
37 | + :class => 'select-subcategory-link' | |
38 | + %> | |
39 | +<% end %> | |
40 | + | ... | ... |
test/functional/cms_controller_test.rb
... | ... | @@ -286,6 +286,19 @@ class CmsControllerTest < Test::Unit::TestCase |
286 | 286 | assert_not_includes saved.categories, c2 |
287 | 287 | assert_includes saved.categories, c3 |
288 | 288 | end |
289 | + | |
290 | + should 'not associate articles with category twice' do | |
291 | + env = Environment.default | |
292 | + c1 = env.categories.build(:name => "Test category 1"); c1.save! | |
293 | + c2 = env.categories.build(:name => "Test category 2"); c2.save! | |
294 | + c3 = env.categories.build(:name => "Test Category 3"); c3.save! | |
295 | + | |
296 | + # post is in c1, c3 and c3 | |
297 | + post :new, :type => TextileArticle.name, :profile => profile.identifier, :article => { :name => 'adding-categories-test', :category_ids => [ c1.id, c3.id, c3.id ] } | |
298 | + | |
299 | + saved = profile.articles.find_by_name('adding-categories-test') | |
300 | + assert_equal [c1, c3, c3], saved.categories | |
301 | + end | |
289 | 302 | |
290 | 303 | should 'filter html from textile article name' do |
291 | 304 | post :new, :type => 'TextileArticle', :profile => profile.identifier, :article => { :name => 'a <strong>test</strong> article', :body => 'the text of the article ...' } |
... | ... | @@ -480,4 +493,15 @@ class CmsControllerTest < Test::Unit::TestCase |
480 | 493 | assert_includes @controller.available_article_types, EnterpriseHomepage |
481 | 494 | end |
482 | 495 | |
496 | + should 'update categories' do | |
497 | + env = Environment.default | |
498 | + top = env.categories.create!(:display_in_menu => true, :name => 'Top-Level category') | |
499 | + c1 = env.categories.create!(:display_in_menu => true, :name => "Test category 1", :parent_id => top.id) | |
500 | + c2 = env.categories.create!(:display_in_menu => true, :name => "Test category 2", :parent_id => top.id) | |
501 | + get :update_categories, :profile => profile.identifier, :category_id => top.id | |
502 | + assert_template 'shared/_select_categories' | |
503 | + assert_equal top, assigns(:current_category) | |
504 | + assert_equal [c1, c2], assigns(:categories) | |
505 | + end | |
506 | + | |
483 | 507 | end | ... | ... |
test/functional/profile_editor_controller_test.rb
... | ... | @@ -12,7 +12,9 @@ class ProfileEditorControllerTest < Test::Unit::TestCase |
12 | 12 | @request = ActionController::TestRequest.new |
13 | 13 | @response = ActionController::TestResponse.new |
14 | 14 | login_as('ze') |
15 | + @profile = Person['ze'] | |
15 | 16 | end |
17 | + attr_reader :profile | |
16 | 18 | |
17 | 19 | def test_local_files_reference |
18 | 20 | assert_local_files_reference :get, :index, :profile => 'ze' |
... | ... | @@ -432,5 +434,16 @@ class ProfileEditorControllerTest < Test::Unit::TestCase |
432 | 434 | get :index, :profile => 'testuser' |
433 | 435 | assert_tag :tag => 'a', :content => 'Register a new Enterprise' |
434 | 436 | end |
437 | + | |
438 | + should 'update categories' do | |
439 | + env = Environment.default | |
440 | + top = env.categories.create!(:display_in_menu => true, :name => 'Top-Level category') | |
441 | + c1 = env.categories.create!(:display_in_menu => true, :name => "Test category 1", :parent_id => top.id) | |
442 | + c2 = env.categories.create!(:display_in_menu => true, :name => "Test category 2", :parent_id => top.id) | |
443 | + get :update_categories, :profile => profile.identifier, :category_id => top.id | |
444 | + assert_template 'shared/_select_categories' | |
445 | + assert_equal top, assigns(:current_category) | |
446 | + assert_equal [c1, c2], assigns(:categories) | |
447 | + end | |
435 | 448 | |
436 | 449 | end | ... | ... |
... | ... | @@ -0,0 +1,29 @@ |
1 | +setup :fixtures => :all | |
2 | +include_partial 'login' | |
3 | + | |
4 | +Category.destroy_all | |
5 | +env = Environment.default | |
6 | +top = env.categories.create!(:display_in_menu => true, :name => 'Top-Level category') | |
7 | +c1 = env.categories.create!(:display_in_menu => true, :name => "Test category 1", :parent_id => top.id) | |
8 | +c2 = env.categories.create!(:display_in_menu => true, :name => "Test category 2", :parent_id => top.id) | |
9 | +c3 = env.categories.create!(:display_in_menu => true, :name => "Test Category 3", :parent_id => top.id) | |
10 | + | |
11 | +click_and_wait 'link=Manage Content' | |
12 | +click 'link=New article' | |
13 | +click_and_wait 'link=Text article with Textile markup language' | |
14 | +click 'link=Add category' | |
15 | + | |
16 | +assert_visible 'css=div[id=select-categories]' | |
17 | +assert_visible 'css=a[class=select-subcategory-link]' | |
18 | +assert_text 'css=a[class=select-subcategory-link]', 'Top-Level category' | |
19 | + | |
20 | +click 'link=Top-Level category' | |
21 | + | |
22 | +assert_visible 'css=a[class=select-subcategory-link]' | |
23 | +assert_text 'css=a[class=select-subcategory-link]', 'Test category 1' | |
24 | +click 'link=Test category 1' | |
25 | +assert_not_visible 'css=div[id=select-categories]' | |
26 | + | |
27 | +#assert_visible 'css=a[class=select-subcategory-link]' | |
28 | + | |
29 | +# vim: ft=ruby | ... | ... |
test/unit/article_test.rb
... | ... | @@ -349,7 +349,16 @@ class ArticleTest < Test::Unit::TestCase |
349 | 349 | a = p.articles.create!(:name => 'test', :category_ids => [c1.id, c2.id]) |
350 | 350 | |
351 | 351 | assert_equivalent [c1, c2], a.categories(true) |
352 | + end | |
352 | 353 | |
354 | + should 'not add a category twice to article' do | |
355 | + c1 = Category.create!(:environment => Environment.default, :name => 'c1') | |
356 | + c2 = c1.children.create!(:environment => Environment.default, :name => 'c2') | |
357 | + c3 = c2.children.create!(:environment => Environment.default, :name => 'c3') | |
358 | + owner = create_user('testuser').person | |
359 | + art = owner.articles.create!(:name => 'ytest') | |
360 | + art.category_ids = [c2,c3,c3].map(&:id) | |
361 | + assert_equal [c2, c3], art.categories(true) | |
353 | 362 | end |
354 | 363 | |
355 | 364 | should 'not accept Product category as category' do | ... | ... |