Commit 17b51105dce70f1854f884ec698efdd0b1bd9892
1 parent
3f489bc4
Exists in
theme-brasil-digital-from-staging
and in
9 other branches
proposals_discussion: a plugin to promote a debate over ideas proposed by users
Showing
11 changed files
with
296 additions
and
0 deletions
Show diff stats
plugins/proposals_discussion/lib/proposals_discussion_plugin.rb
0 → 100644
... | ... | @@ -0,0 +1,36 @@ |
1 | +class ProposalsDiscussionPlugin < Noosfero::Plugin | |
2 | + | |
3 | + def self.plugin_name | |
4 | + 'Discussion of Proposals' | |
5 | + end | |
6 | + | |
7 | + def self.plugin_description | |
8 | + _("Provide a structured way to promove a discussion over ideas proposed by users.") | |
9 | + end | |
10 | + | |
11 | + def stylesheet? | |
12 | + true | |
13 | + end | |
14 | + | |
15 | + def content_types | |
16 | + if context.respond_to?(:params) && context.params | |
17 | + types = [] | |
18 | + parent_id = context.params[:parent_id] | |
19 | + parent = parent_id ? context.profile.articles.find(parent_id) : nil | |
20 | + types << ProposalsDiscussionPlugin::Discussion unless parent | |
21 | + types << ProposalsDiscussionPlugin::Proposal if parent.kind_of?(ProposalsDiscussionPlugin::Discussion) | |
22 | + types | |
23 | + else | |
24 | + [ProposalsDiscussionPlugin::Discussion, ProposalsDiscussionPlugin::Proposal] | |
25 | + end | |
26 | + end | |
27 | + | |
28 | + def content_remove_new(page) | |
29 | + page.kind_of?(ProposalsDiscussionPlugin::Discussion) || page.kind_of?(ProposalsDiscussionPlugin::Proposal) | |
30 | + end | |
31 | + | |
32 | + def content_remove_upload(page) | |
33 | + page.kind_of?(ProposalsDiscussionPlugin::Discussion) || page.kind_of?(ProposalsDiscussionPlugin::Proposal) | |
34 | + end | |
35 | + | |
36 | +end | ... | ... |
plugins/proposals_discussion/lib/proposals_discussion_plugin/discussion.rb
0 → 100644
... | ... | @@ -0,0 +1,18 @@ |
1 | +class ProposalsDiscussionPlugin::Discussion < Folder | |
2 | + | |
3 | + def self.short_description | |
4 | + _("Discussion") | |
5 | + end | |
6 | + | |
7 | + def self.description | |
8 | + _('Container for proposals.') | |
9 | + end | |
10 | + | |
11 | + def to_html(options = {}) | |
12 | + discussion = self | |
13 | + proc do | |
14 | + render :file => 'content_viewer/discussion', :locals => {:discussion => discussion} | |
15 | + end | |
16 | + end | |
17 | + | |
18 | +end | ... | ... |
plugins/proposals_discussion/lib/proposals_discussion_plugin/proposal.rb
0 → 100644
1.66 KB
... | ... | @@ -0,0 +1,80 @@ |
1 | +.proposal { | |
2 | + background: rgb(236, 236, 236); | |
3 | + width: 31%; | |
4 | + min-width: 272px; | |
5 | + display: inline-block; | |
6 | + vertical-align: top; | |
7 | + margin: 5px 13px 5px 0; | |
8 | + box-shadow: 5px 5px 5px -2px #ddd; | |
9 | +} | |
10 | + | |
11 | +.proposal:hover { | |
12 | + background: rgb(223, 223, 223); | |
13 | +} | |
14 | + | |
15 | +.proposal .title { | |
16 | + background: rgba(0, 0, 0, 0.1); | |
17 | + font-weight: bold; | |
18 | + font-size: 15px; | |
19 | +} | |
20 | + | |
21 | +#article .proposal a:visited, #article .proposal a { | |
22 | + color: rgb(94, 94, 94); | |
23 | + text-decoration: none; | |
24 | + width: 100%; | |
25 | + display: inline-block; | |
26 | +} | |
27 | + | |
28 | +#article .proposal .title { | |
29 | + padding: 0px 5px; | |
30 | +} | |
31 | + | |
32 | +#article .proposal .title a { | |
33 | + padding: 8px 0px; | |
34 | +} | |
35 | + | |
36 | +.proposal .content { | |
37 | + padding: 5px; | |
38 | + color: rgb(83, 83, 83); | |
39 | +} | |
40 | + | |
41 | +.proposal .abstract { | |
42 | + padding-top: 8px; | |
43 | +} | |
44 | + | |
45 | +.proposal .info { | |
46 | + float: left; | |
47 | +} | |
48 | + | |
49 | +.proposal .info .comments { | |
50 | + background: url('/plugins/proposals_discussion/images/comments.gif') no-repeat left/15px; | |
51 | + padding-left: 18px; | |
52 | + display: inline; | |
53 | + font-size: 10px; | |
54 | + color: rgb(82, 82, 82); | |
55 | + opacity: 0.6; | |
56 | +} | |
57 | + | |
58 | +.proposal .actions { | |
59 | + float: right; | |
60 | +} | |
61 | + | |
62 | +.proposal .actions .vote-actions { | |
63 | + position: static; | |
64 | +} | |
65 | + | |
66 | +.proposal .actions .vote-actions .vote-action a { | |
67 | + opacity: 0.6; | |
68 | +} | |
69 | + | |
70 | +form .proposals-discussion-plugin textarea { | |
71 | + width: 98%; | |
72 | +} | |
73 | + | |
74 | +form .proposals-discussion-plugin .abstract textarea { | |
75 | + height: 60px; | |
76 | +} | |
77 | + | |
78 | +form .proposals-discussion-plugin .body textarea { | |
79 | + height: 400px; | |
80 | +} | ... | ... |
... | ... | @@ -0,0 +1 @@ |
1 | +require File.dirname(__FILE__) + '/../../../test/test_helper' | ... | ... |
... | ... | @@ -0,0 +1,22 @@ |
1 | +require File.dirname(__FILE__) + '/../test_helper' | |
2 | + | |
3 | +class ProposalsDiscussionPluginTest < ActiveSupport::TestCase | |
4 | + | |
5 | + def setup | |
6 | + @profile = fast_create(Community) | |
7 | + @proposal = ProposalsDiscussionPlugin::Proposal.new(:name => 'test', :profile => @profile) | |
8 | + end | |
9 | + | |
10 | + attr_reader :profile, :proposal | |
11 | + | |
12 | + should 'save a proposal' do | |
13 | + proposal.abstract = 'abstract' | |
14 | + assert proposal.save | |
15 | + end | |
16 | + | |
17 | + should 'do not save a proposal without abstract' do | |
18 | + proposal.save | |
19 | + assert proposal.errors['abstract'].present? | |
20 | + end | |
21 | + | |
22 | +end | ... | ... |
plugins/proposals_discussion/test/unit/proposals_discussion_plugin_test.rb
0 → 100644
... | ... | @@ -0,0 +1,70 @@ |
1 | +require File.dirname(__FILE__) + '/../test_helper' | |
2 | + | |
3 | +class ProposalsDiscussionPluginTest < ActiveSupport::TestCase | |
4 | + | |
5 | + def setup | |
6 | + @plugin = ProposalsDiscussionPlugin.new | |
7 | + @profile = fast_create(Community) | |
8 | + @params = {} | |
9 | + @plugin.stubs(:context).returns(self) | |
10 | + end | |
11 | + | |
12 | + attr_reader :plugin, :profile, :params | |
13 | + | |
14 | + should 'has stylesheet' do | |
15 | + assert @plugin.stylesheet? | |
16 | + end | |
17 | + | |
18 | + should 'return Discussion as a content type' do | |
19 | + @params[:parent_id] = nil | |
20 | + assert_includes plugin.content_types, ProposalsDiscussionPlugin::Discussion | |
21 | + end | |
22 | + | |
23 | + should 'do not return Discussion as a content type if it has a parent' do | |
24 | + parent = fast_create(Folder, :profile_id => @profile.id) | |
25 | + @params[:parent_id] = parent.id | |
26 | + assert_not_includes plugin.content_types, ProposalsDiscussionPlugin::Discussion | |
27 | + end | |
28 | + | |
29 | + should 'return Proposal as a content type if parent is a Discussion' do | |
30 | + parent = fast_create(ProposalsDiscussionPlugin::Discussion, :profile_id => @profile.id) | |
31 | + @params[:parent_id] = parent.id | |
32 | + assert_includes plugin.content_types, ProposalsDiscussionPlugin::Proposal | |
33 | + end | |
34 | + | |
35 | + should 'do not return Proposal as a content type if parent is nil' do | |
36 | + @params[:parent_id] = nil | |
37 | + assert_not_includes plugin.content_types, ProposalsDiscussionPlugin::Proposal | |
38 | + end | |
39 | + | |
40 | + should 'remove new button from content page for a discussion' do | |
41 | + page = fast_create(ProposalsDiscussionPlugin::Discussion, :profile_id => @profile.id) | |
42 | + assert plugin.content_remove_new(page) | |
43 | + end | |
44 | + | |
45 | + should 'remove upload button from content page for a discussion' do | |
46 | + page = fast_create(ProposalsDiscussionPlugin::Discussion, :profile_id => @profile.id) | |
47 | + assert plugin.content_remove_upload(page) | |
48 | + end | |
49 | + | |
50 | + should 'remove new button from content page for a proposal' do | |
51 | + page = fast_create(ProposalsDiscussionPlugin::Proposal, :profile_id => @profile.id) | |
52 | + assert plugin.content_remove_new(page) | |
53 | + end | |
54 | + | |
55 | + should 'remove upload button from content page for a proposal' do | |
56 | + page = fast_create(ProposalsDiscussionPlugin::Proposal, :profile_id => @profile.id) | |
57 | + assert plugin.content_remove_upload(page) | |
58 | + end | |
59 | + | |
60 | + should 'do not remove new button from content page for others article types' do | |
61 | + page = fast_create(Article, :profile_id => @profile.id) | |
62 | + assert !plugin.content_remove_new(page) | |
63 | + end | |
64 | + | |
65 | + should 'do not remove upload button from content page for others article types' do | |
66 | + page = fast_create(Article, :profile_id => @profile.id) | |
67 | + assert !plugin.content_remove_upload(page) | |
68 | + end | |
69 | + | |
70 | +end | ... | ... |
plugins/proposals_discussion/views/cms/proposals_discussion_plugin/_proposal.html.erb
0 → 100644
... | ... | @@ -0,0 +1,28 @@ |
1 | +<%= required_fields_message %> | |
2 | + | |
3 | +<%= render :file => 'shared/tiny_mce' %> | |
4 | + | |
5 | +<% title_limit = 70 %> | |
6 | +<% abstract_limit = 140 %> | |
7 | + | |
8 | +<div class="proposals-discussion-plugin"> | |
9 | + <div class="title"> | |
10 | + <%= required labelled_form_field _('Title'), limited_text_area(:article, :name, title_limit, 'title_textarea', :rows => 1) %> | |
11 | + </div> | |
12 | + | |
13 | + <div class="abstract"> | |
14 | + <%= required labelled_form_field _('Abstract'), limited_text_area(:article, :abstract, abstract_limit, 'abstract_textarea') %> | |
15 | + </div> | |
16 | + | |
17 | + <div class="body"> | |
18 | + <% editor_type = 'mceEditor' %> | |
19 | + <%= labelled_form_field(_('Text'), text_area(:article, :body, :class => editor_type)) %> | |
20 | + </div> | |
21 | +</div> | |
22 | + | |
23 | +<script> | |
24 | +jQuery( document ).ready(function( $ ) { | |
25 | + limited_text_area('title_textarea', <%= title_limit %>); | |
26 | + limited_text_area('abstract_textarea', <%= abstract_limit %>); | |
27 | +}); | |
28 | +</script> | ... | ... |
plugins/proposals_discussion/views/content_viewer/_proposal_card.html.erb
0 → 100644
... | ... | @@ -0,0 +1,16 @@ |
1 | +<div class="proposal"> | |
2 | + <div class="title"> | |
3 | + <%= link_to proposal_card.name, proposal_card.view_url %> | |
4 | + </div> | |
5 | + <div class="content"> | |
6 | + <div class="info"> | |
7 | + <div class="comments"><%= proposal_card.comments_count %></div> | |
8 | + </div> | |
9 | + <div class="actions"> | |
10 | + <%= @plugins.dispatch(:article_header_extra_contents, proposal_card).collect { |content| instance_exec(&content) }.join("") %> | |
11 | + </div> | |
12 | + <div class="abstract"> | |
13 | + <%= link_to strip_tags(proposal_card.lead), proposal_card.view_url %> | |
14 | + </div> | |
15 | + </div> | |
16 | +</div> | ... | ... |
plugins/proposals_discussion/views/content_viewer/discussion.html.erb
0 → 100644
... | ... | @@ -0,0 +1,12 @@ |
1 | +<div class="description"> | |
2 | + <%= @page.body %> | |
3 | +</div> | |
4 | + | |
5 | +<%= link_to url_for({:controller => 'cms', :action => 'new', :type => "ProposalsDiscussionPlugin::Proposal", :parent_id => @page.id}), :class => 'button with-text icon-add' do %> | |
6 | + <strong><%= _("New Proposal") %></strong> | |
7 | +<% end %> | |
8 | + | |
9 | +<div class="proposals"> | |
10 | + <%= render :partial => 'content_viewer/proposal_card', :collection => discussion.children %> | |
11 | + <div class="clear"></div> | |
12 | +</div> | ... | ... |