Ticket #7145: 7145-ticket-change-preview-r10500.patch
| File 7145-ticket-change-preview-r10500.patch, 9.7 KB (added by rblank, 16 months ago) |
|---|
-
trac/htdocs/js/auto_preview.js
diff --git a/trac/htdocs/js/auto_preview.js b/trac/htdocs/js/auto_preview.js
a b 1 1 // Automatic preview through XHR 2 2 3 3 (function($) { 4 // Enable automatic previewing of form submissions. 5 // 6 // Arguments: 7 // - `args`: additional form data to be passed with the XHR. 8 // - `update`: the function that is called with the preview results. It 9 // is called with the request data and the reply. 10 $.fn.autoFormPreview = function(args, update) { 11 if (auto_preview_timeout <= 0) 12 return this; 13 var form = this.closest('form'); 14 var data = {}; 15 for (var key in args) 16 data[key] = args[key]; 17 var timer = null; 18 var timeout = auto_preview_timeout * 1000; 19 var updating = false; 20 var queued = false; 21 22 // Return true iff the values have changed 23 function values_changed(new_values) { 24 for (var i in values) { 25 var value = values[i], new_value = new_values[i]; 26 if ((value.name != new_value.name) || (value.value != new_value.value)) 27 return true; 28 } 29 return false; 30 } 31 32 // Request a preview through XHR 33 function request() { 34 if (!updating) { 35 var new_values = form.serializeArray(); 36 if (values_changed(new_values)) { 37 values = new_values; 38 updating = true; 39 var data = {}; 40 for (var i in values) { 41 var value = values[i]; 42 data[value.name] = value.value.replace(/\n/g, '\r\n'); 43 } 44 for (var key in args) 45 data[key] = args[key]; 46 $.ajax({ 47 type: "POST", url: form.attr('action'), data: data, 48 dataType: "html", 49 success: function(reply) { 50 if (queued) 51 timer = setTimeout(request, timeout); 52 updating = false; 53 queued = false; 54 update(data, reply); 55 }, 56 error: function(req, err, exc) { 57 updating = false; 58 queued = false; 59 }, 60 }); 61 } 62 } 63 } 64 65 // Trigger a request after the given timeout 66 function trigger() { 67 if (!updating) { 68 if (timer) 69 clearTimeout(timer); 70 timer = setTimeout(request, timeout); 71 } else { 72 queued = true; 73 } 74 return true; 75 } 76 77 var values = form.serializeArray(); 78 return this.each(function() { 79 $(this).keydown(trigger).keypress(trigger).change(trigger).blur(request); 80 }); 81 }; 82 4 83 // Enable automatic previewing to <textarea> elements. 5 84 // 6 85 // Arguments: … … 56 135 57 136 $(this).keydown(trigger).keypress(trigger).blur(request); 58 137 }); 59 } 138 }; 60 139 })(jQuery); -
trac/ticket/templates/ticket.html
diff --git a/trac/ticket/templates/ticket.html b/trac/ticket/templates/ticket.html
a b 18 18 $("div.description").find("h1,h2,h3,h4,h5,h6").addAnchor(_("Link to this section")); 19 19 $(".foldable").enableFolding(false, true); 20 20 <py:when test="ticket.exists"> 21 var args = {realm: "ticket", id: ${ticket.id}, escape_newlines: ${int(preserve_newlines)}}22 $("#comment").autoPreview("${href.wiki_render()}", args, function(textarea, text, rendered) {23 $("#ticketchange div.comment").html(rendered);24 if (rendered)25 $("#ticketchange").show();26 else if ($("#ticketchange ul.changes").length == 0)27 $("#ticketchange").hide();28 });29 $("#trac-comment-editor textarea").autoPreview("${href.wiki_render()}", args,30 function(textarea, text, rendered) {31 var comment = $("#trac-comment-editor").next("div.comment");32 comment.html(rendered);33 if (rendered)34 comment.show();35 else36 comment.hide();37 });38 21 $("#modify").parent().toggleClass("collapsed"); 39 22 $(".trac-topnav a").click(function() { $("#modify").parent().removeClass("collapsed"); }); 40 23 … … 49 32 } 50 33 actions.click(updateActionFields); 51 34 updateActionFields(); 35 36 $("#propertyform").find("textarea, select, :text, :checkbox, :radio") 37 .autoFormPreview({}, function(data, rendered) { 38 $("#ticketchange-content").html(rendered); 39 if (rendered) 40 $("#ticketchange").show(); 41 else if ($("#ticketchange ul.changes").length == 0) 42 $("#ticketchange").hide(); 43 }); 44 var args = {realm: "ticket", id: ${ticket.id}, escape_newlines: ${int(preserve_newlines)}}; 45 $("#trac-comment-editor textarea").autoPreview("${href.wiki_render()}", args, 46 function(textarea, text, rendered) { 47 var comment = $("#trac-comment-editor").next("div.comment"); 48 comment.html(rendered); 49 if (rendered) 50 comment.show(); 51 else 52 comment.hide(); 53 }); 52 54 </py:when> 53 55 <py:otherwise> 54 56 $("#field-summary").focus(); … … 190 192 <form py:if="has_property_editor" method="post" id="propertyform" 191 193 action="${ticket.exists and href.ticket(ticket.id) + '#trac-add-comment' or href.newticket()}"> 192 194 <!--! Add comment --> 193 <div py:if="ticket.exists and can_append" class="field" 194 py:with="show_comment_preview = (change_preview.fields or change_preview.comment) and cnum_edit is None"> 195 <div py:if="ticket.exists and can_append" class="field"> 195 196 <div class="trac-nav"> 196 197 <a href="#content" title="View ticket fields and description">View</a> ↑ 197 198 </div> … … 211 212 Warnings are shown at the <a href="#warning">top of the page</a>. The ticket validation 212 213 may have failed. 213 214 </div> 214 <!--! Preview of ticket changes -->215 <div id="ticketchange" class="ticketdraft" style="${not show_comment_preview and 'display: none' or None}">216 <h3 class="change" id="${'cnum' in change_preview and 'comment:%d' % change_preview.cnum or None}">217 <span class="threading" py:if="'replyto' in change_preview">218 in reply to: ${commentref('↑ ', change_preview.replyto)}219 </span>220 <i18n:msg params="author">Changed by ${authorinfo(change_preview.author)}</i18n:msg>221 </h3>222 <xi:include href="ticket_change.html" py:with="change = change_preview"/>223 </div>224 215 </div> 225 216 226 217 <div> … … 377 368 </fieldset> 378 369 </div> 379 370 371 <!--! Preview of ticket changes --> 372 <div py:if="ticket.exists and can_append" id="ticketchange" class="ticketdraft" 373 style="${(not (change_preview.fields or change_preview.comment) 374 or cnum_edit is not None) and 'display: none' or None}"> 375 <h3 class="change" id="${'cnum' in change_preview and 'comment:%d' % change_preview.cnum or None}"> 376 <span class="threading" py:if="'replyto' in change_preview"> 377 in reply to: ${commentref('↑ ', change_preview.replyto)} 378 </span> 379 <i18n:msg params="author">Changed by ${authorinfo(change_preview.author)}</i18n:msg> 380 </h3> 381 <div id="ticketchange-content"><xi:include href="ticket_change.html" py:with="change = change_preview"/></div> 382 </div> 383 380 384 <!--! Attachment on creation checkbox --> 381 385 <p py:if="not ticket.exists and 'ATTACHMENT_CREATE' in perm(ticket.resource.child('attachment'))"> 382 386 <label> -
trac/ticket/templates/ticket_change.html
diff --git a/trac/ticket/templates/ticket_change.html b/trac/ticket/templates/ticket_change.html
a b Arguments: 13 13 xmlns:i18n="http://genshi.edgewall.org/i18n" 14 14 py:with="show_editor = value_of('show_editor', False)" py:strip=""> 15 15 <ul py:if="change.fields" class="changes"> 16 <li py:for="field_name, field in change.fields.items()">16 <li py:for="field_name, field in sorted(change.fields.iteritems(), key=lambda item: item[1].label.lower())"> 17 17 <strong>${field.label}</strong> 18 18 <py:choose> 19 19 <py:when test="field_name == 'attachment'"><i18n:msg params="name"> -
trac/ticket/web_ui.py
diff --git a/trac/ticket/web_ui.py b/trac/ticket/web_ui.py
a b class TicketModule(Component): 454 454 version = int(version) 455 455 except ValueError: 456 456 version = None 457 xhr = req.get_header('X-Requested-With') == 'XMLHttpRequest' 457 458 458 459 req.perm('ticket', id, version).require('TICKET_VIEW') 459 460 ticket = Ticket(self.env, id, version=version) … … class TicketModule(Component): 539 540 # validates and there were no problems with the workflow side of 540 541 # things. 541 542 valid = self._validate_ticket(req, ticket, not valid) and valid 543 if xhr: 544 req.args['preview'] = True 542 545 if 'preview' not in req.args: 543 546 if valid: 544 547 # redirected if successful … … class TicketModule(Component): 572 575 self._insert_ticket_data(req, ticket, data, 573 576 get_reporter_id(req, 'author'), field_changes) 574 577 578 if xhr: 579 # TODO: Differentiate between comment append and comment edit 580 data['change'] = data['change_preview'] 581 return 'ticket_change.html', data, None 582 575 583 mime = Mimeview(self.env) 576 584 format = req.args.get('format') 577 585 if format:
