Commit b2833502d0184d05a577d9544379302412dc38f8
1 parent
7707a13c
Exists in
master
and in
29 other branches
ActionItem158: a better CMS
git-svn-id: https://svn.colivre.coop.br/svn/noosfero/trunk@1790 3f533792-8f58-4932-b0fe-aaf55b0a4547
Showing
8 changed files
with
170 additions
and
63 deletions
Show diff stats
app/controllers/my_profile/cms_controller.rb
@@ -19,12 +19,14 @@ class CmsController < MyProfileController | @@ -19,12 +19,14 @@ class CmsController < MyProfileController | ||
19 | 19 | ||
20 | def view | 20 | def view |
21 | @article = profile.articles.find(params[:id]) | 21 | @article = profile.articles.find(params[:id]) |
22 | - @subitems = @article.children | 22 | + @subitems = @article.children.reject {|item| item.folder? } |
23 | + @folders = @article.children.select {|item| item.folder? } | ||
23 | end | 24 | end |
24 | 25 | ||
25 | def index | 26 | def index |
26 | @article = nil | 27 | @article = nil |
27 | - @subitems = profile.top_level_articles | 28 | + @subitems = profile.top_level_articles.reject {|item| item.folder? } |
29 | + @folders = profile.top_level_articles.select {|item| item.folder?} | ||
28 | render :action => 'view' | 30 | render :action => 'view' |
29 | end | 31 | end |
30 | 32 | ||
@@ -35,7 +37,7 @@ class CmsController < MyProfileController | @@ -35,7 +37,7 @@ class CmsController < MyProfileController | ||
35 | if request.post? | 37 | if request.post? |
36 | @article.last_changed_by = user | 38 | @article.last_changed_by = user |
37 | if @article.update_attributes(params[:article]) | 39 | if @article.update_attributes(params[:article]) |
38 | - redirect_to :action => 'view', :id => @article.id | 40 | + redirect_back |
39 | return | 41 | return |
40 | end | 42 | end |
41 | end | 43 | end |
@@ -78,7 +80,7 @@ class CmsController < MyProfileController | @@ -78,7 +80,7 @@ class CmsController < MyProfileController | ||
78 | @article.last_changed_by = user | 80 | @article.last_changed_by = user |
79 | if request.post? | 81 | if request.post? |
80 | if @article.save | 82 | if @article.save |
81 | - redirect_to :action => 'view', :id => @article.id | 83 | + redirect_back |
82 | return | 84 | return |
83 | end | 85 | end |
84 | end | 86 | end |
@@ -102,5 +104,15 @@ class CmsController < MyProfileController | @@ -102,5 +104,15 @@ class CmsController < MyProfileController | ||
102 | redirect_to :action => (@article.parent ? 'view' : 'index'), :id => @article.parent | 104 | redirect_to :action => (@article.parent ? 'view' : 'index'), :id => @article.parent |
103 | end | 105 | end |
104 | 106 | ||
107 | + protected | ||
108 | + | ||
109 | + def redirect_back | ||
110 | + if @article.parent | ||
111 | + redirect_to :action => 'view', :id => @article.parent | ||
112 | + else | ||
113 | + redirect_to :action => 'index' | ||
114 | + end | ||
115 | + end | ||
116 | + | ||
105 | end | 117 | end |
106 | 118 |
app/models/article.rb
@@ -112,6 +112,10 @@ class Article < ActiveRecord::Base | @@ -112,6 +112,10 @@ class Article < ActiveRecord::Base | ||
112 | true | 112 | true |
113 | end | 113 | end |
114 | 114 | ||
115 | + def folder? | ||
116 | + false | ||
117 | + end | ||
118 | + | ||
115 | def self.find_by_initial(initial) | 119 | def self.find_by_initial(initial) |
116 | self.find(:all, :order => 'articles.name', :conditions => [ 'articles.name like (?) or articles.name like (?)', initial + '%', initial.upcase + '%']) | 120 | self.find(:all, :order => 'articles.name', :conditions => [ 'articles.name like (?) or articles.name like (?)', initial + '%', initial.upcase + '%']) |
117 | end | 121 | end |
app/models/folder.rb
@@ -20,4 +20,8 @@ class Folder < Article | @@ -20,4 +20,8 @@ class Folder < Article | ||
20 | content_tag('ul', children.map { |child| content_tag('li', link_to(child.name, child.url)) }, :class => 'folder-listing') | 20 | content_tag('ul', children.map { |child| content_tag('li', link_to(child.name, child.url)) }, :class => 'folder-listing') |
21 | end | 21 | end |
22 | 22 | ||
23 | + def folder? | ||
24 | + true | ||
25 | + end | ||
26 | + | ||
23 | end | 27 | end |
app/views/cms/edit.rhtml
@@ -16,6 +16,11 @@ | @@ -16,6 +16,11 @@ | ||
16 | %> | 16 | %> |
17 | 17 | ||
18 | <% button_bar do %> | 18 | <% button_bar do %> |
19 | - <%= submit_button('save', _('Save'), :cancel => (@article.parent ? { :action => 'view', :id => @article.parent.id } : { :action => 'index' } )) %> | 19 | + <%= submit_button :save, _('Save') %> |
20 | + <% if @parent_id || @article.parent %> | ||
21 | + <%= button :cancel, _('Cancel'), :action => 'view', :id => @parent_id || @article.parent %> | ||
22 | + <% else %> | ||
23 | + <%= button :cancel, _('Cancel'), :action => 'index' %> | ||
24 | + <% end %> | ||
20 | <% end %> | 25 | <% end %> |
21 | <% end %> | 26 | <% end %> |
app/views/cms/view.rhtml
@@ -9,68 +9,59 @@ | @@ -9,68 +9,59 @@ | ||
9 | <%= icon('cms') %> | 9 | <%= icon('cms') %> |
10 | <%= _('Content management') %> | 10 | <%= _('Content management') %> |
11 | </h2> | 11 | </h2> |
12 | - | ||
13 | - <% button_bar(:style => 'margin-bottom: 1em;') do %> | ||
14 | - <%= lightbox_button('new', _('New article'), :action => 'new') %> | ||
15 | - <% end %> | ||
16 | - | ||
17 | <% end %> | 12 | <% end %> |
18 | 13 | ||
19 | -<%# subitem %> | ||
20 | -<% if !@subitems.empty? && @article %> | ||
21 | - <%= toggle_panel(_('Hide subitems'), _('Show subitems'), 'article-subitems') %> | 14 | +<% button_bar(:style => 'margin-bottom: 1em;') do %> |
15 | + <% parent_id = ((@article && @article.allow_children?) ? @article : nil) %> | ||
16 | + <%= button :add, _('New folder'), :action => 'new', :type => 'Folder', :parent_id => parent_id %> | ||
17 | + <%= lightbox_button('new', _('New article'), :action => 'new', :parent_id => parent_id) %> | ||
22 | <% end %> | 18 | <% end %> |
23 | - | ||
24 | -<div id='article-subitems'> | ||
25 | - <div class='file-manager-title'><%= @article ? _('Subitems') : _('Articles') %></div> | ||
26 | - <div class='file-manager-small'> | ||
27 | - <% unless @subitems.empty? %> | ||
28 | - <ul> | ||
29 | - <% @subitems.each do |item| %> | ||
30 | - <li> | ||
31 | - <%= file_manager_button(item.name, icon_for_article(item), :action => 'view', :id => item.id) %> | ||
32 | - </li> | ||
33 | - <% end %> | ||
34 | - </ul> | ||
35 | - <% end %> | ||
36 | 19 | ||
37 | - <% if @article %> | ||
38 | - <% button_bar(:class => 'file-manager-controls') do %> | ||
39 | - <% if @article.allow_children? %> | ||
40 | - <%= lightbox_button('new', _('New subitem'), :action => 'new', :parent_id => @article.id) %> | ||
41 | - <% end %> | ||
42 | - <%= button('up', _('Go up one level'), :action => (@article.parent ? 'view' : 'index'), :id => @article.parent) %> | ||
43 | - <% end %> | ||
44 | - <% end %> | ||
45 | - </div> | ||
46 | -</div> <!-- article-children --> | 20 | +<table width='100%'> |
47 | 21 | ||
48 | -<%# display the article content %> | ||
49 | -<div id='article-contents' style='clear: left;'> | ||
50 | - <% if @article %> | ||
51 | - <h2> | ||
52 | - <%= @article.name %> | ||
53 | - <%= image_tag(icon_for_article(@article)) %> | ||
54 | - </h2> | ||
55 | - <% button_bar(:id => 'article-controls') do %> | ||
56 | - | ||
57 | - <ul> | ||
58 | - <li> | ||
59 | - <%= _('"%{article}", last changed by %{author}') % { :article => @article.name, :author => (@article.last_changed_by ? @article.last_changed_by.name : _('Unknown User')) } %> | ||
60 | - </li> | ||
61 | - <li> | ||
62 | - <%= _('Public address of this article: %s') % link_to(url_for(@article.url), @article.url) %> | ||
63 | - </li> | ||
64 | - <li> | ||
65 | - <%= _('Tags:') %> <%= @article.tag_list %> | ||
66 | - </li> | ||
67 | - <%= _('Categories:') %> <%= @article.categories.map { |item| item.name }.join(', ') %> | ||
68 | - </ul> | 22 | + <%# folders %> |
23 | + <tr> | ||
24 | + <th colspan='2'> | ||
25 | + <%= _('Folders') %> | ||
26 | + </th> | ||
27 | + </tr> | ||
28 | + <% if @folders.empty? %> | ||
29 | + <tr><td colspan='2' align='center'><em><%= _('None') %></em></td></tr> | ||
30 | + <% end %> | ||
31 | + <% for folder in @folders %> | ||
32 | + <tr> | ||
33 | + <td> | ||
34 | + <%= image_tag(icon_for_article(folder)) %> | ||
35 | + <%= link_to folder.name, :action => 'view', :id => folder.id %> | ||
36 | + </td> | ||
37 | + <td> | ||
38 | + <%= link_to _('Properties'), :action => 'edit', :id => folder.id %> | ||
39 | + <%= link_to _('View'), folder.url %> | ||
40 | + </td> | ||
41 | + </tr> | ||
42 | + <% end %> | ||
69 | 43 | ||
70 | - <%= button('edit', _('Edit'), { :action => 'edit', :id => @article}) %> | ||
71 | - <%= button('home', _('Use as homepage'), { :action => 'set_home_page', :id => @article }, { :method => :post }) %> | ||
72 | - <%= button('delete', _('Delete'), { :action => 'destroy', :id => @article }, :method => :post, :confirm => _('Are you sure you wan to remove this article?')) %> | ||
73 | - <% end %> | ||
74 | - <%= @article.to_html %> | 44 | + <%# non-folder subitems %> |
45 | + <tr> | ||
46 | + <th colspan='2'> | ||
47 | + <%= _('Articles') %> | ||
48 | + </th> | ||
49 | + </tr> | ||
50 | + <% if @subitems.empty? %> | ||
51 | + <tr><td colspan='2' align='center'><em><%= _('None') %></em></td></tr> | ||
52 | + <% end %> | ||
53 | + <% for item in @subitems %> | ||
54 | + <tr> | ||
55 | + <td> | ||
56 | + <%= image_tag(icon_for_article(item)) %> | ||
57 | + <%= link_to item.name, :id => item.id %> | ||
58 | + </td> | ||
59 | + <td> | ||
60 | + <%= link_to _('Edit'), :action => 'edit', :id => item.id %> | ||
61 | + <%= link_to _('View'), item.url %> | ||
62 | + </td> | ||
63 | + </tr> | ||
75 | <% end %> | 64 | <% end %> |
76 | -</div> | 65 | + |
66 | + | ||
67 | +</table> |
test/functional/cms_controller_test.rb
@@ -313,6 +313,89 @@ class CmsControllerTest < Test::Unit::TestCase | @@ -313,6 +313,89 @@ class CmsControllerTest < Test::Unit::TestCase | ||
313 | assert_tag :tag => 'input', :attributes => { :name => 'parent_id', :value => profile.home_page.id } | 313 | assert_tag :tag => 'input', :attributes => { :name => 'parent_id', :value => profile.home_page.id } |
314 | end | 314 | end |
315 | 315 | ||
316 | + should 'list folders at top level' do | ||
317 | + f1 = Folder.new(:name => 'f1'); profile.articles << f1; f1.save! | ||
318 | + f2 = Folder.new(:name => 'f2'); profile.articles << f2; f2.save! | ||
316 | 319 | ||
320 | + get :index, :profile => profile.identifier | ||
321 | + assert_equal [f1, f2], assigns(:folders) | ||
322 | + assert_not_includes assigns(:subitems), f1 | ||
323 | + assert_not_includes assigns(:subitems), f2 | ||
324 | + end | ||
325 | + | ||
326 | + should 'list folders inside another folder' do | ||
327 | + parent = Folder.new(:name => 'parent'); profile.articles << parent; parent.save! | ||
328 | + f1 = Folder.new(:name => 'f1', :parent => parent); profile.articles << f1; f1.save! | ||
329 | + f2 = Folder.new(:name => 'f2', :parent => parent); profile.articles << f2; f2.save! | ||
330 | + | ||
331 | + get :view, :profile => profile.identifier, :id => parent.id | ||
332 | + assert_equal [f1, f2], assigns(:folders) | ||
333 | + assert_not_includes assigns(:subitems), f1 | ||
334 | + assert_not_includes assigns(:subitems), f2 | ||
335 | + end | ||
336 | + | ||
337 | + should 'offer to create new top-level folder' do | ||
338 | + get :index, :profile => profile.identifier | ||
339 | + assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/new?type=Folder"} | ||
340 | + end | ||
341 | + | ||
342 | + should 'offer to create sub-folder' do | ||
343 | + f = Folder.new(:name => 'f'); profile.articles << f; f.save! | ||
344 | + get :view, :profile => profile.identifier, :id => f.id | ||
345 | + | ||
346 | + assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/new?parent_id=#{f.id}&type=Folder" } | ||
347 | + end | ||
348 | + | ||
349 | + should 'redirect back to index after creating top-level article' do | ||
350 | + post :new, :profile => profile.identifier, :type => 'TextileArticle', :article => { :name => 'test' } | ||
351 | + assert_redirected_to :action => 'index' | ||
352 | + end | ||
353 | + | ||
354 | + should 'redirect back to folder after creating article inside it' do | ||
355 | + f = Folder.new(:name => 'f'); profile.articles << f; f.save! | ||
356 | + post :new, :profile => profile.identifier, :type => 'TextileArticle', :parent_id => f.id, :article => { :name => 'test' } | ||
357 | + assert_redirected_to :action => 'view', :id => f.id | ||
358 | + end | ||
359 | + | ||
360 | + should 'redirect back to index after editing top-level article' do | ||
361 | + f = Folder.new(:name => 'f'); profile.articles << f; f.save! | ||
362 | + post :edit, :profile => profile.identifier, :id => f.id | ||
363 | + assert_redirected_to :action => 'index' | ||
364 | + end | ||
365 | + | ||
366 | + should 'redirect back to folder after editing article inside it' do | ||
367 | + f = Folder.new(:name => 'f'); profile.articles << f; f.save! | ||
368 | + a = TextileArticle.create!(:parent => f, :name => 'test', :profile_id => profile.id) | ||
369 | + | ||
370 | + post :edit, :profile => profile.identifier, :id => a.id | ||
371 | + assert_redirected_to :action => 'view', :id => f.id | ||
372 | + end | ||
373 | + | ||
374 | + should 'point back to index when cancelling creation of top-level article' do | ||
375 | + get :new, :profile => profile.identifier, :type => 'Folder' | ||
376 | + assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms" }, :descendant => { :content => /Cancel/ } | ||
377 | + end | ||
378 | + | ||
379 | + should 'point back to index when cancelling edition of top-level article' do | ||
380 | + f = Folder.new(:name => 'f'); profile.articles << f; f.save! | ||
381 | + get :edit, :profile => profile.identifier, :id => f.id | ||
382 | + | ||
383 | + assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms" }, :descendant => { :content => /Cancel/ } | ||
384 | + end | ||
385 | + | ||
386 | + should 'point back to folder when cancelling creation of an article inside it' do | ||
387 | + f = Folder.new(:name => 'f'); profile.articles << f; f.save! | ||
388 | + get :new, :profile => profile.identifier, :type => 'Folder', :parent_id => f.id | ||
389 | + | ||
390 | + assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/view/#{f.id}" }, :descendant => { :content => /Cancel/ } | ||
391 | + end | ||
392 | + | ||
393 | + should 'point back to folder when cancelling edition of an article inside it' do | ||
394 | + f = Folder.new(:name => 'f'); profile.articles << f; f.save! | ||
395 | + a = TextileArticle.create!(:name => 'test', :parent => f, :profile_id => profile.id) | ||
396 | + get :edit, :profile => profile.identifier, :id => a.id | ||
397 | + | ||
398 | + assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/view/#{f.id}" }, :descendant => { :content => /Cancel/ } | ||
399 | + end | ||
317 | 400 | ||
318 | end | 401 | end |
test/unit/article_test.rb
@@ -229,4 +229,8 @@ class ArticleTest < Test::Unit::TestCase | @@ -229,4 +229,8 @@ class ArticleTest < Test::Unit::TestCase | ||
229 | assert_not_includes list, a2 | 229 | assert_not_includes list, a2 |
230 | end | 230 | end |
231 | 231 | ||
232 | + should 'identify itself as a non-folder' do | ||
233 | + assert !Article.new.folder?, 'should identify itself as non-folder' | ||
234 | + end | ||
235 | + | ||
232 | end | 236 | end |
test/unit/folder_test.rb
@@ -30,4 +30,8 @@ class FolderTest < ActiveSupport::TestCase | @@ -30,4 +30,8 @@ class FolderTest < ActiveSupport::TestCase | ||
30 | assert_match(/<li><a href=".*\/testuser\/f\/otherarticle">otherarticle<\/a><\/li>/, f.to_html) | 30 | assert_match(/<li><a href=".*\/testuser\/f\/otherarticle">otherarticle<\/a><\/li>/, f.to_html) |
31 | end | 31 | end |
32 | 32 | ||
33 | + should 'identify as folder' do | ||
34 | + assert Folder.new.folder?, 'folder must identity itself as folder' | ||
35 | + end | ||
36 | + | ||
33 | end | 37 | end |