diff options
author | Byron Jones <glob@mozilla.com> | 2015-06-05 06:40:01 +0200 |
---|---|---|
committer | Byron Jones <glob@mozilla.com> | 2015-06-05 06:40:01 +0200 |
commit | 907fbcfd19dfa436567bf4a75f566b8f81f43298 (patch) | |
tree | bdbe5df647bdc5bbdbfe0a228bdb9d56d864ba40 | |
parent | a34e675b4ac3ebce28c2a0450fe75f8df38c540c (diff) | |
download | bugzilla-907fbcfd19dfa436567bf4a75f566b8f81f43298.tar.gz bugzilla-907fbcfd19dfa436567bf4a75f566b8f81f43298.tar.xz |
Bug 1146775: implement comment collapse all and by tag
-rw-r--r-- | extensions/BugModal/template/en/default/bug_modal/activity_stream.html.tmpl | 34 | ||||
-rw-r--r-- | extensions/BugModal/template/en/default/bug_modal/header.html.tmpl | 2 | ||||
-rw-r--r-- | extensions/BugModal/web/bug_modal.css | 17 | ||||
-rw-r--r-- | extensions/BugModal/web/bug_modal.js | 45 | ||||
-rw-r--r-- | extensions/BugModal/web/comments.js | 218 | ||||
-rw-r--r-- | template/en/default/global/header.html.tmpl | 4 |
6 files changed, 276 insertions, 44 deletions
diff --git a/extensions/BugModal/template/en/default/bug_modal/activity_stream.html.tmpl b/extensions/BugModal/template/en/default/bug_modal/activity_stream.html.tmpl index 11442985c..4bc860996 100644 --- a/extensions/BugModal/template/en/default/bug_modal/activity_stream.html.tmpl +++ b/extensions/BugModal/template/en/default/bug_modal/activity_stream.html.tmpl @@ -6,9 +6,25 @@ # defined by the Mozilla Public License, v. 2.0. #%] +<div id="comment-actions"> + <button type="button" id="comment-tags-btn" style="display:none" class="minor">Tags ▾</button> + <button type="button" id="comment-toggle-btn" class="minor">Comments ▾</button> +</div> + +<menu id="comment-toggle-menu" type="context" style="display:none"> + <menuitem id="comment-reset" label="Reset"></menuitem> + <hr> + <menuitem id="comment-collapse-all" label="Collapse All"></menuitem> + <menuitem id="comment-expand-all" label="Expand All"></menuitem> + <hr> + <menuitem id="comments-only" label="Comments Only"></menuitem> + [% Hook.process('comments-toggle-menu') %] +</menu> + [% PROCESS bug/time.html.tmpl; + activity_counter = 0; FOREACH change_set IN bug.activity_stream; '<div class="change-set" id="' _ change_set.id _ '">'; @@ -22,7 +38,8 @@ IF change_set.comment; PROCESS comment_header comment=change_set.comment; ELSE; - PROCESS activity_header activities=change_set.activity id=change_set.id; + activity_counter = activity_counter + 1; + PROCESS activity_header activities=change_set.activity id=activity_counter; END; IF change_set.comment; @@ -95,16 +112,16 @@ data-no="[% comment.count FILTER none %]" >Tag</button> [% END %] - <button class="reply-btn minor" type="button" + <button type="button" class="reply-btn minor" data-reply-id="[% comment.count FILTER none %]" data-reply-name="[% comment.author.name || comment.author.moz_nick FILTER html %]" >Reply</button> [% END %] - <button class="comment-spinner minor" id="cs-[% comment.count FILTER none%]">-</button> + <button type="button" class="change-spinner minor" id="cs-[% comment.count FILTER none %]">-</button> </td> </tr> - <tr> + <tr id="cr-[% comment.count FILTER none %]" [%= IF comment.collapsed %]style="display:none"[% END %]> <td colspan="2"> <div class="change-name"> <a href="show_bug.cgi?id=[% bug.bug_id FILTER none %]#c[% comment.count FILTER none %]"> @@ -138,7 +155,7 @@ Comment hidden ([% comment.tags.join(', ') FILTER html %]) </td> <td class="comment-actions"> - <button class="comment-spinner minor" id="ccs-[% comment.count FILTER none%]"> + <button type="button" class="change-spinner minor" id="ccs-[% comment.count FILTER none %]"> [%~ comment.collapsed ? "+" : "-" ~%] </button> </td> @@ -150,7 +167,7 @@ [% BLOCK activity_header %] [% action = activities.0 %] - <div id="[% id FILTER none %]" class="change"> + <div class="change" id="a[% id FILTER none %]"> <table class="layout-table change-head [% extra_class FILTER none %]"> <tr> <td rowspan="2" class="change-gravatar"> @@ -168,8 +185,11 @@ <span class="user-role">([% extra_class.ucfirst FILTER none %])</span> [% END %] </td> + <td class="comment-actions"> + <button type="button" class="change-spinner minor" id="as-[% id FILTER none %]">-</button> + </td> </tr> - <tr> + <tr id="ar-[% id FILTER none %]"> <td colspan="2"> <div class="change-name"> <a href="show_bug.cgi?id=[% bug.bug_id FILTER none %]#[% id FILTER none %]">Updated</a> diff --git a/extensions/BugModal/template/en/default/bug_modal/header.html.tmpl b/extensions/BugModal/template/en/default/bug_modal/header.html.tmpl index a1aee3cfd..7fdb2ed49 100644 --- a/extensions/BugModal/template/en/default/bug_modal/header.html.tmpl +++ b/extensions/BugModal/template/en/default/bug_modal/header.html.tmpl @@ -58,11 +58,13 @@ ); jquery.push( "datetimepicker", + "contextMenu", ); style_urls.push( "extensions/BugModal/web/bug_modal.css", "skins/custom/bug_groups.css", "js/jquery/plugins/datetimepicker/datetimepicker.css", + "js/jquery/plugins/contextMenu/contextMenu.css", ); IF user.in_group('canconfirm'); diff --git a/extensions/BugModal/web/bug_modal.css b/extensions/BugModal/web/bug_modal.css index 0d34039af..e3070f2a6 100644 --- a/extensions/BugModal/web/bug_modal.css +++ b/extensions/BugModal/web/bug_modal.css @@ -325,8 +325,7 @@ input[type="number"] { /* actions */ #top-actions { - margin-top: 5px; - padding-bottom: 20px; + margin: 4px 0; } #top-actions .save-btn { @@ -465,13 +464,18 @@ td.flag-requestee { /* comments and activity */ +#comment-actions { + margin-top: 4px; + text-align: right; +} + .change-set { clear: both; -webkit-box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1); -moz-box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1); box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1); border-bottom: 1px solid rgba(0, 0, 0, 0.2); - margin-top: 20px; + margin-top: 8px; border: 1px solid #ddd; } @@ -488,10 +492,15 @@ td.flag-requestee { padding-left: 8px !important; } +.change-gravatar .vcard { + width: 36px; + text-align: center; +} + .change-author { width: 100%; vertical-align: top; - padding-top: 4px !important; + padding: 5px 0 !important; } .change-author .vcard { diff --git a/extensions/BugModal/web/bug_modal.js b/extensions/BugModal/web/bug_modal.js index 473de438e..87cfcffdf 100644 --- a/extensions/BugModal/web/bug_modal.js +++ b/extensions/BugModal/web/bug_modal.js @@ -25,19 +25,6 @@ $(function() { // products with descriptions (also lazy-loaded) var products = []; - // scroll to an element - function scroll_to(el, complete) { - var offset = el.offset(); - $('html, body') - .animate({ - scrollTop: offset.top - 20, - scrollLeft: offset.left = 20 - }, - 200, - complete - ); - } - // expand/collapse module function slide_module(module, action, fast) { if (!module.attr('id')) @@ -120,7 +107,7 @@ $(function() { .click(function(event) { event.preventDefault(); var id = $('.comment:last')[0].parentNode.id; - scroll_to($('#' + id)); + $.scrollTo($('#' + id)); window.location.hash = id; }); @@ -128,7 +115,7 @@ $(function() { $('#top-btn') .click(function(event) { event.preventDefault(); - scroll_to($('body')); + $.scrollTo($('body')); }); // use non-native tooltips for relative times and bug summaries @@ -450,14 +437,14 @@ $(function() { event.preventDefault(); // focus first to grow the textarea, so we scroll to the correct location $('#comment').focus(); - scroll_to($('#bottom-save-btn')); + $.scrollTo($('#bottom-save-btn')); }); // needinfo in people section -> scroll to near-comment ui $('#needinfo-scroll') .click(function(event) { event.preventDefault(); - scroll_to($('#needinfo_role'), function() { $('#needinfo_role').focus(); }); + $.scrollTo($('#needinfo_role'), function() { $('#needinfo_role').focus(); }); }); // knob @@ -569,7 +556,7 @@ $(function() { if ($('#comment').val() != reply_text) { $('#comment').val($('#comment').val() + reply_text); } - scroll_to($('#comment'), function() { $('#comment').focus(); }); + $.scrollTo($('#comment'), function() { $('#comment').focus(); }); }); // add comment --> enlarge on focus @@ -606,10 +593,10 @@ $(function() { $('#resolution').val($(event.target).text()).change(); $('#top-save-btn').show(); if ($(event.target).text() == "DUPLICATE") { - scroll_to($('body')); + $.scrollTo($('body')); } else { - scroll_to($('body'), function() { $('#resolution').focus(); }); + $.scrollTo($('body'), function() { $('#resolution').focus(); }); } }); $('.status-btn') @@ -619,7 +606,7 @@ $(function() { $('#field-status-edit').show(); $('#bug_status').val($(event.target).data('status')).change(); $('#top-save-btn').show(); - scroll_to($('body'), function() { $('#bug_status').focus(); }); + $.scrollTo($('body'), function() { $('#bug_status').focus(); }); }); // vote button @@ -651,7 +638,7 @@ $(function() { if (current != text) { $('#comment').val(current + text); $('#comment').focus(); - scroll_to($('#bottom-save-btn')); + $.scrollTo($('#bottom-save-btn')); } }); @@ -1158,7 +1145,21 @@ function lb_close(event) { } // stick with inArray/indexOf and return -1 on no match return -1; + }, + + // Animated scroll to bring an element into view + scrollTo: function(el, complete) { + var offset = el.offset(); + $('html, body') + .animate({ + scrollTop: offset.top - 20, + scrollLeft: offset.left = 20 + }, + 200, + complete + ); } + }); })(jQuery); diff --git a/extensions/BugModal/web/comments.js b/extensions/BugModal/web/comments.js index 1f0b18696..f0d689b3e 100644 --- a/extensions/BugModal/web/comments.js +++ b/extensions/BugModal/web/comments.js @@ -9,22 +9,220 @@ $(function() { 'use strict'; // comment collapse/expand - $('.comment-spinner') - .click(function(event) { - event.preventDefault(); - var spinner = $(event.target); - var id = spinner.attr('id').match(/\d+$/)[0]; - // switch to full header for initially collapsed comments - if (spinner.attr('id').match(/^ccs-/)) { + + function toggleChange(spinner, forced) { + // find and cache the id + var id = spinner.data('cid'); + if (!id) { + id = spinner.attr('id').match(/\d+$/)[0]; + spinner.data('cid', id); + } + + // non-comment toggle + if (spinner.attr('id').substr(0, 1) == 'a') { + var changeSet = spinner.parents('.change-set'); + if (forced == 'hide') { + changeSet.find('.activity').hide(); + changeSet.find('.gravatar').css('width', '16px').css('height', '16px'); + $('#ar-' + id).hide(); + spinner.text('+'); + } + else if (forced == 'show' || forced == 'reset') { + changeSet.find('.activity').show(); + changeSet.find('.gravatar').css('width', '32px').css('height', '32px'); + $('#ar-' + id).show(); + spinner.text('-'); + } + else { + changeSet.find('.activity').slideToggle('fast', function() { + $('#ar-' + id).toggle(); + if (changeSet.find('.activity:visible').length) { + changeSet.find('.gravatar').css('width', '32px').css('height', '32px'); + spinner.text('-'); + } + else { + changeSet.find('.gravatar').css('width', '16px').css('height', '16px'); + spinner.text('+'); + } + }); + } + return; + } + + // find the "real spinner", which is the one on the non-default-collapsed block + var realSpinner = $('#cs-' + id); + var defaultCollapsed = realSpinner.data('ch'); + if (defaultCollapsed === undefined) { + defaultCollapsed = spinner.attr('id').substring(0, 4) === 'ccs-'; + realSpinner.data('ch', defaultCollapsed); + } + if (forced === 'reset') { + forced = defaultCollapsed ? 'hide' : 'show'; + } + + // comment toggle + if (forced === 'hide') { + if (defaultCollapsed) { + $('#ch-' + id).hide(); + $('#cc-' + id).show(); + } + $('#ct-' + id).hide(); + if (BUGZILLA.user.id !== 0) + $('#ctag-' + id).hide(); + $('#c' + id).find('.activity').hide(); + $('#c' + id).find('.comment-tags').hide(); + $('#c' + id).find('.comment-tags').hide(); + $('#c' + id).find('.gravatar').css('width', '16px').css('height', '16px'); + $('#cr-' + id).hide(); + spinner.text('+'); + } + else if (forced == 'show') { + if (defaultCollapsed) { $('#cc-' + id).hide(); $('#ch-' + id).show(); } - $('#ct-' + id + ', #ctag-' + id).slideToggle('fast', function() { + $('#ct-' + id).show(); + if (BUGZILLA.user.id !== 0) + $('#ctag-' + id).show(); + $('#c' + id).find('.activity').show(); + $('#c' + id).find('.comment-tags').show(); + $('#c' + id).find('.comment-tags').show(); + $('#c' + id).find('.gravatar').css('width', '32px').css('height', '32px'); + $('#cr-' + id).show(); + spinner.text('-'); + } + else { + $('#ct-' + id).slideToggle('fast', function() { $('#c' + id).find('.activity').toggle(); - spinner.text($('#ct-' + id + ':visible').length ? '-' : '+'); + $('#c' + id).find('.comment-tags').toggle(); + if ($('#ct-' + id + ':visible').length) { + spinner.text('-'); + $('#cr-' + id).show(); + if (BUGZILLA.user.id !== 0) + $('#ctag-' + id).show(); + $('#c' + id).find('.gravatar').css('width', '32px').css('height', '32px'); + if (defaultCollapsed) { + $('#cc-' + id).hide(); + $('#ch-' + id).show(); + } + } + else { + spinner.text('+'); + $('#cr-' + id).hide(); + if (BUGZILLA.user.id !== 0) + $('#ctag-' + id).hide(); + $('#c' + id).find('.gravatar').css('width', '16px').css('height', '16px'); + if (defaultCollapsed) { + $('#ch-' + id).hide(); + $('#cc-' + id).show(); + } + } }); + } + } + + $('.change-spinner') + .click(function(event) { + event.preventDefault(); + toggleChange($(this)); }); + // comment and tag menus + + $('#comment-reset') + .click(function() { + $('.change-spinner:visible').each(function() { + toggleChange($(this), 'reset'); + }); + }); + + $('#comment-collapse-all') + .click(function() { + $('.change-spinner:visible').each(function() { + toggleChange($(this), 'hide'); + }); + }); + + $('#comment-expand-all') + .click(function() { + $('.change-spinner:visible').each(function() { + toggleChange($(this), 'show'); + }); + }); + + $('#comments-only') + .click(function() { + $('.change-spinner:visible').each(function() { + toggleChange($(this), this.id.substr(0, 3) === 'cs-' ? 'show' : 'hide'); + }); + }); + + $.contextMenu({ + selector: '#comment-toggle-btn', + trigger: 'left', + items: $.contextMenu.fromMenu($('#comment-toggle-menu')) + }); + + function updateTagsMenu() { + var tags = []; + $('.comment-tags').each(function() { + $.each(tagsFromDom($(this)), function() { + var tag = this.toLowerCase(); + if (tag in tags) { + tags[tag]++; + } + else { + tags[tag] = 1; + } + }); + }); + var tagNames = Object.keys(tags); + tagNames.sort(); + + var btn = $('#comment-tags-btn'); + if (tagNames.length === 0) { + btn.hide(); + return; + } + btn.show(); + + var menuItems = [ + { name: 'Reset', tag: '' }, + "--" + ]; + $.each(tagNames, function(key, value) { + menuItems.push({ name: value + ' (' + tags[value] + ')', tag: value }); + }); + + $.contextMenu('destroy', '#comment-tags-btn'); + $.contextMenu({ + selector: '#comment-tags-btn', + trigger: 'left', + items: menuItems, + callback: function(key, opt) { + var tag = opt.commands[key].tag; + if (tag === '') { + $('.change-spinner:visible').each(function() { + toggleChange($(this), 'reset'); + }); + return; + } + var firstComment = false; + $('.change-spinner:visible').each(function() { + var that = $(this); + var commentTags = tagsFromDom(that.parents('.comment').find('.comment-tags')); + var hasTag = $.inArrayIn(tag, commentTags) >= 0; + toggleChange(that, hasTag ? 'show' : 'hide'); + if (hasTag && !firstComment) { + firstComment = that; + } + }); + if (firstComment) + $.scrollTo(firstComment); + } + }); + } + // // anything after this point is only executed for logged in users // @@ -259,4 +457,6 @@ $(function() { event.preventDefault(); $('#' + $(this).data('for')).hide(); }); + + updateTagsMenu(); }); diff --git a/template/en/default/global/header.html.tmpl b/template/en/default/global/header.html.tmpl index 086191a39..aafbbca70 100644 --- a/template/en/default/global/header.html.tmpl +++ b/template/en/default/global/header.html.tmpl @@ -130,7 +130,7 @@ [% SET yui = yui_resolve_deps(yui, yui_deps) %] [% END %] - [% SET css_sets = css_files(style_urls, yui, yui_css) %] + [% SET css_sets = css_files(style_urls.unique, yui, yui_css) %] [% IF constants.CONCATENATE_ASSETS %] [% PROCESS format_css_link asset_url = css_sets.unified_standard_skin %] [% ELSE %] @@ -166,7 +166,7 @@ [% END %] [%# jQuery Plugins %] - [% FOREACH jq_name = jquery %] + [% FOREACH jq_name = jquery.unique %] [% starting_js_urls.push("js/jquery/plugins/$jq_name/${jq_name}-min.js") %] [% END %] [% starting_js_urls.push('js/global.js') %] |