Commit 40c80d884a4bceb25918744e55c416cc65af9241
1 parent
904f1fb4
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> | ... | ... |