From 529787d641cf76b48be1e0db8d4c69e8988633aa Mon Sep 17 00:00:00 2001 From: Vladimir Date: Wed, 5 Dec 2012 04:39:05 +0400 Subject: [PATCH] New issue, issue edit, bulk issue edit tagcloud. New UI --- app/helpers/application_helper.rb | 4 + app/views/tagging/_issue_tagcloud.erb | 10 ++- assets/javascripts/toggle_tags.js | 103 ++++++++++++++++++++++++ assets/javascripts/toggle_visibility.js | 17 ---- assets/stylesheets/tagging.css | 31 +++++++ lib/tagging_plugin/tagging_hooks.rb | 72 ++++++----------- 6 files changed, 169 insertions(+), 68 deletions(-) create mode 100644 assets/javascripts/toggle_tags.js delete mode 100644 assets/javascripts/toggle_visibility.js create mode 100644 assets/stylesheets/tagging.css diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index b2da5e1..6f38ac5 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -21,6 +21,10 @@ def link_to_project_tag_filter(project, tag, options = {}, html_options = {}) end end + def tag_without_sharp(tag) + tag[1..-1] + end + def tag_cloud_in_project(project, &each_tag) tags = {} diff --git a/app/views/tagging/_issue_tagcloud.erb b/app/views/tagging/_issue_tagcloud.erb index 2bf1dae..52cc959 100644 --- a/app/views/tagging/_issue_tagcloud.erb +++ b/app/views/tagging/_issue_tagcloud.erb @@ -1,9 +1,13 @@ -<%= t(:tags_in_project) %> +<%= t(:tags_in_project) %> — <% tag_cloud_in_project(@project) do |tag, factor| - options = {:style => "font-size: #{10 * factor + 9}pt" } + style = "font-size: #{10 * factor + 9}pt" %> - <%= link_to_project_tag_filter(@project, tag, {}, options) %> + + <%= tag %> + <% end %> diff --git a/assets/javascripts/toggle_tags.js b/assets/javascripts/toggle_tags.js new file mode 100644 index 0000000..2ad6a21 --- /dev/null +++ b/assets/javascripts/toggle_tags.js @@ -0,0 +1,103 @@ +// IE compatibility +if (!Array.prototype.indexOf) { + Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) { + "use strict" + if (this == null) { + throw new TypeError() + } + var t = Object(this) + var len = t.length >>> 0 + if (len === 0) { + return -1 + } + var n = 0 + if (arguments.length > 1) { + n = Number(arguments[1]); + if (n != n) { // shortcut for verifying if it's NaN + n = 0 + } else if (n != 0 && n != Infinity && n != -Infinity) { + n = (n > 0 || -1) * Math.floor(Math.abs(n)); + } + } + if (n >= len) { + return -1 + } + var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); + for (; k < len; k++) { + if (k in t && t[k] === searchElement) { + return k + } + } + return -1 + } +} + +(function ($) { + $.fn.toggleCloudViaFor = function(cloud_trigger, tag_container) { + var tag_cloud = $(this) + + cloud_trigger.click(function(e) { + tag_cloud.toggle() + e.preventDefault() + }) + + var tag_items = tag_cloud.children() + + $(tag_items).click(function(e) { + var tag_value = $(this).attr("data-tag") + $(this).toggleTagFor(tag_value, tag_container) + + show_selected_tags_from(tag_container, tag_cloud) + + e.preventDefault() + }) + + $(this).toggle() + show_selected_tags_from(tag_container, tag_cloud) + + tag_container.keyup(function(e) { + show_selected_tags_from(tag_container, tag_cloud) + }) + + tag_container.change(function(e) { + show_selected_tags_from(tag_container, tag_cloud) + }) + } + + function show_selected_tags_from(tag_container, tag_cloud) { + var current_tags = tags_to_array(tag_container.attr("value")) + update_selected_tags(current_tags, tag_cloud) + } + + function update_selected_tags(selected_tags, tag_cloud) { + tag_cloud.children().each(function(index, tag_child) { + var tag_value = $(tag_child).attr("data-tag") + if(selected_tags.indexOf(tag_value) == -1) + $(tag_child).removeClass("selected") + else { + $(tag_child).addClass("selected") + } + }) + } + + $.fn.toggleTagFor = function(tag_name, tag_container) { + var content_tags = tags_to_array(tag_container.attr("value")) + + var this_tag_index = content_tags.indexOf(tag_name) + + if(this_tag_index == -1) { + content_tags.push(tag_name) + } else { + content_tags.splice(this_tag_index, 1) + } + + tag_container.attr("value", content_tags.join(" ")) + } + + function tags_to_array(tags) { + dirty_items = tags.split(/[,#\s]+/) + return $.grep(dirty_items, function(val, i){ + return (val.length > 0) + }) + } +})(jQuery) diff --git a/assets/javascripts/toggle_visibility.js b/assets/javascripts/toggle_visibility.js deleted file mode 100644 index be5c63a..0000000 --- a/assets/javascripts/toggle_visibility.js +++ /dev/null @@ -1,17 +0,0 @@ -(function ($) { - $.fn.toggleVisibilityVia = function (cloud_trigger) { - - var tag_cloud = $(this); - - cloud_trigger.click(function(e) { - tag_cloud.toggle(); - e.preventDefault(); - }) - - cloud_trigger.css("cursor", "pointer") - cloud_trigger.css("border-bottom", "dashed 1px") - cloud_trigger.css("text-decoration", "none") - - $(this).toggle(); - } -})(jQuery); diff --git a/assets/stylesheets/tagging.css b/assets/stylesheets/tagging.css new file mode 100644 index 0000000..d128285 --- /dev/null +++ b/assets/stylesheets/tagging.css @@ -0,0 +1,31 @@ +span.tagMatches { + margin-left: 10px; +} + +span.tagMatches span { + padding: 2px; + margin-right: 4px; + background-color: #0000AB; + color: #fff; + cursor: pointer; +} + +#cloud_trigger, #cloud_content a { + cursor: pointer; + + text-decoration: none; + border-bottom: 1px dashed; +} + +#cloud_trigger { + font-weight: bold; +} + +#cloud_content a { + margin: 0.1em; +} + +#cloud_content .selected { + background: #0000AB; + color: #fff; +} diff --git a/lib/tagging_plugin/tagging_hooks.rb b/lib/tagging_plugin/tagging_hooks.rb index 9a65067..b07c1fa 100755 --- a/lib/tagging_plugin/tagging_hooks.rb +++ b/lib/tagging_plugin/tagging_hooks.rb @@ -1,38 +1,13 @@ module TaggingPlugin module Hooks class LayoutHook < Redmine::Hook::ViewListener - def view_issues_new_top(context={}) - return '' if Setting.plugin_redmine_tagging[:sidebar_tagcloud] != "1" - - cloud = context[:controller].send(:render_to_string, { - :partial => 'tagging/issue_tagcloud', - :locals => context - }) - - result = <<-TAGS - #{javascript_include_tag 'jquery_loader', :plugin => 'redmine_tagging'} - #{javascript_include_tag 'toggle_visibility', :plugin => 'redmine_tagging'} - - TAGS - - return result - end - def view_issues_sidebar_planning_bottom(context={}) return '' if Setting.plugin_redmine_tagging[:sidebar_tagcloud] != "1" return context[:controller].send(:render_to_string, { :partial => 'tagging/tagcloud', :locals => context - }) + }) end def view_wiki_sidebar_bottom(context={}) @@ -41,11 +16,18 @@ def view_wiki_sidebar_bottom(context={}) return context[:controller].send(:render_to_string, { :partial => 'tagging/tagcloud_search', :locals => context - }) + }) end def view_layouts_base_html_head(context={}) + tagging_stylesheet = stylesheet_link_tag 'tagging', :plugin => 'redmine_tagging' + unless ((Setting.plugin_redmine_tagging[:sidebar_tagcloud] == "1" && + context[:controller].is_a?(WikiController)) || + (context[:controller].is_a?(IssuesController) && + context[:controller].action_name == 'bulk_edit')) + return tagging_stylesheet + end if Setting.plugin_redmine_tagging[:sidebar_tagcloud] == "1" tag_cloud = context[:controller].send(:render_to_string, { @@ -58,34 +40,18 @@ def view_layouts_base_html_head(context={}) sidebar_tags = '' end - result = <<-TAGS + <<-TAGS + #{tagging_stylesheet} #{javascript_include_tag 'jquery_loader', :plugin => 'redmine_tagging'} - #{javascript_include_tag 'toggle_visibility', :plugin => 'redmine_tagging'} + #{javascript_include_tag 'toggle_tags', :plugin => 'redmine_tagging'} TAGS - - <<-TAGCLOUD - #{result} - - TAGCLOUD end def view_issues_show_details_bottom(context={}) @@ -114,6 +80,12 @@ def view_issues_form_details_bottom(context={}) tags = '

' + context[:form].text_field(:tags, :value => tags) + '

' tags += javascript_include_tag 'jquery_loader', :plugin => 'redmine_tagging' tags += javascript_include_tag 'tag', :plugin => 'redmine_tagging' + tags += javascript_include_tag 'toggle_tags', :plugin => 'redmine_tagging' + + cloud = context[:controller].send(:render_to_string, { + :partial => 'tagging/issue_tagcloud', + :locals => context + }) ac = ActsAsTaggableOn::Tag.find(:all, :conditions => ["id in (select tag_id from taggings @@ -124,6 +96,11 @@ def view_issues_form_details_bottom(context={}) var $j = jQuery.noConflict() $j(document).ready(function() { $j('#issue_tags').tagSuggest({ tags: [#{ac}] }) + + var tags_container = $j('#issue_tags').parent() + var cloud = $j("
#{escape_javascript(cloud)}
") + $j(tags_container).append(cloud) + $j('#cloud_content').toggleCloudViaFor($j('#cloud_trigger'), $j('#issue_tags')) }) generatedscript @@ -260,7 +237,6 @@ def view_reports_issue_report_split_content_right(context={}) report += "
" return report end - end end end