Index: appengine/monorail/templates/tracker/issue-update-form.ezt |
diff --git a/appengine/monorail/templates/tracker/issue-update-form.ezt b/appengine/monorail/templates/tracker/issue-update-form.ezt |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3b125003071b6527bdafdcde89dc4b8b222583da |
--- /dev/null |
+++ b/appengine/monorail/templates/tracker/issue-update-form.ezt |
@@ -0,0 +1,490 @@ |
+<div id="makechanges"> |
+ [# Note: user must have AddIssueComment permission to even include this file. ] |
+ |
+ <div class="h4" style="margin-bottom: 0" |
+ ><label for="addCommentTextArea">Add a comment |
+ [if-any offer_make_changes]and make changes[end]</label> |
+ </div> |
+ <div id="makechangesarea" class="closed" style="margin-top:0; padding:5px"> |
+ |
+ [if-any discourage_plus_one][if-any page_perms.SetStar][if-any read_only][else] |
+ <div class="updates" style="margin-bottom: 1em; padding-left:5px"> |
+ <a class="star" id="star2" style="text-decoration:none; cursor:pointer; color:[if-any starred]cornflowerblue[else]gray[end]" title="[if-any starred]Un-s[else]S[end]tar this issue"> |
+ [if-any starred]★[else]☆[end] |
+ </a> |
+ <b id="vote_feedback">Vote for this issue and get email change notifications</b> |
+ </div> |
+ [end][end][end] |
+ |
+ <div> |
+ <form action="detail.do" id="issue_update_form" |
+ method="POST" enctype="multipart/form-data"> |
+ <input type="hidden" name="_charset_" value=""> |
+ <input type="hidden" name="token" value="[form_token]"> |
+ <input type="hidden" name="id" value="[issue.local_id]"> |
+ <input type="hidden" name="can" value="[can]"> |
+ <input type="hidden" name="q" value="[query]"> |
+ <input type="hidden" name="colspec" value="[colspec]"> |
+ <input type="hidden" name="sort" value="[sortspec]"> |
+ <input type="hidden" name="groupby" value="[groupby]"> |
+ <input type="hidden" name="start" value="[start]"> |
+ <input type="hidden" name="num" value="[num]"> |
+ <input type="hidden" name="pagegen" value="[pagegen]"> |
+ <table cellpadding="0" cellspacing="0" border="0"> |
+ <tr> |
+ <td> |
+ [if-any errors.comment] |
+ <div class="fielderror">[errors.comment]</div> |
+ [end] |
+ <textarea cols="80" rows="8" name="comment" id="addCommentTextArea" |
+ class="issue_text">[initial_comment]</textarea><br> |
+ [if-any allow_attachments] |
+ <div id="attachmentarea"></div> |
+ <span id="attachprompt"><img width="16" height="16" src="/static/images/paperclip.png" border="0" |
+ alt="A paperclip"> |
+ <a href="#" id="attachafile">Attach a file</a></span> |
+ <span id="attachmaxsize" style="margin-left:2em; display:none">Max. attachments per comment: [max_attach_size]</span><br> |
+ [if-any errors.attachments] |
+ <div class="fielderror">[errors.attachments]</div> |
+ [end] |
+ [else] |
+ <div style="color:#666">Issue attachment storage quota exceeded.</div> |
+ [end] |
+ <br> |
+ </td> |
+ [if-any discourage_plus_one] |
+ <td valign="top"> |
+ <div class="tip"> |
+ Each comment triggers notification emails. |
+ So, please do not post |
+ "<tt style="white-space:nowrap">+1 Me too!</tt>".<br> |
+ Instead, click the star icon. |
+ </div> |
+ </td> |
+ [end] |
+ </tr> |
+ <tr> |
+ <td> |
+ <table cellspacing="0" cellpadding="3" border="0" class="rowmajor"> |
+ [# Only show specific issue fields if the user can edit them.] |
+ [if-any page_perms.EditIssue page_perms.EditIssueSummary] |
+ <tr><th style="width: 1em"><label for="summary">Summary:</label></th> |
+ <td class="inplace" colspan="2"> |
+ <input type="text" size="90" |
+ name="summary" id="summary" value="[initial_summary]"> |
+ [if-any errors.summary] |
+ <div class="fielderror">[errors.summary]</div> |
+ [end] |
+ </td> |
+ </tr> |
+ [end] |
+ |
+ |
+ [if-any page_perms.EditIssue page_perms.EditIssueStatus] |
+ <tr><th><label for="statusedit">Status:</label></th><td class="inplace" colspan="2"> |
+ <input type="text" id="statusedit" style="width: 12em" autocomplete="off" |
+ name="status" value="[initial_status]"> |
+ <span id="merge_area" style="margin-left:2em;"> |
+ Merge into issue: |
+ <input type="text" id="merge_into" name="merge_into" style="width: 5em" |
+ value="[is initial_merge_into "0"][else][initial_merge_into][end]"> |
+ </span> |
+ [if-any errors.merge_into_id] |
+ <div class="fielderror">[errors.merge_into_id]</div> |
+ [end] |
+ </td> |
+ </tr> |
+ [end] |
+ |
+ [if-any page_perms.EditIssue page_perms.EditIssueOwner] |
+ <tr><th><label for="owneredit">Owner:</label></th><td class="inplace"> |
+ <input type="text" id="owneredit" autocomplete="off" |
+ style="width: 12em" |
+ name="owner" value="[is initial_owner "----"][else][initial_owner][end]"> |
+ [if-any errors.owner] |
+ <div class="fielderror" id="ownererror">[errors.owner]</div> |
+ [end] |
+ </td> |
+ </tr> |
+ [end] |
+ |
+ [if-any page_perms.EditIssue page_perms.EditIssueCc] |
+ <tr><th><label for="memberccedit">Cc:</label></th><td class="inplace" colspan="2"> |
+ <input type="text" multiple id="memberccedit" size="90" autocomplete="off" |
+ name="cc" value="[initial_cc]"> |
+ [if-any errors.cc] |
+ <div class="fielderror">[errors.cc]</div> |
+ [end] |
+ </td></tr> |
+ [end] |
+ |
+ [if-any page_perms.EditIssue] [# TODO(jrobbins): page_perms.EditIssueComponent] |
+ <tr><th><label for="componentedit">Components:</label></th><td class="inplace" colspan="2"> |
+ <input type="text" id="componentedit" size="90" autocomplete="off" |
+ name="components" value="[initial_components]"> |
+ [if-any errors.components] |
+ <div class="fielderror">[errors.components]</div> |
+ [end] |
+ </td></tr> |
+ [end] |
+ |
+ [if-any page_perms.EditIssue][# Show field editing elements iff user can edit.] |
+ [define any_fields_to_reveal]No[end] |
+ <tbody class="collapse"> |
+ [for fields] |
+ [if-any fields.applicable] |
+ [# TODO(jrobbins): determine applicability dynamically and update fields in JS] |
+ <tr [if-any fields.display][else]class="ifExpand"[define any_fields_to_reveal]Yes[end][end]> |
+ <th class="vt" title="[fields.field_def.docstring_short][if-any fields.field_def.validate_help] |
+ [fields.field_def.validate_help][end]">[fields.field_name]:</th> |
+ <td class="vt"> |
+ [include "field-value-widgets.ezt" fields.field_def.is_multivalued_bool] |
+ <div class="fielderror" style="display:none" id="error_custom_[fields.field_id]"></div> |
+ </td> |
+ <tr> |
+ [end] |
+ [end] |
+ [is any_fields_to_reveal "Yes"] |
+ <tr class="ifCollapse"> |
+ <td colspan="2"><a href="#" class="toggleCollapse">Show all fields</a><t/td> |
+ </tr> |
+ [end] |
+ </tbody> |
+ [end] |
+ |
+ |
+ [if-any page_perms.EditIssue][# Show label editing elements iff the user can edit.] |
+ <tr><th class="vt"><label for="label0">Labels:</label></th> |
+ <td class="labelediting" colspan="2"> |
+ [include "label-fields.ezt" "just-two"] |
+ </td> |
+ </tr> |
+ |
+ <tr><th style="white-space:nowrap"><label for="blocked_on">Blocked on:</label></th> |
+ <td class="inplace" colspan="2"> |
+ <input type="text" name="blocked_on" id="blocked_on" value="[initial_blocked_on]"> |
+ [if-any errors.blocked_on] |
+ <div class="fielderror">[errors.blocked_on]</div> |
+ [end] |
+ </td> |
+ </tr> |
+ <tr><th><label for="blocking">Blocking:</label></th> |
+ <td class="inplace" colspan="2"> |
+ <input type="text" name="blocking" id="blocking" value="[initial_blocking]" /> |
+ [if-any errors.blocking] |
+ <div class="fielderror">[errors.blocking]</div> |
+ [end] |
+ </td> |
+ </tr> |
+ |
+ <tr id="copy_issue_form_fragment" style="display:none"> |
+ <td style="white-space:nowrap"> |
+ <b><label for="copy_to">Copy to project:</label> </b> |
+ </td> |
+ <td> |
+ <input type="text" name="copy_to" id="copy_to" autocomplete="off" |
+ [if-any errors.copy_to_project]value="[errors.copy_to_project]"[else]value="[projectname]"[end] > |
+ <span id="derived_labels_target"></span> |
+ [if-any errors.copy_to] |
+ <div class="fielderror">[errors.copy_to]</div> |
+ [end] |
+ </td> |
+ </tr> |
+ |
+ <tr id="move_issue_form_fragment" style="display:none"> |
+ <td style="white-space:nowrap"> |
+ <b><label for="move_to">Move to project:</label> </b> |
+ </td> |
+ <td> |
+ <input type="text" name="move_to" id="move_to" autocomplete="off" |
+ [if-any errors.move_to_project]value="[errors.move_to_project]"[end] > |
+ <span id="derived_labels_target"></span> |
+ [if-any errors.move_to] |
+ <div class="fielderror">[errors.move_to]</div> |
+ [end] |
+ </td> |
+ </tr> |
+ |
+ [end][# if page_perms.EditIssue] |
+ |
+ [if-any show_captcha] |
+ <tr><th class="vt" style="white-space:nowrap">Human Verification:</th> |
+ <td colspan="2"> |
+ [include "../framework/captcha-field.ezt"] |
+ </td> |
+ </tr> |
+ [end] |
+ |
+ [include "../framework/label-validation-row.ezt"] |
+ </table> |
+ |
+ <input type="submit" id="submit_btn" name="btn" value="Save changes"> |
+ <input type="button" id="discard" name="nobtn" value="Discard" data-local-id="[issue.local_id]"> |
+ [if-any page_perms.EditIssue] |
+ <span style="margin-left:1.5em"><label for="after_issue_update">And then:</label></span> |
+ <select name="after_issue_update" id="after_issue_update"> |
+ <option value="0" [is after_issue_update "0"]selected=selected[end]>Go up to issue list</option> |
+ <option value="1" [is after_issue_update "1"]selected=selected[end]>Stay on this issue</option> |
+ <option value="2" [is after_issue_update "2"]selected=selected[end]>Go to next issue</option> |
+ </select> |
+ <input type="hidden" name="next_id" value="[if-any flipper.show][flipper.next_id][else][end]"> |
+ [end] |
+ |
+ [if-any page_perms.EditIssue] |
+ <input type="checkbox" checked="checked" name="send_email" id="send_email" |
+ style="margin-left:1.5em"> |
+ <label for="send_email" title="Send issue change notifications to interested users">Send email</label> |
+ [end] |
+ |
+ [if-any page_perms.DeleteIssue] |
+ <label for="more_actions" style="margin-left:3em">More actions:</label> |
+ <select name="more_actions" id="more_actions" style="display:none"> |
+ <option value="0" selected="selected" disabled="1">More actions...</option> |
+ <option value="delete">Delete issue</option> |
+ <option value="copy" [if-any offer_issue_copy_move][else]disabled="disabled"[end]>Copy issue</option> |
+ <option value="move" [if-any offer_issue_copy_move][else]disabled="disabled"[end]>Move issue</option> |
+ </select> |
+ [end] |
+ |
+ </td> |
+ </tr> |
+ </table> |
+ </form> |
+ |
+ [if-any page_perms.DeleteIssue] |
+ <div id="delete_div"><br><br> |
+ <form action="delete.do" method="post" id="delete_form"> |
+ <input type="hidden" name="token" value="[delete_form_token]"> |
+ <input type="hidden" name="id" value="[issue.local_id]"> |
+ <input type="hidden" name="delete" value="true"> |
+ <input type="submit" name="deletebtn" value="Delete issue"> |
+ </form> |
+ </div> |
+ |
+ <script type="text/javascript" nonce="[nonce]"> |
+runOnLoad(function() { |
+ [# Hide the non-js UI and show a better UI to users that have JS enabled.] |
+ [if-any errors.copy_to][else] |
+ document.getElementById('copy_issue_form_fragment').style.display = "none"; |
+ [end] |
+ [if-any errors.move_to][else] |
+ document.getElementById('move_issue_form_fragment').style.display = "none"; |
+ [end] |
+ [if-any page_perms.DeleteIssue] |
+ document.getElementById('delete_div').style.display = "none"; |
+ [end] |
+ |
+ // TODO(jobbins): _attachIssueMoveValidator('move_to', '[issue.local_id]'); |
+}); |
+ </script> |
+ |
+ <script type="text/javascript" nonce="[nonce]"> |
+runOnLoad(function() { |
+ var more_actions = document.getElementById('more_actions'); |
+ more_actions.style.display = ""; |
+}); |
+ </script> |
+ [end] |
+ |
+ |
+ </div>[# makechangesarea] |
+</div>[# makechanges] |
+ |
+ |
+<script type="text/javascript" nonce="[nonce]"> |
+runOnLoad(function() { |
+ if ($("attachafile")) { |
+ $("attachafile").addEventListener("click", function(event) { |
+ _addAttachmentFields("attachmentarea"); |
+ event.preventDefault(); |
+ }); |
+ } |
+ |
+ if ($("addCommentTextArea")) { |
+ $("addCommentTextArea").addEventListener("keyup", function(event) { |
+ _dirty(); |
+ return true; |
+ }); |
+ } |
+ |
+ if ($("submit_btn")) { |
+ $("submit_btn").addEventListener("focus", function(event) { |
+ _acrob(null); |
+ }); |
+ $("submit_btn").addEventListener("mousedown", function(event) { |
+ _acrob(null); |
+ }); |
+ $("submit_btn").addEventListener("click", function(event) { |
+ _trimCommas(); |
+ userMadeChanges = false; |
+ TKR_isDirty = false; |
+ }); |
+ } |
+ if ($("discard")) { |
+ $("discard").addEventListener("focus", function(event) { |
+ _acrob(null); |
+ }); |
+ $("discard").addEventListener("click", function(event) { |
+ _acrob(null); |
+ _confirmDiscardUpdate('detail?id=' + event.target.getAttribute("data-local-id")); |
+ return false; |
+ }); |
+ } |
+ if ($("more_actions")) { |
+ $("more_actions").addEventListener("change", function(event) { |
+ _handleDetailActions(); |
+ }); |
+ } |
+ |
+ if ($("summary")) { |
+ $("summary").addEventListener("focus", function(event) { |
+ _acrob(null); |
+ _acof(event); |
+ }); |
+ $("summary").addEventListener("keyup", function(event) { |
+ _dirty(); |
+ return true; |
+ }); |
+ } |
+ if ($("blocked_on")) { |
+ $("blocked_on").addEventListener("focus", function(event) { |
+ _acrob(null); |
+ _acof(event); |
+ }); |
+ $("blocked_on").addEventListener("keyup", function(event) { |
+ _dirty(); |
+ return true; |
+ }); |
+ } |
+ if ($("statusedit")) { |
+ $("statusedit").addEventListener("focus", function(event) { |
+ _acof(event); |
+ }); |
+ $("statusedit").addEventListener("keyup", function(event) { |
+ _dirty(); |
+ return _confirmNovelStatus($("statusedit")); |
+ }); |
+ } |
+ |
+ var _idsToAddDefaultListeners = [[] |
+ "owneredit", "memberccedit", "componentedit", "copy_to", "move_to"]; |
+ for (var i = 0; i < _idsToAddDefaultListeners.length; i++) { |
+ var id = _idsToAddDefaultListeners[[]i]; |
+ if ($(id)) { |
+ $(id).addEventListener("focus", function(event) { |
+ _acof(event); |
+ }); |
+ $(id).addEventListener("keyup", function(event) { |
+ _dirty(); |
+ return true; |
+ }); |
+ } |
+ } |
+ |
+ _allOrigLabels = [[] |
+ "[label0]", "[label1]", "[label2]", "[label3]", "[label4]", |
+ "[label5]", "[label6]", "[label7]", "[label8]", "[label9]", |
+ "[label10]", "[label11]", "[label12]", "[label13]", "[label14]", |
+ "[label15]", "[label16]", "[label17]", "[label18]", "[label19]", |
+ "[label20]", "[label21]", "[label22]", "[label23]"]; |
+ |
+ _lfidprefix = 'labeledit'; |
+ |
+ window.allowSubmit = true; |
+ $("issue_update_form").addEventListener("submit", function(event) { |
+ if (!_checkPlusOne()) |
+ event.preventDefault(); |
+ [# User cannot remove restricted labels if they cannot see them.] |
+ [if-any page_perms.EditIssue] |
+ if (!_checkUnrestrict([if-any prevent_restriction_removal]true[else]false[end])) |
+ event.preventDefault(); |
+ [end] |
+ if (allowSubmit) { |
+ allowSubmit = false; |
+ $("submit_btn").value = "Adding comment..."; |
+ $("submit_btn").disabled = "disabled"; |
+ } |
+ else { |
+ event.preventDefault(); |
+ } |
+ }); |
+ |
+ if ($("star2")) |
+ $("star2").addEventListener("click", function (event) { |
+ _TKR_toggleStar($("star2"), "[projectname]", [issue.local_id], "[set_star_token]"); |
+ _TKR_syncStarIcons($("star2"), "star"); |
+ }); |
+ |
+ if ($("flag_spam")) { |
+ $("flag_spam").addEventListener("click", function(event) { |
+ $("spam_form").submit(); |
+ return; |
+ }); |
+ } |
+}); |
+</script> |
+ |
+[# If the user can edit issue metadata, we need to do a bunch of JS setup for editing features. |
+ Otherwise, if they can only enter comments, they still might need to retry a failed CAPTCHA. ] |
+ |
+[if-any page_perms.EditIssue page_perms.EditIssueStatus page_perms.EditIssueOwner page_perms.EditIssueCc] |
+<script type="text/javascript" nonce="[nonce]"> |
+runOnLoad(function() { |
+ [if-any page_perms.EditIssue] |
+ _exposeExistingLabelFields(); |
+ [end] |
+ |
+ [if-any errors.custom_fields] |
+ [for errors.custom_fields] |
+ var field_error; |
+ field_error = document.getElementById('error_custom_' + [errors.custom_fields.field_id]); |
+ field_error.innerText = "[errors.custom_fields.message]"; |
+ field_error.style.display = ""; |
+ [end] |
+ [end] |
+ |
+ |
+function checksubmit() { |
+ var restrict_to_known = [if-any restrict_to_known]true[else]false[end]; |
+ var submit = $('submit_btn'); |
+ var blocksubmitmsg = $('blocksubmitmsg'); |
+ var cg = $('cg'); |
+ if (cg != undefined) { submit.disabled='disabled'; } |
+ var confirmmsg = $('confirmmsg'); |
+ var statusedit = $('statusedit'); |
+ var merge_area = $('merge_area'); |
+ var statuses_offer_merge = [[] [for statuses_offer_merge]"[statuses_offer_merge]"[if-index statuses_offer_merge last][else],[end][end] ]; |
+ if ((restrict_to_known && confirmmsg && confirmmsg.innerText) || |
+ (blocksubmitmsg && blocksubmitmsg.innerHTML) || |
+ (cg && cg.value == "") || |
+ (!allowSubmit)) { |
+ submit.disabled='disabled'; |
+ } else { |
+ submit.disabled=''; |
+ } |
+ |
+ if (statusedit) { |
+ var offer_merge = 'none'; |
+ for (var i = 0; i < statuses_offer_merge.length; i++) { |
+ if (statusedit.value == statuses_offer_merge[[]i]) offer_merge = ''; |
+ } |
+ merge_area.style.display = offer_merge; |
+ } |
+} |
+ |
+[if-any any_errors] |
+ // Take user directly to the errors. |
+ if (!location.hash) { |
+ location.hash = "#makechanges"; |
+ } |
+[end] |
+ |
+checksubmit(); |
+setInterval(checksubmit, 700); [# catch changes that were not keystrokes, e.g., paste menu item.] |
+ |
+}); |
+</script> |
+[end] |
+ |
+ |
+[include "field-value-widgets-js.ezt"] |