Commit 6c70738c86eee708f050eec365df833a47090abb
1 parent
81fab8d7
Exists in
master
and in
28 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 | ... | ... |