diff --git a/app/views/hooks/redmine_hearts/_view_layouts_base_content.html.erb b/app/views/hooks/redmine_hearts/_view_layouts_base_content.html.erb index 4fb0afd..96fbf96 100644 --- a/app/views/hooks/redmine_hearts/_view_layouts_base_content.html.erb +++ b/app/views/hooks/redmine_hearts/_view_layouts_base_content.html.erb @@ -1,5 +1,10 @@ <%# frozen_string_literal: true %> <% self.class.send :include, HeartsHelper %> +<% if ((controller.kind_of? NewsController) && (controller.action_name == 'index')) %> + <%= content_tag :div, :class => "news-heart-holder" do %> + <%= safe_join(multiple_heart_links_with_counters(@newss, User.current), '') %> + <% end if defined?(@newss) && @newss.any? %> +<% else %> <% case @heartable %> <% when Issue %> <%= heart_link_with_counter @heartable, User.current %> @@ -16,3 +21,4 @@ <% else %> <%= heart_link_with_counter @heartable, User.current %> <% end %> +<% end %> diff --git a/assets/javascripts/transplant_heart_link_with_counter.js b/assets/javascripts/transplant_heart_link_with_counter.js index 2c772e7..4c345f9 100644 --- a/assets/javascripts/transplant_heart_link_with_counter.js +++ b/assets/javascripts/transplant_heart_link_with_counter.js @@ -1,16 +1,21 @@ $(function() { "use strict"; - $(".journal-heart-holder > .heart-link-with-count").each(function () { - let link = this; + function getHeartableSubject(link) { let heartable_subject; - let num_insert = 0; $.each(link.classList, function () { let klass = this; if (/^([-a-z0-9]+-[0-9]+)-heart$/.test(klass)) { heartable_subject = RegExp.$1; } }); + return heartable_subject; + } + + $(".journal-heart-holder > .heart-link-with-count").each(function () { + let link = this; + let heartable_subject = getHeartableSubject(link); + let num_insert = 0; if (num_insert === 0) { let note_subject = heartable_subject.replace(/^[-a-z0-9]+-/, "journal-") + "-notes"; @@ -28,14 +33,8 @@ $(function() { }); $("#content > .heart-link-with-count, #main > .heart-link-with-count, .replies-heart-holder > .heart-link-with-count").each(function () { let link = this; - let heartable_subject; + let heartable_subject = getHeartableSubject(link); let num_insert = 0; - $.each(link.classList, function () { - let klass = this; - if (/^([-a-z0-9]+-[0-9]+)-heart$/.test(klass)) { - heartable_subject = RegExp.$1; - } - }); // insert immediate after the corresponding watcher links. if (num_insert === 0) { @@ -53,6 +52,27 @@ $(function() { num_insert += $(link).appendTo("#content > .contextual").length; } + if (num_insert === 0) { + console.debug("Failed to transplant : ." + heartable_subject + "-heart"); + } + }); + $(".news-heart-holder > .heart-link-with-count").each(function () { + let link = this; + let heartable_subject = getHeartableSubject(link); + let num_insert = 0; + + if (num_insert === 0) { + let newsLink = $(".news-article header a[href$=\"/" + heartable_subject.replace("-", "/") + "\"]"); + if (newsLink.length > 0) { + let context = $(".contextual", newsLink.parent().parent()); + if (content.length > 0) { + num_insert += $(link).appendTo(context).length; + } else { + num_insert += $('
').append(link).appendTo(newsLink.parent().parent()).length; + } + } + } + if (num_insert === 0) { console.debug("Failed to transplant : ." + heartable_subject + "-heart"); } diff --git a/assets/stylesheets/application.css b/assets/stylesheets/application.css index 80c8d86..34a281b 100644 --- a/assets/stylesheets/application.css +++ b/assets/stylesheets/application.css @@ -14,7 +14,8 @@ } #history .journal .contextual .heart-link-with-count .heart-link-label, - .message.reply .contextual .heart-link-with-count .heart-link-label { + .message.reply .contextual .heart-link-with-count .heart-link-label, + .news-article .contextual .heart-link-with-count .heart-link-label { display: none; } } @@ -37,6 +38,7 @@ .recent-heart-list .heartable-link { margin-right: 1em; } -.journal-heart-holder * { +.journal-heart-holder *, +.news-heart-holder * { display: none; } diff --git a/init.rb b/init.rb index c11d0d3..5b823f7 100644 --- a/init.rb +++ b/init.rb @@ -18,6 +18,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. require_dependency 'redmine_hearts/acts_as_heartable.rb' +require_dependency 'redmine_hearts/issue_query.rb' require_dependency 'redmine_hearts/redmine_heartable_patch.rb' require_dependency 'redmine_hearts/view_hook.rb' diff --git a/lib/redmine_hearts/issue_query.rb b/lib/redmine_hearts/issue_query.rb new file mode 100644 index 0000000..0f5dac1 --- /dev/null +++ b/lib/redmine_hearts/issue_query.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true +# +# Redmine Hearts plugin +# Copyright (C) @cat_in_136 +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software + +ActionDispatch::Callbacks.to_prepare do + IssueQuery.add_available_column( + QueryAssociationColumn.new(:hearts, :count, + :caption => :hearts_link_label, + :default_order => 'desc', + :sortable => lambda { + query_str = Heart.where(:heartable_type => Issue, :heartable_id => "9999"). + select("COUNT(*)"). + to_sql.sub("9999", "#{Issue.table_name}.id") + "(#{query_str})" + }) + ) +end diff --git a/lib/redmine_hearts/view_hook.rb b/lib/redmine_hearts/view_hook.rb index 8285645..9371ee6 100644 --- a/lib/redmine_hearts/view_hook.rb +++ b/lib/redmine_hearts/view_hook.rb @@ -59,6 +59,8 @@ def heartable_subject(controller) if model_klass && model_klass.included_modules.include?(Redmine::Acts::Heartable::InstanceMethods) subject = controller.instance_variable_get("@#{controller.controller_name.singularize}") end + elsif ((controller.kind_of? NewsController) && (controller.action_name == 'index')) + subject = controller.instance_variable_get(:@newss) end subject end diff --git a/test/integration/hearts_hooked_issues_test.rb b/test/integration/hearts_hooked_issues_test.rb index 79bbe5a..707bc28 100644 --- a/test/integration/hearts_hooked_issues_test.rb +++ b/test/integration/hearts_hooked_issues_test.rb @@ -33,6 +33,14 @@ def test_index_shall_not_contain_hooks assert_select '.heart-link-with-count', :count => 0 end + def test_index_with_heart_column + get '/issues?set_filter=1&sort=hearts.count:desc,id&c[]=subject&c[]=hearts.count' + assert_response :success + assert_select 'thead > tr > th:nth-child(4)', :text => 'Like' + assert_select 'td.id', :text => '5' + assert_select 'tbody > tr#issue-2:first-child td.hearts-count', :text => '2' + end + def test_view get '/issues/1' assert_response :success diff --git a/test/integration/hearts_hooked_news_test.rb b/test/integration/hearts_hooked_news_test.rb index cc61e5d..c2df8ea 100644 --- a/test/integration/hearts_hooked_news_test.rb +++ b/test/integration/hearts_hooked_news_test.rb @@ -25,12 +25,17 @@ class HeartsHookedNewsTest < Redmine::IntegrationTest :news, :hearts - def test_index_shall_not_contain_hooks + def test_index get '/news/' assert_response :success - assert_select 'script[src*="transplant_heart_link_with_counter.js"]', :count => 0 - assert_select 'link[href*="redmine_hearts/stylesheets/application.css"]', :count => 0 - assert_select '.heart-link-with-count', :count => 0 + assert_select 'script[src*="transplant_heart_link_with_counter.js"]', :count => 1 + assert_select 'link[href*="redmine_hearts/stylesheets/application.css"]', :count => 1 + + assert_select '.heart-link-with-count', :count => 2 + assert_select '#content .news-heart-holder .heart-link-with-count.news-2-heart', :count => 1 + assert_select '#content .news-heart-holder .heart-link-with-count.news-2-heart span.heart-count-number', :text => "0" + assert_select '#content .news-heart-holder .heart-link-with-count.news-1-heart', :count => 1 + assert_select '#content .news-heart-holder .heart-link-with-count.news-1-heart span.heart-count-number', :text => "1" end def test_view