changeset 6823:2e72d2d16a0f

comments: display comment previews while submitting Instead of just saying 'Submitting' and not showing any progress to the user until the comment has been accepted by the server, show a preview of the comment above the comment box in a way which is makes it obvious to the user the comment is being submitted. Apart from that, also clear the comment box so that a repeated clicking the submit button doesn't result in a duplicate comment. The preview doesn't highlight URLs or support @mentions or *bold*, which is a good enough approximation in this case. When/if we (re-)add the rST/Markdown support, we will need a client-side parser for the syntax we choose. When the submission fails, display a message and offer the user to retry or cancel the submission.
author Andrew Shadura <andrew@shadura.me>
date Mon, 10 Jul 2017 13:13:10 -0500
parents 385c85f19d8d
children 2983dd668fd1
files kallithea/public/css/style.css kallithea/public/js/base.js kallithea/templates/base/root.html kallithea/templates/changeset/changeset_file_comment.html
diffstat 4 files changed, 115 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/kallithea/public/css/style.css	Mon Jul 03 22:17:28 2017 +0200
+++ b/kallithea/public/css/style.css	Mon Jul 10 13:13:10 2017 -0500
@@ -2796,6 +2796,40 @@
     border-radius: 4px !important;
 }
 
+@keyframes animated-comment-background {
+    0% { background-position: 0 0; }
+    100% { background-position: 20px 0; }
+}
+
+.comment-preview.failed .user,
+.comment-preview.failed .panel-body {
+    color: #666;
+}
+
+.comment-preview .comment-submission-status {
+    float: right;
+}
+
+.comment-preview .comment-submission-status .btn-group {
+    margin-left: 10px;
+}
+
+.comment-preview.submitting .panel-body {
+    background-image: linear-gradient(
+        -45deg,
+        #FAFAFA,
+        #FAFAFA 25%,
+        #FFF 25%,
+        #FFF 50%,
+        #FAFAFA 50%,
+        #FAFAFA 75%,
+        #FFF 75%,
+        #FFF 100%
+    );
+    background-size: 20px 20px;
+    animation: animated-comment-background 0.4s linear infinite;
+}
+
 /****
 PULL REQUESTS
 *****/
--- a/kallithea/public/js/base.js	Mon Jul 03 22:17:28 2017 +0200
+++ b/kallithea/public/js/base.js	Mon Jul 10 13:13:10 2017 -0500
@@ -647,6 +647,7 @@
         .clone()
         .addClass('comment-inline-form');
     $comment_div.append($form_div);
+    var $preview = $comment_div.find("div.comment-preview");
     var $form = $comment_div.find("form");
     var $textarea = $form.find('textarea');
 
@@ -678,7 +679,18 @@
             }
         }
 
-        $form.find('.submitting-overlay').show();
+        if (review_status) {
+            var $review_status = $preview.find('.automatic-comment');
+            var review_status_lbl = $("#comment-inline-form-template input.status_change_radio[value='" + review_status + "']").parent().text().strip();
+            $review_status.find('.comment-status-label').text(review_status_lbl);
+            $review_status.show();
+        }
+        $preview.find('.comment-text div').text(text);
+        $preview.show();
+        $textarea.val('');
+        if (f_path && line_no) {
+            $form.hide();
+        }
 
         var postData = {
             'text': text,
@@ -702,7 +714,33 @@
                 }
             }
         };
-        ajaxPOST(AJAX_COMMENT_URL, postData, success);
+        var failure = function(x, s, e) {
+            $preview.removeClass('submitting').addClass('failed');
+            var $status = $preview.find('.comment-submission-status');
+            $('<span>', {
+                'title': e,
+                text: _TM['Unable to post']
+            }).replaceAll($status.contents());
+            $('<div>', {
+                'class': 'btn-group'
+            }).append(
+                $('<button>', {
+                    'class': 'btn btn-default btn-xs',
+                    text: _TM['Retry']
+                }).click(function() {
+                    $status.text(_TM['Submitting ...']);
+                    $preview.addClass('submitting').removeClass('failed');
+                    ajaxPOST(AJAX_COMMENT_URL, postData, success, failure);
+                }),
+                $('<button>', {
+                    'class': 'btn btn-default btn-xs',
+                    text: _TM['Cancel']
+                }).click(function() {
+                    comment_div_state($comment_div, f_path, line_no);
+                })
+            ).appendTo($status);
+        };
+        ajaxPOST(AJAX_COMMENT_URL, postData, success, failure);
     });
 
     // add event handler for hide/cancel buttons
--- a/kallithea/templates/base/root.html	Mon Jul 03 22:17:28 2017 +0200
+++ b/kallithea/templates/base/root.html	Mon Jul 10 13:13:10 2017 -0500
@@ -22,13 +22,17 @@
         <script type="text/javascript">
             ## JS translations map
             var TRANSLATION_MAP = {
-                'Add Another Comment':${h.jshtml(_("Add Another Comment"))},
-                'Stop following this repository':${h.jshtml(_('Stop following this repository'))},
-                'Start following this repository':${h.jshtml(_('Start following this repository'))},
-                'Group':${h.jshtml(_('Group'))},
-                'members':${h.jshtml(_('members'))},
-                'Loading ...':${h.jshtml(_('Loading ...'))},
-                'loading ...':${h.jshtml(_('loading ...'))},
+                'Cancel': ${h.jshtml(_("Cancel"))},
+                'Retry': ${h.jshtml(_("Retry"))},
+                'Submitting ...': ${h.jshtml(_("Submitting ..."))},
+                'Unable to post': ${h.jshtml(_("Unable to post"))},
+                'Add Another Comment': ${h.jshtml(_("Add Another Comment"))},
+                'Stop following this repository': ${h.jshtml(_('Stop following this repository'))},
+                'Start following this repository': ${h.jshtml(_('Start following this repository'))},
+                'Group': ${h.jshtml(_('Group'))},
+                'members': ${h.jshtml(_('members'))},
+                'Loading ...': ${h.jshtml(_('Loading ...'))},
+                'loading ...': ${h.jshtml(_('loading ...'))},
                 'Search truncated': ${h.jshtml(_('Search truncated'))},
                 'No matching files': ${h.jshtml(_('No matching files'))},
                 'Open New Pull Request from {0}': ${h.jshtml(_('Open New Pull Request from {0}'))},
--- a/kallithea/templates/changeset/changeset_file_comment.html	Mon Jul 03 22:17:28 2017 +0200
+++ b/kallithea/templates/changeset/changeset_file_comment.html	Mon Jul 10 13:13:10 2017 -0500
@@ -34,14 +34,16 @@
         %if co.status_change:
            <div class="automatic-comment">
              <p>
-               ${_("Status change")}: ${co.status_change[0].status_lbl}
+               ${_("Status change")}: <span class="comment-status-label">${co.status_change[0].status_lbl}</span>
                <i class="icon-circle changeset-status-${co.status_change[0].status}"></i>
              </p>
            </div>
         %endif
+        <div class="comment-text">
         %if co.text:
           ${h.render_w_mentions(co.text, c.repo_name)|n}
         %endif
+        </div>
       </div>
     </div>
   </div>
@@ -49,7 +51,33 @@
 
 
 <%def name="comment_inline_form()">
-<div id='comment-inline-form-template' style="display:none">
+<div id='comment-inline-form-template' style="display: none;">
+  <div class="comment comment-preview submitting" style="display: none;">
+    <div class="panel panel-default">
+      <div class="panel-heading">
+          ${h.gravatar_div(request.authuser.email, size=20)}
+          <span class="user">
+              ${request.authuser.full_name_or_username}
+          </span>
+
+          <span class="comment-submission-status">
+              ${_('Submitting ...')}
+          </span>
+      </div>
+      <div class="panel-body">
+           <div class="automatic-comment" style="display: none;">
+             <p>
+               ${_("Status change")}: <span class="comment-status-label"></span>
+               <i class="icon-circle"></i>
+             </p>
+           </div>
+           <div class="comment-text">
+             <div class="formatted-fixed">
+             </div>
+           </div>
+      </div>
+    </div>
+  </div>
   <div class="ac">
   %if request.authuser.username != 'default':
     ${h.form('#', class_='inline-form')}
@@ -97,7 +125,6 @@
 
       </div>
       <div class="comment-button">
-        <div class="submitting-overlay" style="display:none">${_('Submitting ...')}</div>
         ${h.submit('save', _('Comment'), class_='btn btn-default btn-sm save-inline-form')}
         ${h.reset('hide-inline-form', _('Cancel'), class_='btn btn-default btn-sm hide-inline-form')}
       </div>