From adceb1cda6441d2969ed5a3d6d45add6f33c6df7 Mon Sep 17 00:00:00 2001 From: Byron Jones Date: Thu, 13 Feb 2014 13:45:42 +0800 Subject: Bug 40896: Bugzilla needs a "preview" mode for comments r=gerv, a=justdave --- Bugzilla/WebService/Bug.pm | 66 +++++++++++++++++++++ js/field.js | 76 +++++++++++++++++++++++++ skins/standard/global.css | 34 +++++++++++ template/en/default/bug/comment.html.tmpl | 36 ++++++++++++ template/en/default/bug/create/create.html.tmpl | 4 +- template/en/default/bug/edit.html.tmpl | 4 +- 6 files changed, 214 insertions(+), 6 deletions(-) create mode 100644 template/en/default/bug/comment.html.tmpl diff --git a/Bugzilla/WebService/Bug.pm b/Bugzilla/WebService/Bug.pm index de7853092..9ab217b04 100644 --- a/Bugzilla/WebService/Bug.pm +++ b/Bugzilla/WebService/Bug.pm @@ -318,6 +318,30 @@ sub comments { return { bugs => \%bugs, comments => \%comments }; } +sub render_comment { + my ($self, $params) = @_; + + unless (defined $params->{text}) { + ThrowCodeError('params_required', + { function => 'Bug.render_comment', + params => ['text'] }); + } + + Bugzilla->switch_to_shadow_db(); + my $bug = $params->{id} ? Bugzilla::Bug->check($params->{id}) : undef; + + my $tmpl = '[% text FILTER quoteUrls(bug) %]'; + my $html; + my $template = Bugzilla->template; + $template->process( + \$tmpl, + { bug => $bug, text => $params->{text}}, + \$html + ); + + return { html => $html }; +} + # Helper for Bug.comments sub _translate_comment { my ($self, $comment, $filters) = @_; @@ -4682,6 +4706,48 @@ The comment tag provided is longer than the maximum length. =back +=head2 render_comment + +B + +=over + +=item B + +Returns the HTML rendering of the provided comment text. + +=item B + +=over + +=item C + +B C Text comment text to render. + +=item C + +C The ID of the bug to render the comment against. + +=back + +=item B + +C containing the HTML rendering. + +=item B + +This method can throw all of the errors that L throws. + +=item B + +=over + +=item Added in Bugzilla B<5.0>. + +=back + +=back + =head1 B =over diff --git a/js/field.js b/js/field.js index 900299ee0..670c70a86 100644 --- a/js/field.js +++ b/js/field.js @@ -983,3 +983,79 @@ function initDirtyFieldTracking() { }); } } + +/** + * Comment preview + */ + +var last_comment_text = ''; + +function show_comment_preview(bug_id) { + var Dom = YAHOO.util.Dom; + var comment = document.getElementById('comment'); + var preview = document.getElementById('comment_preview'); + if (!comment || !preview) return; + if (Dom.hasClass('comment_preview_tab', 'active_comment_tab')) return; + + preview.style.width = (comment.clientWidth - 4) + 'px'; + preview.style.height = comment.offsetHeight + 'px'; + + Dom.addClass(comment, 'bz_default_hidden'); + Dom.removeClass('comment_tab', 'active_comment_tab'); + Dom.removeClass(preview, 'bz_default_hidden'); + Dom.addClass('comment_preview_tab', 'active_comment_tab'); + + Dom.addClass('comment_preview_error', 'bz_default_hidden'); + + if (last_comment_text == comment.value) + return; + + Dom.addClass('comment_preview_text', 'bz_default_hidden'); + Dom.removeClass('comment_preview_loading', 'bz_default_hidden'); + + YAHOO.util.Connect.setDefaultPostHeader('application/json', true); + YAHOO.util.Connect.asyncRequest('POST', 'jsonrpc.cgi', + { + success: function(res) { + data = YAHOO.lang.JSON.parse(res.responseText); + if (data.error) { + Dom.addClass('comment_preview_loading', 'bz_default_hidden'); + Dom.removeClass('comment_preview_error', 'bz_default_hidden'); + Dom.get('comment_preview_error').innerHTML = + YAHOO.lang.escapeHTML(data.error.message); + } else { + document.getElementById('comment_preview_text').innerHTML = data.result.html; + Dom.addClass('comment_preview_loading', 'bz_default_hidden'); + Dom.removeClass('comment_preview_text', 'bz_default_hidden'); + last_comment_text = comment.value; + } + }, + failure: function(res) { + Dom.addClass('comment_preview_loading', 'bz_default_hidden'); + Dom.removeClass('comment_preview_error', 'bz_default_hidden'); + Dom.get('comment_preview_error').innerHTML = + YAHOO.lang.escapeHTML(res.responseText); + } + }, + YAHOO.lang.JSON.stringify({ + version: "1.1", + method: 'Bug.render_comment', + params: { + id: bug_id, + text: comment.value + } + }) + ); +} + +function show_comment_edit() { + var comment = document.getElementById('comment'); + var preview = document.getElementById('comment_preview'); + if (!comment || !preview) return; + if (YAHOO.util.Dom.hasClass(comment, 'active_comment_tab')) return; + + YAHOO.util.Dom.addClass(preview, 'bz_default_hidden'); + YAHOO.util.Dom.removeClass('comment_preview_tab', 'active_comment_tab'); + YAHOO.util.Dom.removeClass(comment, 'bz_default_hidden'); + YAHOO.util.Dom.addClass('comment_tab', 'active_comment_tab'); +} diff --git a/skins/standard/global.css b/skins/standard/global.css index 29dd9f44e..18bec598a 100644 --- a/skins/standard/global.css +++ b/skins/standard/global.css @@ -678,6 +678,40 @@ input.required, select.required, span.required_explanation { margin-left: -1px; } +.comment_tab { + float: left; + border: 1px solid silver; + border-bottom: 0px; + padding: 2px 1em; + cursor: pointer; + background: transparent; +} + +.active_comment_tab { + background: #fff; + font-weight: bold; +} + +#comment_preview { + border: 1px solid silver; + padding: 2px; + overflow: auto; + margin: 0px; +} + +#comment_preview_text { + margin: 0px; + width: auto; +} + +#comment_preview_loading { + font-style: italic; +} + +#comment { + margin-top: 0px; +} + /*******************/ /* Form Validation */ /*******************/ diff --git a/template/en/default/bug/comment.html.tmpl b/template/en/default/bug/comment.html.tmpl new file mode 100644 index 000000000..1d8cf0b30 --- /dev/null +++ b/template/en/default/bug/comment.html.tmpl @@ -0,0 +1,36 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +[%# INTERFACE: + # + # This template supports the same parameters as global/textarea.html.tmpl + # with the exception of "name" and "id", which will always be "comment". + #%] + +[% IF feature_enabled('jsonrpc') %] +
+
Comment
+
Preview
+
+[% END %] + +[% INCLUDE global/textarea.html.tmpl + name = "comment" + id = "comment" +%] +
+ +[% IF feature_enabled('jsonrpc') %] +
+
Generating Preview...
+
+

+  
+[% END %] diff --git a/template/en/default/bug/create/create.html.tmpl b/template/en/default/bug/create/create.html.tmpl index 6adf75102..d372c4d08 100644 --- a/template/en/default/bug/create/create.html.tmpl +++ b/template/en/default/bug/create/create.html.tmpl @@ -542,9 +542,7 @@ TUI_hide_default('attachment_text_field'); # by global/textarea.html.tmpl. So we must not escape the comment here. %] [% comment FILTER none %] [%- END %] - [% INCLUDE global/textarea.html.tmpl - name = 'comment' - id = 'comment' + [% INCLUDE bug/comment.html.tmpl minrows = 10 maxrows = 25 cols = constants.COMMENT_COLS diff --git a/template/en/default/bug/edit.html.tmpl b/template/en/default/bug/edit.html.tmpl index 3b93ebe2b..89b78bc9f 100644 --- a/template/en/default/bug/edit.html.tmpl +++ b/template/en/default/bug/edit.html.tmpl @@ -1110,9 +1110,7 @@
[% IF bug.check_can_change_field('longdesc', 0, 1) %] - [% INCLUDE global/textarea.html.tmpl - name = 'comment' - id = 'comment' + [% INCLUDE bug/comment.html.tmpl minrows = 10 maxrows = 25 cols = constants.COMMENT_COLS -- cgit v1.2.3-24-g4f1b