Implement replying to comments.
authorAlexandre Segura <mex.zktk@gmail.com>
Mon, 27 Feb 2017 17:50:14 +0100
changeset 396 0a4743126d74
parent 395 e5286c7506b5
child 397 b936a1aab4dc
Implement replying to comments.
src/iconolab/serializers.py
src/iconolab/settings/dev.py.tmpl
src/iconolab/templates/iconolab/detail_image.html
src/iconolab/templates/partials/comment_form.html
src_js/iconolab-bundle/src/components/editor/Comment.vue
src_js/iconolab-bundle/src/components/editor/CommentList.vue
src_js/iconolab-bundle/src/iconolab.scss
--- a/src/iconolab/serializers.py	Mon Feb 27 17:47:22 2017 +0100
+++ b/src/iconolab/serializers.py	Mon Feb 27 17:50:14 2017 +0100
@@ -25,6 +25,7 @@
 
 
 class IconolabCommentSerializer(serializers.ModelSerializer):
+    allow_thread = serializers.BooleanField()
     class Meta:
         model = IconolabComment
         fields = '__all__'
--- a/src/iconolab/settings/dev.py.tmpl	Mon Feb 27 17:47:22 2017 +0100
+++ b/src/iconolab/settings/dev.py.tmpl	Mon Feb 27 17:50:14 2017 +0100
@@ -83,7 +83,7 @@
 COMMENTS_APP = "django_comments_xtd"
 COMMENTS_XTD_MODEL = "iconolab.models.IconolabComment"
 COMMENTS_XTD_FORM_CLASS = 'iconolab.forms.comments.IconolabCommentForm'
-COMMENTS_XTD_MAX_THREAD_LEVEL = 100
+COMMENTS_XTD_MAX_THREAD_LEVEL = 1
 COMMENTS_PER_PAGE_DEFAULT = 10
 
 SITE_ID = 1
--- a/src/iconolab/templates/iconolab/detail_image.html	Mon Feb 27 17:47:22 2017 +0100
+++ b/src/iconolab/templates/iconolab/detail_image.html	Mon Feb 27 17:50:14 2017 +0100
@@ -60,15 +60,15 @@
           action="{% url 'annotation_edit' collection_name image_guid ':annotation_guid' %}">
           {% csrf_token %}
         </annotation-form>
-        <comment-list v-bind:annotation="annotation"
-          fetch="{% url 'get_annotation_comments_json' ':annotation_guid' %}"></comment-list>
-        <div id="form-comment">
-          <form style="display: none;">
-              <div class="form-group">
-                <textarea class="form-control input-sm" placeholder="Ajouter mon commentaire..." disabled></textarea>
-              </div>
-              <button type="submit" class="btn btn-block btn-sm btn-primary" disabled>Commenter</button>
-          </form>
+        <div style="display: none;" class="annotation-comment-list">
+          <label class="small text-muted">Commentaires</label>
+          <comment-list v-bind:annotation="annotation"
+            fetch="{% url 'get_annotation_comments_json' ':annotation_guid' %}"></comment-list>
+        </div>
+        <div class="annotation-comment-box" id="form-comment">
+          <comment-form v-if="annotation">
+            <button slot="submit" type="submit" class="btn btn-block btn-sm btn-primary">Commenter</button>
+          </comment-form>
         </div>
       </div>
     </div>
@@ -84,6 +84,15 @@
   var getCommentFormURL = "{% url 'get_comment_form' ':annotation_guid' %}"
   var isAuthenticated = {% if user.is_authenticated %}true{% else %}false{% endif %};
 
+  Vue.component('comment-form', {
+    template: '<div></div>',
+    data: function() {
+      return {
+        replyTo: 0
+      }
+    }
+  });
+
   var vm = new Vue({
     el: '.annotation-navigator',
     data: function() {
@@ -110,12 +119,17 @@
     $.get(getCommentFormURL.replace(':annotation_guid', annotation), { next: currentPath + '#' + annotation })
       .then(function(form) {
 
+        Vue.component('comment-form', function (resolve, reject) {
+          resolve({
+            props: ['reply-to'],
+            template: form,
+          });
+        });
+
         $('.list-group a[data-annotation-id]').removeClass('active');
         $el.addClass('active');
 
-        if (isAuthenticated) {
-          $('#form-comment form').replaceWith(form).show();
-        }
+        $('.annotation-comment-list').show();
 
         vm.annotation = annotations[revision];
 
@@ -156,10 +170,7 @@
 
     vm.annotation = null;
 
-    $('#form-comment form')
-      .hide()
-      .find('textarea, [type="submit"]')
-      .attr('disabled', true);
+    $('.annotation-comment-list').hide();
 
     location.hash = '';
   });
@@ -181,7 +192,7 @@
       }
     }
   }
-  window.addEventListener('hashchange', function() { router(false) });
+  window.addEventListener('hashchange', function() { router(true) });
   window.addEventListener('load', function() { router(true) });
 
 </script>
--- a/src/iconolab/templates/partials/comment_form.html	Mon Feb 27 17:47:22 2017 +0100
+++ b/src/iconolab/templates/partials/comment_form.html	Mon Feb 27 17:50:14 2017 +0100
@@ -8,21 +8,15 @@
   {{ comment_form.security_hash }}
 
   <input type="hidden" name="next" value="{{ next }}">
-  <input type="hidden" name="reply_to" value="0"></input>
+  <input type="hidden" name="reply_to" v-bind:value="replyTo || 0"></input>
 
-  <fieldset class="form-group {% if comment_form.comment.errors %}has-error{% endif %}">
-    {% if comment_form.comment.errors %}
-      <div class="alert alert-danger" role="alert">
-        <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
-        <span class="sr-only">Erreur :</span>
-          {{ comment_form.comment.errors | striptags }}
-      </div>
-    {% endif %}
+  <fieldset class="form-group form-group-sm">
     <textarea class="form-control input-sm"
       name="{{ comment_form.comment.name }}"
       id="id_{{ comment_form.comment.name }}"
       placeholder="Ajouter mon commentaire..."></textarea>
   </fieldset>
-  <input class="btn btn-block btn-sm btn-primary" type="submit" name="post" class="submit-post" value="Commenter">
+
+  <slot name="submit"></slot>
 
 </form>
--- a/src_js/iconolab-bundle/src/components/editor/Comment.vue	Mon Feb 27 17:47:22 2017 +0100
+++ b/src_js/iconolab-bundle/src/components/editor/Comment.vue	Mon Feb 27 17:50:14 2017 +0100
@@ -1,9 +1,16 @@
 <template>
-    <div class="comment">
-        <div class="comment-body" v-html="commentFormatted"></div>
+    <div class="comment" v-bind:style="{ marginLeft: (level * 15) + 'px' }">
+        <div class="comment-body">
+            <strong class="comment-author">{{ username }}</strong>
+            <div class="comment-content" v-html="commentFormatted"></div>
+        </div>
         <div class="comment-footer">
-            <span class="comment-author">{{ username }}</span>
+            <a v-if="allowThread" href="#" v-on:click.prevent="showForm = !showForm">Répondre</a>
             <span class="comment-date">{{ dateFormatted }}</span>
+            <comment-form v-bind:reply-to="id" v-if="allowThread" v-show="showForm">
+                <button slot="submit" type="submit" class="btn btn-xs btn-primary">Valider</button>
+                <a slot="submit" href="#" v-on:click.prevent="showForm = false" class="text-muted" style="margin-left: 5px;">Annuler</a>
+            </comment-form>
         </div>
     </div>
 </template>
@@ -12,15 +19,26 @@
 
     import showdown from 'showdown'
 
-    const converter = new showdown.Converter()
+    const converter = new showdown.Converter({
+        simpleLineBreaks: true
+    })
 
     export default {
+        components: ['comment-form'],
         props: [
+            'id',
+            'level',
             'comment',
             'username',
             'email',
-            'date'
+            'date',
+            'allowThread'
         ],
+        data() {
+            return {
+                showForm: false
+            }
+        },
         computed: {
             dateFormatted: function () {
 
@@ -46,11 +64,15 @@
     padding: 5px 0;
     border-bottom: 1px solid #ccc;
 }
+.comment-author {
+    float: left;
+    margin-right: 4px;
+}
+.comment-date {
+
+}
 .comment-footer {
     margin-top: 5px;
     color: #ccc;
 }
-.comment-date {
-    float: right;
-}
 </style>
--- a/src_js/iconolab-bundle/src/components/editor/CommentList.vue	Mon Feb 27 17:47:22 2017 +0100
+++ b/src_js/iconolab-bundle/src/components/editor/CommentList.vue	Mon Feb 27 17:50:14 2017 +0100
@@ -1,12 +1,14 @@
 <template>
-    <div v-show="annotation">
-        <label class="small text-muted">Commentaires</label>
+    <div v-show="annotation" class="wrapper">
         <div v-show="comments.length === 0" class="alert alert-info">Pas de commentaire pour le moment.</div>
         <comment
             v-for="comment in comments"
+            v-bind:id="comment.id"
+            v-bind:level="comment.level"
             v-bind:comment="comment.comment"
             v-bind:username="comment.user_name"
-            v-bind:date="comment.submit_date"></comment>
+            v-bind:date="comment.submit_date"
+            v-bind:allowThread="comment.allow_thread"></comment>
     </div>
 </template>
 
@@ -43,6 +45,10 @@
 </script>
 
 <style scoped>
+.wrapper {
+    max-height: 200px;
+    overflow-y: scroll;
+}
 .alert {
     padding: 10px;
     font-size: 12px;
--- a/src_js/iconolab-bundle/src/iconolab.scss	Mon Feb 27 17:47:22 2017 +0100
+++ b/src_js/iconolab-bundle/src/iconolab.scss	Mon Feb 27 17:50:14 2017 +0100
@@ -346,23 +346,21 @@
         }
         .panel {
             margin-bottom: 0;
-            max-height: 600px;
-            height: 600px;
-            overflow-y: scroll;
         }
         .panel-body {
             flex-direction: column;
             justify-content: space-between;
 
             > * {
-                flex: 1;
+                flex: 1 1 auto;
             }
             > *:last-child {
                 display: flex;
                 flex-direction: column;
                 justify-content: flex-end;
-
-                padding-bottom : 20px;
+            }
+            .annotation-comment-box {
+                padding-top: 15px;
             }
         }
     }