Commit 260f0d799b8520b7de6f9c6c802266e3b1bc052a
1 parent
3e4b7e40
Exists in
master
and in
23 other branches
Adding macro support for TinyMCE articles and a plugin called CommentGroupMacro …
…that uses the macro support
Showing
29 changed files
with
1007 additions
and
56 deletions
Show diff stats
app/controllers/public/content_viewer_controller.rb
| @@ -98,10 +98,13 @@ class ContentViewerController < ApplicationController | @@ -98,10 +98,13 @@ class ContentViewerController < ApplicationController | ||
| 98 | session[:notice] = _("Notification of new comments to '%s' was successfully canceled") % params[:email] | 98 | session[:notice] = _("Notification of new comments to '%s' was successfully canceled") % params[:email] |
| 99 | end | 99 | end |
| 100 | end | 100 | end |
| 101 | + | ||
| 102 | + @comments = @plugins.dispatch_first(:load_comments, @page) | ||
| 103 | + @comments ||= @page.comments.without_spam.as_thread | ||
| 104 | + @comments = [@comments] unless @comments.is_a?(Array) | ||
| 105 | + | ||
| 106 | + @comments_count = Comment.count_thread(@comments) | ||
| 101 | 107 | ||
| 102 | - comments = @page.comments.without_spam | ||
| 103 | - @comments = comments.as_thread | ||
| 104 | - @comments_count = comments.count | ||
| 105 | if params[:slideshow] | 108 | if params[:slideshow] |
| 106 | render :action => 'slideshow', :layout => 'slideshow' | 109 | render :action => 'slideshow', :layout => 'slideshow' |
| 107 | end | 110 | end |
app/helpers/application_helper.rb
| @@ -988,10 +988,7 @@ module ApplicationHelper | @@ -988,10 +988,7 @@ module ApplicationHelper | ||
| 988 | options.merge!(:page => params[:npage]) | 988 | options.merge!(:page => params[:npage]) |
| 989 | content = article.to_html(options) | 989 | content = article.to_html(options) |
| 990 | content = content.kind_of?(Proc) ? self.instance_eval(&content) : content | 990 | content = content.kind_of?(Proc) ? self.instance_eval(&content) : content |
| 991 | - @plugins && @plugins.each do |plugin| | ||
| 992 | - content = plugin.parse_content(content) | ||
| 993 | - end | ||
| 994 | - content | 991 | + filter_html(content, article) |
| 995 | end | 992 | end |
| 996 | 993 | ||
| 997 | def colorpicker_field(object_name, method, options = {}) | 994 | def colorpicker_field(object_name, method, options = {}) |
| @@ -1425,4 +1422,36 @@ module ApplicationHelper | @@ -1425,4 +1422,36 @@ module ApplicationHelper | ||
| 1425 | @no_design_blocks = true | 1422 | @no_design_blocks = true |
| 1426 | end | 1423 | end |
| 1427 | 1424 | ||
| 1425 | + def filter_html(html, source) | ||
| 1426 | + if @plugins | ||
| 1427 | + html = convert_macro(html, source) | ||
| 1428 | + end | ||
| 1429 | + html | ||
| 1430 | + end | ||
| 1431 | + | ||
| 1432 | + def convert_macro(html, source) | ||
| 1433 | + doc = Hpricot(html) | ||
| 1434 | + while element = doc.search('.macro').first | ||
| 1435 | + macro_name = element['data-macro'] | ||
| 1436 | + method_name = "macro_#{macro_name}" | ||
| 1437 | + attrs = collect_macro_attributes(element) | ||
| 1438 | + plugin_instance = Environment.macros[environment.id][method_name] | ||
| 1439 | + if plugin_instance | ||
| 1440 | + result = plugin_instance.send(method_name, attrs, element.inner_html, source) | ||
| 1441 | + element.inner_html = result.kind_of?(Proc) ? self.instance_eval(&result) : result | ||
| 1442 | + element['class'] = "parsed-macro #{macro_name}" | ||
| 1443 | + else | ||
| 1444 | + element.inner_html = _("Unsupported macro %s!") % macro_name | ||
| 1445 | + element['class'] = "failed-macro #{macro_name}" | ||
| 1446 | + end | ||
| 1447 | + attrs.each {|key, value| element.remove_attribute("data-macro-#{key}")} | ||
| 1448 | + end | ||
| 1449 | + doc.html | ||
| 1450 | + end | ||
| 1451 | + | ||
| 1452 | + def collect_macro_attributes(element) | ||
| 1453 | + element.attributes.to_hash.select {|key, value| key[0..10] == 'data-macro-'}. | ||
| 1454 | + inject({}){|result, a| result.merge({a[0][11..-1] => a[1]})}.with_indifferent_access | ||
| 1455 | + end | ||
| 1456 | + | ||
| 1428 | end | 1457 | end |
app/helpers/boxes_helper.rb
| @@ -99,8 +99,8 @@ module BoxesHelper | @@ -99,8 +99,8 @@ module BoxesHelper | ||
| 99 | unless block.visible? | 99 | unless block.visible? |
| 100 | options[:title] = _("This block is invisible. Your visitors will not see it.") | 100 | options[:title] = _("This block is invisible. Your visitors will not see it.") |
| 101 | end | 101 | end |
| 102 | - @controller.send(:content_editor?) || @plugins.each do |plugin| | ||
| 103 | - result = plugin.parse_content(result) | 102 | + if @controller.send(:content_editor?) |
| 103 | + result = filter_html(result, block) | ||
| 104 | end | 104 | end |
| 105 | box_decorator.block_target(block.box, block) + | 105 | box_decorator.block_target(block.box, block) + |
| 106 | content_tag('div', | 106 | content_tag('div', |
| @@ -0,0 +1,96 @@ | @@ -0,0 +1,96 @@ | ||
| 1 | +module MacrosHelper | ||
| 2 | + | ||
| 3 | + def macros_in_menu | ||
| 4 | + Environment.macros[@environment.id].reject{ |macro_name, plugin_instance| macro_configuration(macro_name)[:icon_path] } | ||
| 5 | + end | ||
| 6 | + | ||
| 7 | + def macros_with_buttons | ||
| 8 | + Environment.macros[@environment.id].reject{ |macro_name, plugin_instance| !macro_configuration(macro_name)[:icon_path] } | ||
| 9 | + end | ||
| 10 | + | ||
| 11 | + def macro_configuration(macro_name) | ||
| 12 | + plugin_instance = Environment.macros[@environment.id][macro_name] | ||
| 13 | + plugin_instance.send("config_#{macro_name}") | ||
| 14 | + end | ||
| 15 | + | ||
| 16 | + def macro_title(macro_name) | ||
| 17 | + macro_configuration(macro_name)[:title] || macro_name.to_s.humanize | ||
| 18 | + end | ||
| 19 | + | ||
| 20 | + def generate_macro_config_dialog(macro_name) | ||
| 21 | + if macro_configuration(macro_name)[:skip_dialog] | ||
| 22 | + "function(){#{macro_generator(macro_name)}}" | ||
| 23 | + else | ||
| 24 | + "function(){ | ||
| 25 | + jQuery('<div>'+#{macro_configuration_dialog(macro_name).to_json}+'</div>').dialog({ | ||
| 26 | + title: #{macro_title(macro_name).to_json}, | ||
| 27 | + modal: true, | ||
| 28 | + buttons: [ | ||
| 29 | + {text: #{_('Ok').to_json}, click: function(){ | ||
| 30 | + tinyMCE.activeEditor.execCommand('mceInsertContent', false, | ||
| 31 | + (function(dialog){ #{macro_generator(macro_name)} })(this)); | ||
| 32 | + jQuery(this).dialog('close'); | ||
| 33 | + }}, | ||
| 34 | + {text: #{_('Cancel').to_json}, click: function(){jQuery(this).dialog('close');}} | ||
| 35 | + ] | ||
| 36 | + }); | ||
| 37 | + }" | ||
| 38 | + end | ||
| 39 | + end | ||
| 40 | + | ||
| 41 | + def include_macro_js_files | ||
| 42 | + plugins_javascripts = [] | ||
| 43 | + Environment.macros[environment.id].map do |macro_name, plugin_instance| | ||
| 44 | + if macro_configuration(macro_name)[:js_files] | ||
| 45 | + macro_configuration(macro_name)[:js_files].map { |js| plugins_javascripts << plugin_instance.class.public_path(js) } | ||
| 46 | + end | ||
| 47 | + end | ||
| 48 | + javascript_include_tag(plugins_javascripts, :cache => 'cache/plugins-' + Digest::MD5.hexdigest(plugins_javascripts.to_s)) unless plugins_javascripts.empty? | ||
| 49 | + end | ||
| 50 | + | ||
| 51 | + def macro_css_files | ||
| 52 | + plugins_css = [] | ||
| 53 | + Environment.macros[environment.id].map do |macro_name, plugin_instance| | ||
| 54 | + if macro_configuration(macro_name)[:css_files] | ||
| 55 | + macro_configuration(macro_name)[:css_files].map { |css| plugins_css << plugin_instance.class.public_path(css) } | ||
| 56 | + end | ||
| 57 | + end | ||
| 58 | + plugins_css.join(',') | ||
| 59 | + end | ||
| 60 | + | ||
| 61 | + protected | ||
| 62 | + | ||
| 63 | + def macro_generator(macro_name) | ||
| 64 | + if macro_configuration(macro_name)[:generator] | ||
| 65 | + macro_configuration(macro_name)[:generator] | ||
| 66 | + else | ||
| 67 | + macro_default_generator(macro_name) | ||
| 68 | + end | ||
| 69 | + end | ||
| 70 | + | ||
| 71 | + def macro_default_generator(macro_name) | ||
| 72 | + code = "var params = {};" | ||
| 73 | + configuration = macro_configuration(macro_name) | ||
| 74 | + configuration[:params].map do |field| | ||
| 75 | + code += "params.#{field[:name]} = jQuery('*[name=#{field[:name]}]', dialog).val();" | ||
| 76 | + end | ||
| 77 | + code + " | ||
| 78 | + var html = jQuery('<div class=\"macro mceNonEditable\" data-macro=\"#{macro_name[6..-1]}\">'+#{macro_title(macro_name).to_json}+'</div>')[0]; | ||
| 79 | + for(key in params) html.setAttribute('data-macro-'+key,params[key]); | ||
| 80 | + return html.outerHTML; | ||
| 81 | + " | ||
| 82 | + end | ||
| 83 | + | ||
| 84 | + def macro_configuration_dialog(macro_name) | ||
| 85 | + macro_configuration(macro_name)[:params].map do |field| | ||
| 86 | + label_name = field[:label] || field[:name].to_s.humanize | ||
| 87 | + case field[:type] | ||
| 88 | + when 'text' | ||
| 89 | + labelled_form_field(label_name, text_field_tag(field[:name], field[:default])) | ||
| 90 | + when 'select' | ||
| 91 | + labelled_form_field(label_name, select_tag(field[:name], options_for_select(field[:values], field[:default]))) | ||
| 92 | + end | ||
| 93 | + end.join("\n") | ||
| 94 | + end | ||
| 95 | + | ||
| 96 | +end |
app/models/comment.rb
| @@ -157,6 +157,14 @@ class Comment < ActiveRecord::Base | @@ -157,6 +157,14 @@ class Comment < ActiveRecord::Base | ||
| 157 | @replies = comments_list | 157 | @replies = comments_list |
| 158 | end | 158 | end |
| 159 | 159 | ||
| 160 | + def self.count_thread(comments) | ||
| 161 | + count = comments.length | ||
| 162 | + comments.each do |c| | ||
| 163 | + count+=count_thread(c.replies) | ||
| 164 | + end | ||
| 165 | + count | ||
| 166 | + end | ||
| 167 | + | ||
| 160 | def self.as_thread | 168 | def self.as_thread |
| 161 | result = {} | 169 | result = {} |
| 162 | root = [] | 170 | root = [] |
app/models/environment.rb
| @@ -16,6 +16,10 @@ class Environment < ActiveRecord::Base | @@ -16,6 +16,10 @@ class Environment < ActiveRecord::Base | ||
| 16 | filename | 16 | filename |
| 17 | end | 17 | end |
| 18 | 18 | ||
| 19 | + class << self | ||
| 20 | + attr_accessor :macros | ||
| 21 | + end | ||
| 22 | + | ||
| 19 | PERMISSIONS['Environment'] = { | 23 | PERMISSIONS['Environment'] = { |
| 20 | 'view_environment_admin_panel' => N_('View environment admin panel'), | 24 | 'view_environment_admin_panel' => N_('View environment admin panel'), |
| 21 | 'edit_environment_features' => N_('Edit environment features'), | 25 | 'edit_environment_features' => N_('Edit environment features'), |
app/views/comment/_comment_form.rhtml
| @@ -89,6 +89,8 @@ function check_captcha(button, confirm_action) { | @@ -89,6 +89,8 @@ function check_captcha(button, confirm_action) { | ||
| 89 | <%= required labelled_form_field(_('Enter your comment'), f.text_area(:body, :rows => 5)) %> | 89 | <%= required labelled_form_field(_('Enter your comment'), f.text_area(:body, :rows => 5)) %> |
| 90 | <%= f.hidden_field(:reply_of_id) %> | 90 | <%= f.hidden_field(:reply_of_id) %> |
| 91 | 91 | ||
| 92 | + <%= @plugins.dispatch(:comment_form_extra_contents, local_assigns).collect { |content| instance_eval(&content) }.join("") %> | ||
| 93 | + | ||
| 92 | <% button_bar do %> | 94 | <% button_bar do %> |
| 93 | <%= submit_button('add', _('Post comment'), :onclick => "if(check_captcha(this)) { save_comment(this) } else { check_captcha(this, save_comment)};return false;") %> | 95 | <%= submit_button('add', _('Post comment'), :onclick => "if(check_captcha(this)) { save_comment(this) } else { check_captcha(this, save_comment)};return false;") %> |
| 94 | <%= button_to_function :cancel, _('Cancel'), "jQuery.colorbox.close();f=jQuery(this).parents('.post_comment_box'); f.removeClass('opened'); f.addClass('closed'); return false" %> | 96 | <%= button_to_function :cancel, _('Cancel'), "jQuery.colorbox.close();f=jQuery(this).parents('.post_comment_box'); f.removeClass('opened'); f.addClass('closed'); return false" %> |
app/views/content_viewer/view_page.rhtml
| @@ -91,7 +91,7 @@ | @@ -91,7 +91,7 @@ | ||
| 91 | 91 | ||
| 92 | <% if @page.accept_comments? || @comments_count > 0 %> | 92 | <% if @page.accept_comments? || @comments_count > 0 %> |
| 93 | <h3 <%= 'class="no-comments-yet"' if @comments_count == 0 %>> | 93 | <h3 <%= 'class="no-comments-yet"' if @comments_count == 0 %>> |
| 94 | - <%= number_of_comments(@page) %> | 94 | + <%= display_number_of_comments(@comments_count) %> |
| 95 | </h3> | 95 | </h3> |
| 96 | <% end %> | 96 | <% end %> |
| 97 | 97 |
app/views/shared/tiny_mce.rhtml
| 1 | +<% extend MacrosHelper %> | ||
| 1 | <%= javascript_include_tag 'tinymce/jscripts/tiny_mce/tiny_mce.js' %> | 2 | <%= javascript_include_tag 'tinymce/jscripts/tiny_mce/tiny_mce.js' %> |
| 3 | +<%= include_macro_js_files %> | ||
| 2 | <script type="text/javascript"> | 4 | <script type="text/javascript"> |
| 3 | - var myplugins = "searchreplace,print,table,contextmenu"; | 5 | + var myplugins = "searchreplace,print,table,contextmenu,-macrosPlugin"; |
| 4 | var first_line, second_line; | 6 | var first_line, second_line; |
| 5 | var mode = '<%= mode ||= false %>' | 7 | var mode = '<%= mode ||= false %>' |
| 6 | <% if mode %> | 8 | <% if mode %> |
| @@ -8,36 +10,82 @@ | @@ -8,36 +10,82 @@ | ||
| 8 | second_line = "" | 10 | second_line = "" |
| 9 | <% else %> | 11 | <% else %> |
| 10 | first_line = "print,separator,copy,paste,separator,undo,redo,separator,search,replace,separator,forecolor,fontsizeselect,formatselect" | 12 | first_line = "print,separator,copy,paste,separator,undo,redo,separator,search,replace,separator,forecolor,fontsizeselect,formatselect" |
| 11 | - second_line = "bold,italic,underline,strikethrough,separator,bullist,numlist,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,link,unlink,image,table,separator,cleanup,code" | 13 | + second_line = "bold,italic,underline,strikethrough,separator,bullist,numlist,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,link,unlink,image,table,separator,cleanup,code,macros" |
| 14 | + <% Environment.macros[environment.id].each do |macro_name, plugin_instance| %> | ||
| 15 | + <% if macro_configuration(macro_name)[:icon_path] %> | ||
| 16 | + second_line += ',<%=macro_name %>' | ||
| 17 | + <% end %> | ||
| 18 | + <% end %> | ||
| 12 | <% end %> | 19 | <% end %> |
| 13 | 20 | ||
| 14 | if (tinymce.isIE) { | 21 | if (tinymce.isIE) { |
| 15 | // the paste plugin is only useful in Internet Explorer | 22 | // the paste plugin is only useful in Internet Explorer |
| 16 | myplugins = "paste," + myplugins; | 23 | myplugins = "paste," + myplugins; |
| 17 | } | 24 | } |
| 25 | + | ||
| 26 | +tinymce.create('tinymce.plugins.MacrosPlugin', { | ||
| 27 | + createControl: function(n, cm) { | ||
| 28 | + switch (n) { | ||
| 29 | + case 'macros': | ||
| 30 | + <% unless macros_in_menu.empty? %> | ||
| 31 | + var c = cm.createMenuButton('macros', { | ||
| 32 | + title : 'Macros', | ||
| 33 | + image : '/designs/icons/tango/Tango/16x16/emblems/emblem-system.png', | ||
| 34 | + icons : false | ||
| 35 | + }); | ||
| 36 | + | ||
| 37 | + <% macros_in_menu.each do |macro_name, plugin_instance| %> | ||
| 38 | + c.onRenderMenu.add(function(c, m) { | ||
| 39 | + m.add({ | ||
| 40 | + title: <%= macro_title(macro_name).to_json %>, | ||
| 41 | + onclick: <%= generate_macro_config_dialog(macro_name) %> | ||
| 42 | + }); | ||
| 43 | + }); | ||
| 44 | + <% end %> | ||
| 45 | + | ||
| 46 | + // Return the new menu button instance | ||
| 47 | + return c; | ||
| 48 | + <% end %> | ||
| 49 | + } | ||
| 50 | + return null; | ||
| 51 | + } | ||
| 52 | +}); | ||
| 53 | + | ||
| 54 | +// Register plugin with a short name | ||
| 55 | +tinymce.PluginManager.add('macrosPlugin', tinymce.plugins.MacrosPlugin); | ||
| 56 | + | ||
| 18 | tinyMCE.init({ | 57 | tinyMCE.init({ |
| 19 | - mode : "textareas", | ||
| 20 | - editor_selector : "mceEditor", | ||
| 21 | - theme : "advanced", | ||
| 22 | - relative_urls : false, | ||
| 23 | - remove_script_host : true, | ||
| 24 | - document_base_url : <%= environment.top_url.to_json %>, | ||
| 25 | - plugins: myplugins, | ||
| 26 | - theme_advanced_toolbar_location : "top", | ||
| 27 | - theme_advanced_layout_manager: 'SimpleLayout', | ||
| 28 | - theme_advanced_buttons1 : first_line, | ||
| 29 | - theme_advanced_buttons2 : second_line, | ||
| 30 | - theme_advanced_buttons3 : "", | ||
| 31 | - theme_advanced_blockformats :"p,address,pre,h2,h3,h4,h5,h6", | ||
| 32 | - paste_auto_cleanup_on_paste : true, | ||
| 33 | - paste_insert_word_content_callback : "convertWord", | ||
| 34 | - paste_use_dialog: false, | ||
| 35 | - apply_source_formatting : true, | ||
| 36 | - extended_valid_elements : "applet[style|archive|codebase|code|height|width],comment,iframe[src|style|allowtransparency|frameborder|width|height|scrolling],embed[title|src|type|height|width]", | ||
| 37 | - content_css: '/stylesheets/tinymce.css', | ||
| 38 | - language: <%= tinymce_language.inspect %>, | ||
| 39 | - entity_encoding: 'raw' | ||
| 40 | - }); | 58 | + mode : "textareas", |
| 59 | + editor_selector : "mceEditor", | ||
| 60 | + theme : "advanced", | ||
| 61 | + relative_urls : false, | ||
| 62 | + remove_script_host : true, | ||
| 63 | + document_base_url : <%= environment.top_url.to_json %>, | ||
| 64 | + plugins: myplugins, | ||
| 65 | + theme_advanced_toolbar_location : "top", | ||
| 66 | + theme_advanced_layout_manager: 'SimpleLayout', | ||
| 67 | + theme_advanced_buttons1 : first_line, | ||
| 68 | + theme_advanced_buttons2 : second_line, | ||
| 69 | + theme_advanced_buttons3 : "", | ||
| 70 | + theme_advanced_blockformats :"p,address,pre,h2,h3,h4,h5,h6", | ||
| 71 | + paste_auto_cleanup_on_paste : true, | ||
| 72 | + paste_insert_word_content_callback : "convertWord", | ||
| 73 | + paste_use_dialog: false, | ||
| 74 | + apply_source_formatting : true, | ||
| 75 | + extended_valid_elements : "applet[style|archive|codebase|code|height|width],comment,iframe[src|style|allowtransparency|frameborder|width|height|scrolling],embed[title|src|type|height|width]", | ||
| 76 | + content_css: '/stylesheets/tinymce.css,<%= macro_css_files %>', | ||
| 77 | + language: <%= tinymce_language.inspect %>, | ||
| 78 | + entity_encoding: 'raw', | ||
| 79 | + setup : function(ed) { | ||
| 80 | + <% macros_with_buttons.each do |macro_name, plugin_instance| %> | ||
| 81 | + ed.addButton('<%= macro_name %>', { | ||
| 82 | + title: <%= macro_title(macro_name).to_json %>, | ||
| 83 | + onclick: <%= generate_macro_config_dialog(macro_name) %>, | ||
| 84 | + image : '<%= macro_configuration(macro_name)[:icon_path]%>' | ||
| 85 | + }); | ||
| 86 | + <% end %> | ||
| 87 | + } | ||
| 88 | +}); | ||
| 41 | 89 | ||
| 42 | function convertWord(type, content) { | 90 | function convertWord(type, content) { |
| 43 | switch (type) { | 91 | switch (type) { |
lib/noosfero/plugin.rb
| @@ -5,6 +5,13 @@ class Noosfero::Plugin | @@ -5,6 +5,13 @@ class Noosfero::Plugin | ||
| 5 | 5 | ||
| 6 | attr_accessor :context | 6 | attr_accessor :context |
| 7 | 7 | ||
| 8 | + def initialize(context=nil) | ||
| 9 | + self.context = context | ||
| 10 | + macro_methods.each do |method| | ||
| 11 | + Environment.macros[context.environment.id][method] = self unless context.nil? | ||
| 12 | + end | ||
| 13 | + end | ||
| 14 | + | ||
| 8 | class << self | 15 | class << self |
| 9 | 16 | ||
| 10 | def klass(dir) | 17 | def klass(dir) |
| @@ -199,8 +206,8 @@ class Noosfero::Plugin | @@ -199,8 +206,8 @@ class Noosfero::Plugin | ||
| 199 | 206 | ||
| 200 | # -> Parse and possibly make changes of content (article, block, etc) during HTML rendering | 207 | # -> Parse and possibly make changes of content (article, block, etc) during HTML rendering |
| 201 | # returns = content as string after parser and changes | 208 | # returns = content as string after parser and changes |
| 202 | - def parse_content(raw_content) | ||
| 203 | - raw_content | 209 | + def parse_content(args) |
| 210 | + args | ||
| 204 | end | 211 | end |
| 205 | 212 | ||
| 206 | # -> Adds links to the admin panel | 213 | # -> Adds links to the admin panel |
| @@ -236,6 +243,18 @@ class Noosfero::Plugin | @@ -236,6 +243,18 @@ class Noosfero::Plugin | ||
| 236 | def filter_comment(comment) | 243 | def filter_comment(comment) |
| 237 | end | 244 | end |
| 238 | 245 | ||
| 246 | + # Define custom logic to load the article comments. | ||
| 247 | + # | ||
| 248 | + # Example: | ||
| 249 | + # | ||
| 250 | + # def load_comments(article) | ||
| 251 | + # article.comments.find(:all, :conditions => ['spam IS NULL OR spam = ?', false]) | ||
| 252 | + # end | ||
| 253 | + # | ||
| 254 | + def load_comments(article) | ||
| 255 | + nil | ||
| 256 | + end | ||
| 257 | + | ||
| 239 | # This method is called by the CommentHandler background job before sending | 258 | # This method is called by the CommentHandler background job before sending |
| 240 | # the notification email. If the comment is marked as spam (i.e. by calling | 259 | # the notification email. If the comment is marked as spam (i.e. by calling |
| 241 | # <tt>comment.spam!</tt>), then the notification email will *not* be sent. | 260 | # <tt>comment.spam!</tt>), then the notification email will *not* be sent. |
| @@ -288,7 +307,7 @@ class Noosfero::Plugin | @@ -288,7 +307,7 @@ class Noosfero::Plugin | ||
| 288 | def profile_info_extra_contents | 307 | def profile_info_extra_contents |
| 289 | nil | 308 | nil |
| 290 | end | 309 | end |
| 291 | - | 310 | + |
| 292 | # -> Removes the invite friend button from the friends controller | 311 | # -> Removes the invite friend button from the friends controller |
| 293 | # returns = boolean | 312 | # returns = boolean |
| 294 | def remove_invite_friends_button | 313 | def remove_invite_friends_button |
| @@ -350,6 +369,18 @@ class Noosfero::Plugin | @@ -350,6 +369,18 @@ class Noosfero::Plugin | ||
| 350 | def login_extra_contents | 369 | def login_extra_contents |
| 351 | nil | 370 | nil |
| 352 | end | 371 | end |
| 372 | + | ||
| 373 | + # -> Adds adicional content to comment form | ||
| 374 | + # returns = lambda block that creates html code | ||
| 375 | + def comment_form_extra_contents(args) | ||
| 376 | + nil | ||
| 377 | + end | ||
| 378 | + | ||
| 379 | + # -> Register macro methods in environment | ||
| 380 | + # returns = ['method1', 'method2', ...] | ||
| 381 | + def macro_methods | ||
| 382 | + [] | ||
| 383 | + end | ||
| 353 | 384 | ||
| 354 | def method_missing(method, *args, &block) | 385 | def method_missing(method, *args, &block) |
| 355 | # This is a generic hotspot for all controllers on Noosfero. | 386 | # This is a generic hotspot for all controllers on Noosfero. |
| @@ -376,6 +407,11 @@ class Noosfero::Plugin | @@ -376,6 +407,11 @@ class Noosfero::Plugin | ||
| 376 | # returns = string with reason of expiration | 407 | # returns = string with reason of expiration |
| 377 | elsif method.to_s =~ /^content_expire_(#{content_actions.join('|')})$/ | 408 | elsif method.to_s =~ /^content_expire_(#{content_actions.join('|')})$/ |
| 378 | nil | 409 | nil |
| 410 | + # -> Answers to a specific macro | ||
| 411 | + # expects: params, inner_html, content | ||
| 412 | + # returns = html_code | ||
| 413 | + elsif method.to_s =~ /^macro_(.+)$/ | ||
| 414 | + nil | ||
| 379 | else | 415 | else |
| 380 | super | 416 | super |
| 381 | end | 417 | end |
lib/noosfero/plugin/manager.rb
| @@ -6,6 +6,7 @@ class Noosfero::Plugin::Manager | @@ -6,6 +6,7 @@ class Noosfero::Plugin::Manager | ||
| 6 | def initialize(environment, context) | 6 | def initialize(environment, context) |
| 7 | @environment = environment | 7 | @environment = environment |
| 8 | @context = context | 8 | @context = context |
| 9 | + Environment.macros = {environment.id => {}} | ||
| 9 | end | 10 | end |
| 10 | 11 | ||
| 11 | delegate :each, :to => :enabled_plugins | 12 | delegate :each, :to => :enabled_plugins |
| @@ -27,13 +28,20 @@ class Noosfero::Plugin::Manager | @@ -27,13 +28,20 @@ class Noosfero::Plugin::Manager | ||
| 27 | map { |plugin| plugin.send(event, *args) }.compact | 28 | map { |plugin| plugin.send(event, *args) }.compact |
| 28 | end | 29 | end |
| 29 | 30 | ||
| 31 | + def dispatch_first(event, *args) | ||
| 32 | + value = nil | ||
| 33 | + map do |plugin| | ||
| 34 | + value = plugin.send(event, *args) | ||
| 35 | + break if value | ||
| 36 | + end | ||
| 37 | + value | ||
| 38 | + end | ||
| 39 | + | ||
| 30 | alias :dispatch_scopes :dispatch_without_flatten | 40 | alias :dispatch_scopes :dispatch_without_flatten |
| 31 | 41 | ||
| 32 | def enabled_plugins | 42 | def enabled_plugins |
| 33 | @enabled_plugins ||= (Noosfero::Plugin.all & environment.enabled_plugins).map do |plugin| | 43 | @enabled_plugins ||= (Noosfero::Plugin.all & environment.enabled_plugins).map do |plugin| |
| 34 | - p = plugin.constantize.new | ||
| 35 | - p.context = context | ||
| 36 | - p | 44 | + plugin.constantize.new(context) |
| 37 | end | 45 | end |
| 38 | end | 46 | end |
| 39 | 47 |
plugins/comment_group_macro/controllers/profile/comment_group_macro_plugin_profile_controller.rb
0 → 100644
| @@ -0,0 +1,16 @@ | @@ -0,0 +1,16 @@ | ||
| 1 | +class CommentGroupMacroPluginProfileController < ProfileController | ||
| 2 | + append_view_path File.join(File.dirname(__FILE__) + '/../views') | ||
| 3 | + | ||
| 4 | + def view_comments | ||
| 5 | + article_id = params[:article_id] | ||
| 6 | + group_id = params[:group_id] | ||
| 7 | + | ||
| 8 | + article = profile.articles.find(article_id) | ||
| 9 | + comments = article.group_comments.without_spam.in_group(group_id) | ||
| 10 | + render :update do |page| | ||
| 11 | + page.replace_html "comments_list_group_#{group_id}", :partial => 'comment/comment.rhtml', :collection => comments.as_thread | ||
| 12 | + page.replace_html "comment-count-#{group_id}", comments.count | ||
| 13 | + end | ||
| 14 | + end | ||
| 15 | + | ||
| 16 | +end |
plugins/comment_group_macro/db/migrate/20121220201629_add_group_id_to_comment.rb
0 → 100644
plugins/comment_group_macro/lib/comment_group_macro_plugin.rb
0 → 100644
| @@ -0,0 +1,44 @@ | @@ -0,0 +1,44 @@ | ||
| 1 | +require_dependency 'comment_group_macro_plugin/ext/article' | ||
| 2 | +require_dependency 'comment_group_macro_plugin/ext/comment' | ||
| 3 | + | ||
| 4 | +#FIXME See a better way to generalize this parameter. | ||
| 5 | +ActionView::Base.sanitized_allowed_attributes += ['data-macro', 'data-macro-group_id'] | ||
| 6 | + | ||
| 7 | +class CommentGroupMacroPlugin < Noosfero::Plugin | ||
| 8 | + | ||
| 9 | + def self.plugin_name | ||
| 10 | + "Comment Group" | ||
| 11 | + end | ||
| 12 | + | ||
| 13 | + def self.plugin_description | ||
| 14 | + _("A plugin that display comment groups.") | ||
| 15 | + end | ||
| 16 | + | ||
| 17 | + def load_comments(article) | ||
| 18 | + article.comments.without_spam.without_group.as_thread | ||
| 19 | + end | ||
| 20 | + | ||
| 21 | + #FIXME make this test | ||
| 22 | + def macro_display_comments(params, inner_html, source) | ||
| 23 | + group_id = params[:group_id].to_i | ||
| 24 | + article = source | ||
| 25 | + count = article.group_comments.without_spam.in_group(group_id).count | ||
| 26 | + | ||
| 27 | + lambda {render :partial => 'plugins/comment_group_macro/views/comment_group.rhtml', :locals => {:group_id => group_id, :article_id => article.id, :inner_html => inner_html, :count => count }} | ||
| 28 | + end | ||
| 29 | + | ||
| 30 | + def macro_methods | ||
| 31 | + 'macro_display_comments' | ||
| 32 | + end | ||
| 33 | + | ||
| 34 | + def config_macro_display_comments | ||
| 35 | + { :params => [], :skip_dialog => true, :generator => 'makeCommentable();', :js_files => 'comment_group.js', :icon_path => '/designs/icons/tango/Tango/16x16/emblems/emblem-system.png', :css_files => 'comment_group.css' } | ||
| 36 | + end | ||
| 37 | + | ||
| 38 | + def comment_form_extra_contents(args) | ||
| 39 | + lambda { | ||
| 40 | + hidden_field_tag('comment[group_id]', args[:group_id]) if args.has_key?(:group_id) | ||
| 41 | + } | ||
| 42 | + end | ||
| 43 | + | ||
| 44 | +end |
plugins/comment_group_macro/lib/comment_group_macro_plugin/ext/article.rb
0 → 100644
| @@ -0,0 +1,21 @@ | @@ -0,0 +1,21 @@ | ||
| 1 | +require_dependency 'article' | ||
| 2 | + | ||
| 3 | +class Article | ||
| 4 | + | ||
| 5 | + #FIXME make this test | ||
| 6 | + has_many :group_comments, :class_name => 'Comment', :foreign_key => 'source_id', :dependent => :destroy, :order => 'created_at asc', :conditions => [ 'group_id IS NOT NULL'] | ||
| 7 | + | ||
| 8 | + #FIXME make this test | ||
| 9 | + validate :not_empty_group_comments_removed | ||
| 10 | + | ||
| 11 | + #FIXME make this test | ||
| 12 | + def not_empty_group_comments_removed | ||
| 13 | + if body | ||
| 14 | + groups_with_comments = group_comments.collect {|comment| comment.group_id}.uniq | ||
| 15 | + groups = Hpricot(body.to_s).search('.macro').collect{|element| element['data-macro-group_id'].to_i} | ||
| 16 | + errors.add_to_base(N_('Not empty group comment cannot be removed')) unless (groups_with_comments-groups).empty? | ||
| 17 | + end | ||
| 18 | + end | ||
| 19 | + | ||
| 20 | +end | ||
| 21 | + |
plugins/comment_group_macro/lib/comment_group_macro_plugin/ext/comment.rb
0 → 100644
| @@ -0,0 +1,47 @@ | @@ -0,0 +1,47 @@ | ||
| 1 | +function getNextGroupId() { | ||
| 2 | + max = -1; | ||
| 3 | + groups = jQuery('#article_body_ifr').contents().find('.article_comments'); | ||
| 4 | + groups.each(function(key, value) { | ||
| 5 | + value = jQuery(value).attr('data-macro-group_id'); | ||
| 6 | + if(value>max) max = parseInt(value); | ||
| 7 | + }); | ||
| 8 | + return max+1; | ||
| 9 | +} | ||
| 10 | + | ||
| 11 | +function makeCommentable() { | ||
| 12 | + tinyMCE.activeEditor.focus(); | ||
| 13 | + start = jQuery(tinyMCE.activeEditor.selection.getStart()).closest('p'); | ||
| 14 | + end = jQuery(tinyMCE.activeEditor.selection.getEnd()).closest('p'); | ||
| 15 | + | ||
| 16 | + //text = start.parent().children(); | ||
| 17 | + text = jQuery('#article_body_ifr').contents().find('*'); | ||
| 18 | + selection = text.slice(text.index(start), text.index(end)+1); | ||
| 19 | + | ||
| 20 | + hasTag = false; | ||
| 21 | + selection.each(function(key, value) { | ||
| 22 | + commentTag = jQuery(value).closest('.article_comments'); | ||
| 23 | + if(commentTag.length) { | ||
| 24 | + commentTag.children().unwrap('<div class=\"article_comments\"/>'); | ||
| 25 | + hasTag = true; | ||
| 26 | + } | ||
| 27 | + }); | ||
| 28 | + | ||
| 29 | + if(!hasTag) { | ||
| 30 | + tags = start.siblings().add(start); | ||
| 31 | + tags = tags.slice(tags.index(start), tags.index(end)>=0?tags.index(end)+1:tags.index(start)+1); | ||
| 32 | + tags.wrapAll('<div class=\"macro article_comments\" data-macro=\"display_comments\" data-macro-group_id=\"'+getNextGroupId()+'\"/>'); | ||
| 33 | + | ||
| 34 | + contents = jQuery('#article_body_ifr').contents(); | ||
| 35 | + lastP = contents.find('p.article_comments_last_paragraph'); | ||
| 36 | + if(lastP.text().trim().length > 0) { | ||
| 37 | + lastP.removeClass('article_comments_last_paragraph'); | ||
| 38 | + } else { | ||
| 39 | + lastP.remove(); | ||
| 40 | + } | ||
| 41 | + lastDiv = contents.find('div.article_comments').last(); | ||
| 42 | + if(lastDiv.next().length==0) { | ||
| 43 | + lastDiv.after("<p class='article_comments_last_paragraph'> </p>"); | ||
| 44 | + } | ||
| 45 | + } | ||
| 46 | +} | ||
| 47 | + |
1.66 KB
plugins/comment_group_macro/test/functional/comment_group_macro_plugin_profile_controller_test.rb
0 → 100644
| @@ -0,0 +1,38 @@ | @@ -0,0 +1,38 @@ | ||
| 1 | +require File.dirname(__FILE__) + '/../../../../test/test_helper' | ||
| 2 | +require File.dirname(__FILE__) + '/../../controllers/profile/comment_group_macro_plugin_profile_controller' | ||
| 3 | + | ||
| 4 | +# Re-raise errors caught by the controller. | ||
| 5 | +class CommentGroupMacroPluginProfileController; def rescue_action(e) raise e end; end | ||
| 6 | + | ||
| 7 | +class CommentGroupMacroPluginProfileControllerTest < ActionController::TestCase | ||
| 8 | + | ||
| 9 | + def setup | ||
| 10 | + @controller = CommentGroupMacroPluginProfileController.new | ||
| 11 | + @request = ActionController::TestRequest.new | ||
| 12 | + @response = ActionController::TestResponse.new | ||
| 13 | + | ||
| 14 | + @profile = create_user('testuser').person | ||
| 15 | + @article = profile.articles.build(:name => 'test') | ||
| 16 | + @article.save! | ||
| 17 | + end | ||
| 18 | + attr_reader :article | ||
| 19 | + attr_reader :profile | ||
| 20 | + | ||
| 21 | + should 'be able to show group comments' do | ||
| 22 | + comment = fast_create(Comment, :source_id => article, :author_id => profile, :title => 'a comment', :body => 'lalala', :group_id => 0) | ||
| 23 | + xhr :get, :view_comments, :profile => @profile.identifier, :article_id => article.id, :group_id => 0 | ||
| 24 | + assert_template 'comment/_comment.rhtml' | ||
| 25 | + assert_match /comments_list_group_0/, @response.body | ||
| 26 | + assert_match /\"comment-count-0\", \"1\"/, @response.body | ||
| 27 | + end | ||
| 28 | + | ||
| 29 | + should 'do not show global comments' do | ||
| 30 | + comment = fast_create(Comment, :source_id => article, :author_id => profile, :title => 'global comment', :body => 'global', :group_id => nil) | ||
| 31 | + comment = fast_create(Comment, :source_id => article, :author_id => profile, :title => 'a comment', :body => 'lalala', :group_id => 0) | ||
| 32 | + xhr :get, :view_comments, :profile => @profile.identifier, :article_id => article.id, :group_id => 0 | ||
| 33 | + assert_template 'comment/_comment.rhtml' | ||
| 34 | + assert_match /comments_list_group_0/, @response.body | ||
| 35 | + assert_match /\"comment-count-0\", \"1\"/, @response.body | ||
| 36 | + end | ||
| 37 | + | ||
| 38 | +end |
plugins/comment_group_macro/test/unit/comment_group_macro_plugin_test.rb
0 → 100644
| @@ -0,0 +1,81 @@ | @@ -0,0 +1,81 @@ | ||
| 1 | +require File.dirname(__FILE__) + '/../../../../test/test_helper' | ||
| 2 | + | ||
| 3 | +class CommentGroupMacroPluginTest < ActiveSupport::TestCase | ||
| 4 | + | ||
| 5 | + include Noosfero::Plugin::HotSpot | ||
| 6 | + | ||
| 7 | + def setup | ||
| 8 | + @environment = Environment.default | ||
| 9 | + end | ||
| 10 | + | ||
| 11 | + attr_reader :environment | ||
| 12 | + | ||
| 13 | + should 'register comment_group_macro in environment' do | ||
| 14 | + Environment.macros = {} | ||
| 15 | + Environment.macros[environment.id] = {} | ||
| 16 | + macros = Environment.macros[environment.id] | ||
| 17 | + context = mock() | ||
| 18 | + context.stubs(:environment).returns(environment) | ||
| 19 | + plugin = CommentGroupMacroPlugin.new(context) | ||
| 20 | + assert_equal ['macro_display_comments'], macros.keys | ||
| 21 | + end | ||
| 22 | + | ||
| 23 | + should 'load_comments returns all the comments wihout group of an article passed as parameter' do | ||
| 24 | + article = fast_create(Article) | ||
| 25 | + c1 = fast_create(Comment, :source_id => article.id, :group_id => 1) | ||
| 26 | + c2 = fast_create(Comment, :source_id => article.id) | ||
| 27 | + c3 = fast_create(Comment, :source_id => article.id) | ||
| 28 | + | ||
| 29 | + plugin = CommentGroupMacroPlugin.new | ||
| 30 | + assert_equal [], [c2, c3] - plugin.load_comments(article) | ||
| 31 | + assert_equal [], plugin.load_comments(article) - [c2, c3] | ||
| 32 | + end | ||
| 33 | + | ||
| 34 | + should 'load_comments not returns spam comments' do | ||
| 35 | + article = fast_create(Article) | ||
| 36 | + c1 = fast_create(Comment, :source_id => article.id, :group_id => 1) | ||
| 37 | + c2 = fast_create(Comment, :source_id => article.id) | ||
| 38 | + c3 = fast_create(Comment, :source_id => article.id, :spam => true) | ||
| 39 | + | ||
| 40 | + plugin = CommentGroupMacroPlugin.new | ||
| 41 | + assert_equal [], [c2] - plugin.load_comments(article) | ||
| 42 | + assert_equal [], plugin.load_comments(article) - [c2] | ||
| 43 | + end | ||
| 44 | + | ||
| 45 | + should 'load_comments returns only root comments of article' do | ||
| 46 | + article = fast_create(Article) | ||
| 47 | + c1 = fast_create(Comment, :source_id => article.id, :group_id => 1) | ||
| 48 | + c2 = fast_create(Comment, :source_id => article.id) | ||
| 49 | + c3 = fast_create(Comment, :source_id => article.id, :reply_of_id => c2.id) | ||
| 50 | + | ||
| 51 | + plugin = CommentGroupMacroPlugin.new | ||
| 52 | + assert_equal [], [c2] - plugin.load_comments(article) | ||
| 53 | + assert_equal [], plugin.load_comments(article) - [c2] | ||
| 54 | + end | ||
| 55 | + | ||
| 56 | + should 'params of macro display comments configuration be an empty array' do | ||
| 57 | + plugin = CommentGroupMacroPlugin.new | ||
| 58 | + assert_equal [], plugin.config_macro_display_comments[:params] | ||
| 59 | + end | ||
| 60 | + | ||
| 61 | + should 'skip_dialog of macro display comments configuration be true' do | ||
| 62 | + plugin = CommentGroupMacroPlugin.new | ||
| 63 | + assert plugin.config_macro_display_comments[:skip_dialog] | ||
| 64 | + end | ||
| 65 | + | ||
| 66 | + should 'generator of macro display comments configuration be the makeCommentable function' do | ||
| 67 | + plugin = CommentGroupMacroPlugin.new | ||
| 68 | + assert_equal 'makeCommentable();', plugin.config_macro_display_comments[:generator] | ||
| 69 | + end | ||
| 70 | + | ||
| 71 | + should 'js_files of macro display comments configuration return comment_group.js' do | ||
| 72 | + plugin = CommentGroupMacroPlugin.new | ||
| 73 | + assert_equal 'comment_group.js', plugin.config_macro_display_comments[:js_files] | ||
| 74 | + end | ||
| 75 | + | ||
| 76 | + should 'css_files of macro display comments configuration return comment_group.css' do | ||
| 77 | + plugin = CommentGroupMacroPlugin.new | ||
| 78 | + assert_equal 'comment_group.css', plugin.config_macro_display_comments[:css_files] | ||
| 79 | + end | ||
| 80 | + | ||
| 81 | +end |
| @@ -0,0 +1,47 @@ | @@ -0,0 +1,47 @@ | ||
| 1 | +<div class="comments"> | ||
| 2 | + <div class="comment_group_<%= group_id %>" style="float: left"> | ||
| 3 | + <div style="float: left"> | ||
| 4 | + <%= link_to_remote(image_tag("/plugins/comment_group_macro/images/comments.gif"), | ||
| 5 | + :url => { :controller => 'comment_group_macro_plugin_profile', :action => 'view_comments', :group_id => group_id, :article_id => article_id}, | ||
| 6 | + :loaded => visual_effect(:highlight, "comments_list_group_#{group_id}"), | ||
| 7 | + :method => :post, | ||
| 8 | + :condition => "!groupVisible(#{group_id})", | ||
| 9 | + :complete => "jQuery('div.comment-group-loading-#{group_id}').removeClass('comment-button-loading')")%> | ||
| 10 | + </div> | ||
| 11 | + <!-- FIXME: css file --> | ||
| 12 | + <div id="comments_group_count_<%= group_id %>" style="float: right; vertical-align: middle; padding-left: 3px; padding-right: 5px; color: #5AC1FC"><span id="comment-count-<%= group_id %>" class='comment-count'><%= count %></span></div> | ||
| 13 | + | ||
| 14 | + </div> | ||
| 15 | + | ||
| 16 | + <div> | ||
| 17 | + <%= inner_html %> | ||
| 18 | + </div> | ||
| 19 | + | ||
| 20 | + <div class="comment-group-loading-<%= group_id %>"/> | ||
| 21 | + | ||
| 22 | + <div class="comments_list_toggle_group_<%= group_id %>" style="display:none"> | ||
| 23 | + <div class="article-comments-list"> | ||
| 24 | + <div id="comments_list_group_<%= group_id %>"></div> | ||
| 25 | + </div> | ||
| 26 | + | ||
| 27 | + <div id="page-comment-form-<%= group_id %>" class='post_comment_box closed'><%= render :partial => 'comment/comment_form', :locals => {:comment => Comment.new, :display_link => true, :cancel_triggers_hide => true, :group_id => group_id}%></div> | ||
| 28 | + | ||
| 29 | + </div> | ||
| 30 | + | ||
| 31 | + <script type="text/javascript"> | ||
| 32 | + function groupVisible(group) { | ||
| 33 | + return jQuery('div.comments_list_toggle_group_'+group).is(':visible'); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + (function($) { | ||
| 37 | + var button = $('div.comment_group_<%= group_id %> a'); | ||
| 38 | + button.click(function() { | ||
| 39 | + var div = $('div.comments_list_toggle_group_<%= group_id %>') | ||
| 40 | + if(!div.is(':visible')) | ||
| 41 | + $('div.comment-group-loading-<%= group_id %>').addClass('comment-button-loading'); | ||
| 42 | + div.toggle('fast'); | ||
| 43 | + }); | ||
| 44 | + })(jQuery) | ||
| 45 | + </script> | ||
| 46 | +</div> | ||
| 47 | + |
plugins/send_email/lib/send_email_plugin.rb
| @@ -12,12 +12,14 @@ class SendEmailPlugin < Noosfero::Plugin | @@ -12,12 +12,14 @@ class SendEmailPlugin < Noosfero::Plugin | ||
| 12 | true | 12 | true |
| 13 | end | 13 | end |
| 14 | 14 | ||
| 15 | - def parse_content(raw_content) | 15 | + def parse_content(args) |
| 16 | + raw_content = args[:html] | ||
| 16 | if context.profile | 17 | if context.profile |
| 17 | raw_content.gsub(/\{sendemail\}/, "/profile/#{context.profile.identifier}/plugins/send_email/deliver") | 18 | raw_content.gsub(/\{sendemail\}/, "/profile/#{context.profile.identifier}/plugins/send_email/deliver") |
| 18 | else | 19 | else |
| 19 | raw_content.gsub(/\{sendemail\}/, '/plugin/send_email/deliver') | 20 | raw_content.gsub(/\{sendemail\}/, '/plugin/send_email/deliver') |
| 20 | end | 21 | end |
| 22 | + args.clone.merge({:html => raw_content}) | ||
| 21 | end | 23 | end |
| 22 | 24 | ||
| 23 | end | 25 | end |
test/functional/content_viewer_controller_test.rb
| @@ -1229,4 +1229,118 @@ class ContentViewerControllerTest < ActionController::TestCase | @@ -1229,4 +1229,118 @@ class ContentViewerControllerTest < ActionController::TestCase | ||
| 1229 | assert_equal 1, assigns(:comments_count) | 1229 | assert_equal 1, assigns(:comments_count) |
| 1230 | end | 1230 | end |
| 1231 | 1231 | ||
| 1232 | + should 'add extra content on comment form from plugins' do | ||
| 1233 | + class Plugin1 < Noosfero::Plugin | ||
| 1234 | + def comment_form_extra_contents(args) | ||
| 1235 | + lambda { | ||
| 1236 | + hidden_field_tag('comment[some_field_id]', 1) | ||
| 1237 | + } | ||
| 1238 | + end | ||
| 1239 | + end | ||
| 1240 | + class Plugin2 < Noosfero::Plugin | ||
| 1241 | + def comment_form_extra_contents(args) | ||
| 1242 | + lambda { | ||
| 1243 | + hidden_field_tag('comment[another_field_id]', 1) | ||
| 1244 | + } | ||
| 1245 | + end | ||
| 1246 | + end | ||
| 1247 | + | ||
| 1248 | + Environment.default.enable_plugin(Plugin1.name) | ||
| 1249 | + Environment.default.enable_plugin(Plugin2.name) | ||
| 1250 | + | ||
| 1251 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | ||
| 1252 | + | ||
| 1253 | + get :view_page, :profile => profile.identifier, :page => [ 'myarticle' ] | ||
| 1254 | + | ||
| 1255 | + assert_tag :tag => 'input', :attributes => {:name => 'comment[some_field_id]', :type => 'hidden'} | ||
| 1256 | + assert_tag :tag => 'input', :attributes => {:name => 'comment[another_field_id]', :type => 'hidden'} | ||
| 1257 | + end | ||
| 1258 | + | ||
| 1259 | + should 'collect comments as plugin definition' do | ||
| 1260 | + class Plugin1 < Noosfero::Plugin | ||
| 1261 | + def load_comments(page) | ||
| 1262 | + [page.comments.find(4)] | ||
| 1263 | + end | ||
| 1264 | + end | ||
| 1265 | + Environment.default.enable_plugin(Plugin1.name) | ||
| 1266 | + Comment.delete_all | ||
| 1267 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | ||
| 1268 | + page.comments.build(:author => profile, :title => 'hi', :body => 'hello 1' ).save! | ||
| 1269 | + page.comments.build(:author => profile, :title => 'hi', :body => 'hello 2' ).save! | ||
| 1270 | + page.comments.build(:author => profile, :title => 'hi', :body => 'hello 3' ).save! | ||
| 1271 | + c = page.comments.build(:author => profile, :title => 'hi', :body => 'hello 4' ) | ||
| 1272 | + c.save! | ||
| 1273 | + | ||
| 1274 | + | ||
| 1275 | + get :view_page, :profile => profile.identifier, :page => [ 'myarticle' ] | ||
| 1276 | + | ||
| 1277 | + assert_equal [c], assigns(:comments) | ||
| 1278 | + end | ||
| 1279 | + | ||
| 1280 | + should 'not be a problem if loaded comments of plugins not be an array' do | ||
| 1281 | + class Plugin1 < Noosfero::Plugin | ||
| 1282 | + def load_comments(page) | ||
| 1283 | + page.comments.find(4) | ||
| 1284 | + end | ||
| 1285 | + end | ||
| 1286 | + Environment.default.enable_plugin(Plugin1.name) | ||
| 1287 | + Comment.delete_all | ||
| 1288 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | ||
| 1289 | + page.comments.build(:author => profile, :title => 'hi', :body => 'hello 1' ).save! | ||
| 1290 | + page.comments.build(:author => profile, :title => 'hi', :body => 'hello 2' ).save! | ||
| 1291 | + page.comments.build(:author => profile, :title => 'hi', :body => 'hello 3' ).save! | ||
| 1292 | + c = page.comments.build(:author => profile, :title => 'hi', :body => 'hello 4' ) | ||
| 1293 | + c.save! | ||
| 1294 | + | ||
| 1295 | + | ||
| 1296 | + get :view_page, :profile => profile.identifier, :page => [ 'myarticle' ] | ||
| 1297 | + | ||
| 1298 | + assert_equal [c], assigns(:comments) | ||
| 1299 | + end | ||
| 1300 | + | ||
| 1301 | + | ||
| 1302 | + should 'take in consideration only the first plugin comments definition' do | ||
| 1303 | + class Plugin1 < Noosfero::Plugin | ||
| 1304 | + def load_comments(page) | ||
| 1305 | + page.comments.first | ||
| 1306 | + end | ||
| 1307 | + end | ||
| 1308 | + class Plugin2 < Noosfero::Plugin | ||
| 1309 | + def load_comments(page) | ||
| 1310 | + page.comments.last | ||
| 1311 | + end | ||
| 1312 | + end | ||
| 1313 | + Environment.default.enable_plugin(Plugin1.name) | ||
| 1314 | + Environment.default.enable_plugin(Plugin2.name) | ||
| 1315 | + | ||
| 1316 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | ||
| 1317 | + c1 = page.comments.build(:author => profile, :title => 'hi', :body => 'hello 1' ) | ||
| 1318 | + c1.save! | ||
| 1319 | + page.comments.build(:author => profile, :title => 'hi', :body => 'hello 2' ).save! | ||
| 1320 | + page.comments.build(:author => profile, :title => 'hi', :body => 'hello 3' ).save! | ||
| 1321 | + c2 = page.comments.build(:author => profile, :title => 'hi', :body => 'hello 4' ) | ||
| 1322 | + c2.save! | ||
| 1323 | + | ||
| 1324 | + get :view_page, :profile => profile.identifier, :page => [ 'myarticle' ] | ||
| 1325 | + | ||
| 1326 | + assert_equal [c1], assigns(:comments) | ||
| 1327 | + end | ||
| 1328 | + | ||
| 1329 | + should 'empty array of comments collected by plugin make the comments variable be an empty array' do | ||
| 1330 | + class Plugin1 < Noosfero::Plugin | ||
| 1331 | + def load_comments(page) | ||
| 1332 | + [] | ||
| 1333 | + end | ||
| 1334 | + end | ||
| 1335 | + Environment.default.enable_plugin(Plugin1.name) | ||
| 1336 | + | ||
| 1337 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | ||
| 1338 | + page.comments.build(:author => profile, :title => 'hi', :body => 'hello 1' ).save! | ||
| 1339 | + page.comments.build(:author => profile, :title => 'hi', :body => 'hello 2' ).save! | ||
| 1340 | + | ||
| 1341 | + | ||
| 1342 | + get :view_page, :profile => profile.identifier, :page => [ 'myarticle' ] | ||
| 1343 | + | ||
| 1344 | + assert_equal [], assigns(:comments) | ||
| 1345 | + end | ||
| 1232 | end | 1346 | end |
test/unit/application_helper_test.rb
| @@ -3,6 +3,7 @@ require File.dirname(__FILE__) + '/../test_helper' | @@ -3,6 +3,7 @@ require File.dirname(__FILE__) + '/../test_helper' | ||
| 3 | class ApplicationHelperTest < ActiveSupport::TestCase | 3 | class ApplicationHelperTest < ActiveSupport::TestCase |
| 4 | 4 | ||
| 5 | include ApplicationHelper | 5 | include ApplicationHelper |
| 6 | + include Noosfero::Plugin::HotSpot | ||
| 6 | 7 | ||
| 7 | def setup | 8 | def setup |
| 8 | self.stubs(:session).returns({}) | 9 | self.stubs(:session).returns({}) |
| @@ -657,6 +658,45 @@ class ApplicationHelperTest < ActiveSupport::TestCase | @@ -657,6 +658,45 @@ class ApplicationHelperTest < ActiveSupport::TestCase | ||
| 657 | assert_not_nil add_zoom_to_images | 658 | assert_not_nil add_zoom_to_images |
| 658 | end | 659 | end |
| 659 | 660 | ||
| 661 | + should 'parse macros' do | ||
| 662 | + class Plugin1 < Noosfero::Plugin | ||
| 663 | + def macro_test1(params, inner_html, source) | ||
| 664 | + 'Test1' | ||
| 665 | + end | ||
| 666 | + def macro_test2(params, inner_html, source) | ||
| 667 | + 'Test2' | ||
| 668 | + end | ||
| 669 | + | ||
| 670 | + def macro_methods | ||
| 671 | + ['macro_test1', 'macro_test2'] | ||
| 672 | + end | ||
| 673 | + end | ||
| 674 | + | ||
| 675 | + @environment = Environment.default | ||
| 676 | + Environment.macros = {@environment.id => {}} | ||
| 677 | + context = mock() | ||
| 678 | + context.stubs(:environment).returns(@environment) | ||
| 679 | + Plugin1.new(context) | ||
| 680 | + html = ' | ||
| 681 | + <div class="macro nonEdit" data-macro="test1" data-macro-param="123"></div> | ||
| 682 | + <div class="macro nonEdit" data-macro="test2"></div> | ||
| 683 | + <div class="macro nonEdit" data-macro="unexistent" data-macro-param="987"></div> | ||
| 684 | + ' | ||
| 685 | + parsed_html = convert_macro(html, mock()) | ||
| 686 | + parsed_divs = Hpricot(parsed_html).search('div') | ||
| 687 | + expected_divs = Hpricot(' | ||
| 688 | + <div data-macro="test1" class="parsed-macro test1">Test1</div> | ||
| 689 | + <div data-macro="test2" class="parsed-macro test2">Test2</div> | ||
| 690 | + <div data-macro="unexistent" class="failed-macro unexistent">Unsupported macro unexistent!</div> | ||
| 691 | + ').search('div') | ||
| 692 | + | ||
| 693 | + # comparing div attributes between parsed and expected html | ||
| 694 | + parsed_divs.each_with_index do |div, i| | ||
| 695 | + assert_equal expected_divs[i].attributes.to_hash, div.attributes.to_hash | ||
| 696 | + assert_equal expected_divs[i].inner_text, div.inner_text | ||
| 697 | + end | ||
| 698 | + end | ||
| 699 | + | ||
| 660 | protected | 700 | protected |
| 661 | include NoosferoTestHelper | 701 | include NoosferoTestHelper |
| 662 | 702 |
test/unit/comment_test.rb
| @@ -571,6 +571,21 @@ class CommentTest < ActiveSupport::TestCase | @@ -571,6 +571,21 @@ class CommentTest < ActiveSupport::TestCase | ||
| 571 | SpammerLogger.clean_log | 571 | SpammerLogger.clean_log |
| 572 | end | 572 | end |
| 573 | 573 | ||
| 574 | + should 'count a thread of comments' do | ||
| 575 | + Comment.delete_all | ||
| 576 | + comments = [] | ||
| 577 | + comments.push(create_comment) | ||
| 578 | + c1 = create_comment | ||
| 579 | + comments.push(c1) | ||
| 580 | + create_comment(:reply_of_id => c1.id) | ||
| 581 | + create_comment(:reply_of_id => c1.id) | ||
| 582 | + c2 = create_comment | ||
| 583 | + comments.push(c2) | ||
| 584 | + create_comment(:reply_of_id => c2.id) | ||
| 585 | + | ||
| 586 | + assert_equal 6, Comment.count_thread(comments) | ||
| 587 | + end | ||
| 588 | + | ||
| 574 | private | 589 | private |
| 575 | 590 | ||
| 576 | def create_comment(args = {}) | 591 | def create_comment(args = {}) |
| @@ -0,0 +1,124 @@ | @@ -0,0 +1,124 @@ | ||
| 1 | +require File.dirname(__FILE__) + '/../test_helper' | ||
| 2 | + | ||
| 3 | +class MacrosHelperTest < ActiveSupport::TestCase | ||
| 4 | + include MacrosHelper | ||
| 5 | + include ApplicationHelper | ||
| 6 | + include ActionView::Helpers::FormOptionsHelper | ||
| 7 | + include ActionView::Helpers::FormTagHelper | ||
| 8 | + include ActionView::Helpers::TagHelper | ||
| 9 | + | ||
| 10 | + CONFIG = { | ||
| 11 | + :params => [ | ||
| 12 | + { :name => :identifier, :type => 'text'}, | ||
| 13 | + { :name => :size, :type => 'select', | ||
| 14 | + :values => [ | ||
| 15 | + [_('Big'), :big], | ||
| 16 | + [_('Icon'), :icon], | ||
| 17 | + [_('Minor'), :minor], | ||
| 18 | + [_('Portrait'), :portrait], | ||
| 19 | + [_('Thumb'), :thumb] | ||
| 20 | + ], | ||
| 21 | + :default => :portrait | ||
| 22 | + } | ||
| 23 | + ], | ||
| 24 | + :title => _('Profile Image Link') | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + should 'generate html for macro configuration' do | ||
| 28 | + @environment = Environment.default | ||
| 29 | + Environment.macros = {} | ||
| 30 | + macros = Environment.macros[@environment.id] = {} | ||
| 31 | + plugin_instance = mock | ||
| 32 | + plugin_instance.stubs('config_macro_example').returns(CONFIG) | ||
| 33 | + macros['macro_example'] = plugin_instance | ||
| 34 | + html = macro_configuration_dialog('macro_example') | ||
| 35 | + assert_tag_in_string html, :tag => 'label', :content => _('Identifier') | ||
| 36 | + assert_tag_in_string html, :tag => 'input', :attributes => {:name => 'identifier'} | ||
| 37 | + assert_tag_in_string html, :tag => 'label', :content => 'size'.humanize | ||
| 38 | + assert_tag_in_string html, :tag => 'select', :attributes => {:name => 'size'}, :descendant => {:tag => 'option', :attributes => {:value => 'big'}, :content => _('Big')} | ||
| 39 | + assert_tag_in_string html, :tag => 'select', :attributes => {:name => 'size'}, :descendant => {:tag => 'option', :attributes => {:value => 'icon'}, :content => _('Icon')} | ||
| 40 | + assert_tag_in_string html, :tag => 'select', :attributes => {:name => 'size'}, :descendant => {:tag => 'option', :attributes => {:value => 'minor'}, :content => _('Minor')} | ||
| 41 | + assert_tag_in_string html, :tag => 'select', :attributes => {:name => 'size'}, :descendant => {:tag => 'option', :attributes => {:value => 'portrait', :selected => true}, :content => _('Portrait')} | ||
| 42 | + assert_tag_in_string html, :tag => 'select', :attributes => {:name => 'size'}, :descendant => {:tag => 'option', :attributes => {:value => 'thumb'}, :content => _('Thumb')} | ||
| 43 | + end | ||
| 44 | + | ||
| 45 | + should 'get macro title' do | ||
| 46 | + @environment = Environment.default | ||
| 47 | + Environment.macros = {} | ||
| 48 | + macros = Environment.macros[@environment.id] = {} | ||
| 49 | + plugin_instance = mock | ||
| 50 | + plugin_instance.stubs('config_macro_example').returns(CONFIG) | ||
| 51 | + macros['macro_example'] = plugin_instance | ||
| 52 | + title = macro_title('macro_example') | ||
| 53 | + assert _('Profile Image Link'), title | ||
| 54 | + end | ||
| 55 | + | ||
| 56 | + should 'get only macros in menu' do | ||
| 57 | + @environment = Environment.default | ||
| 58 | + Environment.macros = {} | ||
| 59 | + macros = Environment.macros[@environment.id] = {} | ||
| 60 | + plugin_instance = mock | ||
| 61 | + plugin_instance.stubs('config_macro_example').returns({}) | ||
| 62 | + macros['macro_example'] = plugin_instance | ||
| 63 | + plugin_instance_other = mock | ||
| 64 | + plugin_instance_other.stubs('config_macro_example_other').returns({:icon_path => 'icon.png'}) | ||
| 65 | + macros['macro_example_other'] = plugin_instance_other | ||
| 66 | + assert_equal [plugin_instance], macros_in_menu.values | ||
| 67 | + end | ||
| 68 | + | ||
| 69 | + should 'get only macros with buttons' do | ||
| 70 | + @environment = Environment.default | ||
| 71 | + Environment.macros = {} | ||
| 72 | + macros = Environment.macros[@environment.id] = {} | ||
| 73 | + plugin_instance = mock | ||
| 74 | + plugin_instance.stubs('config_macro_example').returns({}) | ||
| 75 | + macros['macro_example'] = plugin_instance | ||
| 76 | + plugin_instance_other = mock | ||
| 77 | + plugin_instance_other.stubs('config_macro_example_other').returns({:icon_path => 'icon.png'}) | ||
| 78 | + macros['macro_example_other'] = plugin_instance_other | ||
| 79 | + assert_equal [plugin_instance_other], macros_with_buttons.values | ||
| 80 | + end | ||
| 81 | + | ||
| 82 | + should 'skip macro config dialog and call generator directly' do | ||
| 83 | + @environment = Environment.default | ||
| 84 | + Environment.macros = {} | ||
| 85 | + macros = Environment.macros[@environment.id] = {} | ||
| 86 | + plugin_instance = mock | ||
| 87 | + plugin_instance.stubs('config_macro_example').returns({:skip_dialog => true, :generator => '', :params => [] }) | ||
| 88 | + macros['macro_example'] = plugin_instance | ||
| 89 | + assert_equal 'function(){}', generate_macro_config_dialog('macro_example') | ||
| 90 | + end | ||
| 91 | + | ||
| 92 | + should 'include js files' do | ||
| 93 | + @environment = Environment.default | ||
| 94 | + Environment.macros = {} | ||
| 95 | + macros = Environment.macros[@environment.id] = {} | ||
| 96 | + plugin_instance = mock | ||
| 97 | + plugin_instance.stubs('config_macro_example').returns({:js_files => 'macro.js' }) | ||
| 98 | + plugin_instance.class.stubs(:public_path).with('macro.js').returns('macro.js') | ||
| 99 | + macros['macro_example'] = plugin_instance | ||
| 100 | + assert_equal '<script src="/javascripts/macro.js" type="text/javascript"></script>', include_macro_js_files | ||
| 101 | + end | ||
| 102 | + | ||
| 103 | + should 'get macro css files' do | ||
| 104 | + @environment = Environment.default | ||
| 105 | + Environment.macros = {} | ||
| 106 | + macros = Environment.macros[@environment.id] = {} | ||
| 107 | + plugin_instance = mock | ||
| 108 | + plugin_instance.stubs('config_macro_example').returns({:css_files => 'macro.css' }) | ||
| 109 | + plugin_instance.class.stubs(:public_path).with('macro.css').returns('macro.css') | ||
| 110 | + macros['macro_example'] = plugin_instance | ||
| 111 | + assert_equal 'macro.css', macro_css_files | ||
| 112 | + end | ||
| 113 | + | ||
| 114 | + should 'get macro specific generator' do | ||
| 115 | + @environment = Environment.default | ||
| 116 | + Environment.macros = {} | ||
| 117 | + macros = Environment.macros[@environment.id] = {} | ||
| 118 | + plugin_instance = mock | ||
| 119 | + plugin_instance.stubs('config_macro_example').returns({:generator => 'macro_generator' }) | ||
| 120 | + macros['macro_example'] = plugin_instance | ||
| 121 | + assert_equal 'macro_generator', macro_generator('macro_example') | ||
| 122 | + end | ||
| 123 | + | ||
| 124 | +end |
test/unit/plugin_manager_test.rb
| @@ -2,22 +2,12 @@ require File.dirname(__FILE__) + '/../test_helper' | @@ -2,22 +2,12 @@ require File.dirname(__FILE__) + '/../test_helper' | ||
| 2 | 2 | ||
| 3 | class PluginManagerTest < ActiveSupport::TestCase | 3 | class PluginManagerTest < ActiveSupport::TestCase |
| 4 | 4 | ||
| 5 | + include Noosfero::Plugin::HotSpot | ||
| 6 | + | ||
| 5 | def setup | 7 | def setup |
| 6 | @environment = Environment.default | 8 | @environment = Environment.default |
| 7 | - @controller = mock() | ||
| 8 | - @controller.stubs(:profile).returns() | ||
| 9 | - @controller.stubs(:request).returns() | ||
| 10 | - @controller.stubs(:response).returns() | ||
| 11 | - @controller.stubs(:params).returns() | ||
| 12 | - @manager = Noosfero::Plugin::Manager.new(@environment, @controller) | ||
| 13 | end | 9 | end |
| 14 | attr_reader :environment | 10 | attr_reader :environment |
| 15 | - attr_reader :manager | ||
| 16 | - | ||
| 17 | - should 'give access to environment and context' do | ||
| 18 | - assert_same @environment, @manager.environment | ||
| 19 | - assert_same @controller, @manager.context | ||
| 20 | - end | ||
| 21 | 11 | ||
| 22 | should 'return the intersection between environment\'s enabled plugins and system available plugins' do | 12 | should 'return the intersection between environment\'s enabled plugins and system available plugins' do |
| 23 | class Plugin1 < Noosfero::Plugin; end; | 13 | class Plugin1 < Noosfero::Plugin; end; |
| @@ -26,8 +16,8 @@ class PluginManagerTest < ActiveSupport::TestCase | @@ -26,8 +16,8 @@ class PluginManagerTest < ActiveSupport::TestCase | ||
| 26 | class Plugin4 < Noosfero::Plugin; end; | 16 | class Plugin4 < Noosfero::Plugin; end; |
| 27 | environment.stubs(:enabled_plugins).returns([Plugin1.to_s, Plugin2.to_s, Plugin4.to_s]) | 17 | environment.stubs(:enabled_plugins).returns([Plugin1.to_s, Plugin2.to_s, Plugin4.to_s]) |
| 28 | Noosfero::Plugin.stubs(:all).returns([Plugin1.to_s, Plugin3.to_s, Plugin4.to_s]) | 18 | Noosfero::Plugin.stubs(:all).returns([Plugin1.to_s, Plugin3.to_s, Plugin4.to_s]) |
| 29 | - plugins = manager.enabled_plugins.map { |instance| instance.class.to_s } | ||
| 30 | - assert_equal [Plugin1.to_s, Plugin4.to_s], plugins | 19 | + results = plugins.enabled_plugins.map { |instance| instance.class.to_s } |
| 20 | + assert_equal [Plugin1.to_s, Plugin4.to_s], results | ||
| 31 | end | 21 | end |
| 32 | 22 | ||
| 33 | should 'map events to registered plugins' do | 23 | should 'map events to registered plugins' do |
| @@ -55,8 +45,62 @@ class PluginManagerTest < ActiveSupport::TestCase | @@ -55,8 +45,62 @@ class PluginManagerTest < ActiveSupport::TestCase | ||
| 55 | p1 = Plugin1.new | 45 | p1 = Plugin1.new |
| 56 | p2 = Plugin2.new | 46 | p2 = Plugin2.new |
| 57 | 47 | ||
| 58 | - assert_equal [p1.random_event, p2.random_event], manager.dispatch(:random_event) | 48 | + assert_equal [p1.random_event, p2.random_event], plugins.dispatch(:random_event) |
| 49 | + end | ||
| 50 | + | ||
| 51 | + should 'dispatch_first method returns the first plugin response if there is many plugins to responde the event' do | ||
| 52 | + | ||
| 53 | + class Plugin1 < Noosfero::Plugin | ||
| 54 | + def random_event | ||
| 55 | + 'Plugin 1 action.' | ||
| 56 | + end | ||
| 57 | + end | ||
| 58 | + | ||
| 59 | + class Plugin2 < Noosfero::Plugin | ||
| 60 | + def random_event | ||
| 61 | + 'Plugin 2 action.' | ||
| 62 | + end | ||
| 63 | + end | ||
| 64 | + | ||
| 65 | + class Plugin3 < Noosfero::Plugin | ||
| 66 | + def random_event | ||
| 67 | + 'Plugin 3 action.' | ||
| 68 | + end | ||
| 69 | + end | ||
| 70 | + | ||
| 71 | + environment.stubs(:enabled_plugins).returns([Plugin1.to_s, Plugin2.to_s, Plugin3.to_s]) | ||
| 72 | + p1 = Plugin1.new | ||
| 73 | + | ||
| 74 | + assert_equal p1.random_event, plugins.dispatch_first(:random_event) | ||
| 59 | end | 75 | end |
| 60 | 76 | ||
| 77 | + should 'dispatch_first method returns the first plugin response if there is many plugins to responde the event and the first one respond nil' do | ||
| 78 | + | ||
| 79 | + class Plugin1 < Noosfero::Plugin | ||
| 80 | + def random_event | ||
| 81 | + nil | ||
| 82 | + end | ||
| 83 | + end | ||
| 84 | + | ||
| 85 | + class Plugin2 < Noosfero::Plugin | ||
| 86 | + def random_event | ||
| 87 | + 'Plugin 2 action.' | ||
| 88 | + end | ||
| 89 | + end | ||
| 90 | + | ||
| 91 | + class Plugin3 < Noosfero::Plugin | ||
| 92 | + def random_event | ||
| 93 | + 'Plugin 3 action.' | ||
| 94 | + end | ||
| 95 | + end | ||
| 96 | + | ||
| 97 | + environment.stubs(:enabled_plugins).returns([Plugin1.to_s, Plugin2.to_s, Plugin3.to_s]) | ||
| 98 | + | ||
| 99 | + p2 = Plugin2.new | ||
| 100 | + | ||
| 101 | + assert_equal p2.random_event, plugins.dispatch_first(:random_event) | ||
| 102 | + end | ||
| 103 | + | ||
| 104 | + | ||
| 61 | end | 105 | end |
| 62 | 106 |
test/unit/plugin_test.rb
| @@ -7,6 +7,8 @@ class PluginTest < ActiveSupport::TestCase | @@ -7,6 +7,8 @@ class PluginTest < ActiveSupport::TestCase | ||
| 7 | end | 7 | end |
| 8 | attr_reader :environment | 8 | attr_reader :environment |
| 9 | 9 | ||
| 10 | + include Noosfero::Plugin::HotSpot | ||
| 11 | + | ||
| 10 | should 'keep the list of all loaded subclasses' do | 12 | should 'keep the list of all loaded subclasses' do |
| 11 | class Plugin1 < Noosfero::Plugin | 13 | class Plugin1 < Noosfero::Plugin |
| 12 | end | 14 | end |
| @@ -26,4 +28,59 @@ class PluginTest < ActiveSupport::TestCase | @@ -26,4 +28,59 @@ class PluginTest < ActiveSupport::TestCase | ||
| 26 | assert_equal({:controller => 'plugin_test/plugin1_admin', :action => 'index'}, Plugin1.admin_url) | 28 | assert_equal({:controller => 'plugin_test/plugin1_admin', :action => 'index'}, Plugin1.admin_url) |
| 27 | end | 29 | end |
| 28 | 30 | ||
| 31 | + should 'register its macros in the environment when instantiated' do | ||
| 32 | + class Plugin1 < Noosfero::Plugin | ||
| 33 | + def macro_example1(params, inner_html, source) | ||
| 34 | + end | ||
| 35 | + | ||
| 36 | + def example2(params, inner_html, source) | ||
| 37 | + end | ||
| 38 | + | ||
| 39 | + def not_macro | ||
| 40 | + end | ||
| 41 | + | ||
| 42 | + def macro_methods | ||
| 43 | + ['macro_example1', 'example2'] | ||
| 44 | + end | ||
| 45 | + end | ||
| 46 | + | ||
| 47 | + Environment.macros = {} | ||
| 48 | + Environment.macros[environment.id] = {} | ||
| 49 | + macros = Environment.macros[environment.id] | ||
| 50 | + context = mock() | ||
| 51 | + context.stubs(:environment).returns(environment) | ||
| 52 | + | ||
| 53 | + plugin_instance = Plugin1.new(context) | ||
| 54 | + | ||
| 55 | + assert_equal plugin_instance, macros['macro_example1'] | ||
| 56 | + assert_equal plugin_instance, macros['example2'] | ||
| 57 | + assert_nil macros['not_macro'] | ||
| 58 | + end | ||
| 59 | + | ||
| 60 | + should 'load_comments return nil by default' do | ||
| 61 | + | ||
| 62 | + class Plugin1 < Noosfero::Plugin; end; | ||
| 63 | + | ||
| 64 | + environment.stubs(:enabled_plugins).returns([Plugin1.to_s]) | ||
| 65 | + | ||
| 66 | + profile = fast_create(Profile, :name => 'test profile', :identifier => 'test_profile') | ||
| 67 | + a = fast_create(Article, :name => 'my article', :profile_id => profile.id) | ||
| 68 | + assert_nil plugins.dispatch_first(:load_comments, a) | ||
| 69 | + end | ||
| 70 | + | ||
| 71 | + should 'load_comments return the value defined by plugin' do | ||
| 72 | + | ||
| 73 | + class Plugin1 < Noosfero::Plugin | ||
| 74 | + def load_comments(page) | ||
| 75 | + 'some value' | ||
| 76 | + end | ||
| 77 | + end | ||
| 78 | + | ||
| 79 | + environment.stubs(:enabled_plugins).returns([Plugin1.to_s]) | ||
| 80 | + | ||
| 81 | + profile = fast_create(Profile, :name => 'test profile', :identifier => 'test_profile') | ||
| 82 | + a = fast_create(Article, :name => 'my article', :profile_id => profile.id) | ||
| 83 | + assert_equal 'some value', plugins.dispatch_first(:load_comments, a) | ||
| 84 | + end | ||
| 85 | + | ||
| 29 | end | 86 | end |