Implement replying to comments.
--- 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;
}
}
}