Implement annotation on the whole picture.
authorAlexandre Segura <mex.zktk@gmail.com>
Tue, 16 May 2017 11:29:33 +0200
changeset 504 11a862e01b04
parent 503 a6290b2fae6b
child 505 bf5439a77a8d
Implement annotation on the whole picture.
src/iconolab/templates/iconolab/detail_image.html
src_js/iconolab-bundle/src/components/editor/AnnotationForm.vue
src_js/iconolab-bundle/src/components/editor/Canvas.vue
src_js/iconolab-bundle/src/components/editor/CommentList.vue
--- a/src/iconolab/templates/iconolab/detail_image.html	Mon May 15 14:44:14 2017 +0200
+++ b/src/iconolab/templates/iconolab/detail_image.html	Tue May 16 11:29:33 2017 +0200
@@ -41,7 +41,8 @@
       v-bind:is-authenticated="isAuthenticated"
       v-bind:annotations="annotations"
       v-on:click:annotation="onAnnotationClick($event)"
-      v-on:close:annotation="onAnnotationClose"></image-annotator>
+      v-on:close:annotation="onAnnotationClose"
+      v-on:add:annotation="onAnnotationAdd"></image-annotator>
     <form id="form-annotation" action="{% url 'annotation_create' collection_name image.image_guid %}" method="POST">
       {% csrf_token %}
       <input type="hidden" name="{{ form.title.name }}">
@@ -55,15 +56,17 @@
       <div class="panel-body">
         <annotation-form v-bind:annotation="annotation"
           v-bind:is-authenticated="isAuthenticated"
-          action="{% url 'annotation_edit' collection_name image_guid ':annotation_guid' %}"
+          new-annotation-url="{% url 'annotation_create' collection_name image.image_guid %}"
+          edit-annotation-url="{% url 'annotation_edit' collection_name image_guid ':annotation_guid' %}"
           revisions-url="{% url 'annotation_revisions' collection_name image_guid ':annotation_guid' %}"
-          author-url="{% url 'user_home' '--username--' %}">
+          author-url="{% url 'user_home' '--username--' %}"
+          v-on:close="onAnnotationClose">
           {% csrf_token %}
         </annotation-form>
         <div class="annotation-comment-box" id="form-comment">
-          <comment-form v-if="annotation &amp;&amp; isAuthenticated"></comment-form>
+          <comment-form v-if="showCommentForm"></comment-form>
         </div>
-        <div v-show="annotation" style="display: none;" class="annotation-comment-list">
+        <div v-show="showCommentList" style="display: none;" class="annotation-comment-list">
           <label class="small text-muted">Commentaires</label>
           <comment-list v-bind:annotation="annotation"
             v-bind:is-authenticated="isAuthenticated"
@@ -159,18 +162,31 @@
           isAuthenticated: isAuthenticated,
         };
       },
+      computed: {
+        showCommentForm: function() {
+          return this.annotation && this.annotation.annotation_guid && this.isAuthenticated
+        },
+        showCommentList: function() {
+          return this.annotation && this.annotation.annotation_guid
+        }
+      },
       methods: {
         onAnnotationClick: function(annotation) {
           var self = this;
-          getCommentForm(annotation).then(function(template) {
-            updateCommentFormComponent(template);
-            self.annotation = annotation;
-            history.pushState({ annotation_guid: annotation.annotation_guid }, '', annotationURL.replace(':annotation_guid', annotation.annotation_guid));
-          });
+          if (annotation.annotation_guid) {
+            getCommentForm(annotation).then(function(template) {
+              updateCommentFormComponent(template);
+              self.annotation = annotation;
+              history.pushState({ annotation_guid: annotation.annotation_guid }, '', annotationURL.replace(':annotation_guid', annotation.annotation_guid));
+            });
+          }
         },
         onAnnotationClose: function() {
           this.annotation = null;
           history.pushState({ annotation_guid: null }, '', imageURL);
+        },
+        onAnnotationAdd: function() {
+          addAnnotationWithoutFragment()
         }
       }
     });
@@ -238,9 +254,11 @@
   }
 
   function getCommentForm(annotation) {
-    return $.get(getCommentFormURL.replace(':annotation_guid', annotation.annotation_guid), {
-      next: annotationURL.replace(':annotation_guid', annotation.annotation_guid)
-    })
+    if (annotation.annotation_guid) {
+      return $.get(getCommentFormURL.replace(':annotation_guid', annotation.annotation_guid), {
+        next: annotationURL.replace(':annotation_guid', annotation.annotation_guid)
+      })
+    }
   }
 
   function getAnnotationByGuid(guid) {
@@ -249,5 +267,15 @@
     });
   }
 
+  function addAnnotationWithoutFragment() {
+    vm.annotation = {
+      annotation_guid: null,
+      title: '',
+      description: '',
+      fragment: '',
+      tags:[]
+    }
+  }
+
 </script>
 {% endblock %}
--- a/src_js/iconolab-bundle/src/components/editor/AnnotationForm.vue	Mon May 15 14:44:14 2017 +0200
+++ b/src_js/iconolab-bundle/src/components/editor/AnnotationForm.vue	Tue May 16 11:29:33 2017 +0200
@@ -2,7 +2,8 @@
     <div>
         <button
             data-intro="Proposez une nouvelle version" data-position="left"
-            v-if="annotation && isAuthenticated" @click="readonly = !readonly"
+            v-if="annotation && isAuthenticated"
+            @click="onCancelClick"
             class="btn btn-xs pull-right"
             v-bind:class="{ 'btn-primary': readonly, 'btn-warning': !readonly }">
             <i class="fa fa-edit" v-if="readonly"></i>
@@ -20,7 +21,7 @@
             <input type="hidden" name="fragment" v-model="fragment">
             <div v-if="annotation" class="form-group form-group-sm">
                 <label v-if="!readonly || title" class="small text-muted">Titre</label>
-                <input type="text" class="form-control" name="title" v-model="title" v-if="!readonly">
+                <input type="text" class="form-control" name="title" v-model="title" v-if="!readonly" ref="title">
                 <p v-if="readonly && title" v-bind:class="{ 'text-muted': !title }">{{ title || 'Pas de titre' }}</p>
             </div>
             <div v-if="annotation" class="form-group form-group-sm">
@@ -36,13 +37,13 @@
                     @change="onTagsChange($event.tags)"></tag-list>
                 <input type="hidden" name="tags" v-model="serializedTags">
             </div>
-            <p class="small text-center text-muted" v-if="annotation">
+            <p class="small text-center text-muted" v-if="annotation && annotation.annotation_guid">
                 <a v-bind:href="revisionsUrlComputed">Dernière version</a>
                 <span>{{ dateComputed }} par</span>
                 <a v-bind:href="authorUrlComputed">{{ annotation.author }}</a>
             </p>
             <button type="submit" v-if="annotation &amp;&amp; !readonly" v-bind:class="{ disabled: !hasChanged }"
-                class="btn btn-block btn-sm btn-primary">Enregistrer une nouvelle version</button>
+                class="btn btn-block btn-sm btn-primary">{{ submitButtonText }}</button>
         </form>
     </div>
 </template>
@@ -66,7 +67,6 @@
 
     export default {
         props: {
-            action: String,
             annotation: {
                 type: Object,
                 default: function () {
@@ -78,7 +78,9 @@
                 default: false
             },
             revisionsUrl: String,
-            authorUrl: String
+            authorUrl: String,
+            newAnnotationUrl: String,
+            editAnnotationUrl: String
         },
         components: {
             'tag-list': TagList
@@ -127,9 +129,19 @@
             },
             formAction: function() {
                 if (this.annotation) {
-                    return this.action.replace(':annotation_guid', this.annotation.annotation_guid);
+                    if (this.annotation.annotation_guid) {
+                        return this.editAnnotationUrl.replace(':annotation_guid', this.annotation.annotation_guid);
+                    }
+
+                    return this.newAnnotationUrl
                 }
             },
+            submitButtonText: function() {
+                return this.isNewAnnotation ? 'Enregistrer' : 'Enregister une nouvelle version'
+            },
+            isNewAnnotation: function() {
+                return this.annotation && !this.annotation.annotation_guid
+            },
             serializedTags: function() {
                 var tags = this.tags.map(function(tag) {
                     return {
@@ -151,6 +163,13 @@
             }
         },
         methods: {
+            onCancelClick: function() {
+                if (this.isNewAnnotation) {
+                    this.$emit('close')
+                } else {
+                    this.readonly = !this.readonly
+                }
+            },
             onTagsChange: function(tags) {
                 this.tags = tags;
             },
@@ -164,8 +183,14 @@
                     description: annotation.description,
                     fragment: annotation.fragment,
                     tags: annotation.tags.slice(),
-                    readonly: true,
+                    readonly: !this.isNewAnnotation,
                 });
+
+                if (!annotation.annotation_guid) {
+                    setTimeout(() => {
+                        $(this.$refs.title).focus()
+                    }, 500);
+                }
             }
         }
     }
--- a/src_js/iconolab-bundle/src/components/editor/Canvas.vue	Mon May 15 14:44:14 2017 +0200
+++ b/src_js/iconolab-bundle/src/components/editor/Canvas.vue	Tue May 16 11:29:33 2017 +0200
@@ -59,6 +59,7 @@
                 </defs>
             </svg>
         </div>
+        <div class="overlay" v-show="showOverlay"></div>
         <div class="controls" v-show="loaded">
             <div class="controls-left">
                 <button
@@ -107,7 +108,7 @@
                     v-bind:imageWidth="imageWidth"
                     v-bind:imageHeight="imageHeight"></zoom-thumbnail>
             </div>
-            <div class="controls-right" data-intro="Zoomez dans l'image" data-position="top">
+            <div class="controls-zoom" data-intro="Zoomez dans l'image" data-position="top">
                 <button @click="zoomOut" type="button" class="btn"
                     v-bind:class="{ disabled: scale === 1 }">
                     <i class="fa fa-minus" aria-hidden="true"></i>
@@ -117,6 +118,12 @@
                     <i class="fa fa-plus" aria-hidden="true"></i>
                 </button>
             </div>
+            <div class="controls-right">
+                <button @click="addAnnotationWithoutFragment" type="button" class="btn"
+                    title="Annoter toute l'image" data-intro="Annoter toute l'image" data-position="top">
+                    <i class="fa fa-plus-square" aria-hidden="true"></i>
+                </button>
+            </div>
         </div>
         <div class="help">
             <a href="#" class="btn btn-default" v-on:click.stop.prevent="showOnboarding"><i class="fa fa-question-circle"></i></a>
@@ -208,6 +215,9 @@
                 }
 
                 return normalizedAnnotations;
+            },
+            showOverlay: function() {
+                return this.annotation && !this.annotation.annotation_guid
             }
         },
         watch: {
@@ -633,7 +643,11 @@
                     Cookies.set('__iconolab_onboarding', 'true', { expires: 365 });
                 })
                 intro.start()
-            }
+            },
+
+            addAnnotationWithoutFragment: function() {
+                this.$emit('add:annotation')
+            },
         }
     }
 
@@ -698,10 +712,14 @@
         border-radius: 4px;
         padding: 8px;
     }
-    .controls .controls-right {
+    .controls .controls-zoom {
         border-top-right-radius: 4px;
         border-bottom-right-radius: 4px;
     }
+    .controls .controls-right {
+        margin-left: 5px;
+        border-radius: 4px;
+    }
 
 .help {
     position: absolute;
@@ -709,4 +727,14 @@
     right: 10px;
 }
 
+.overlay {
+    position: absolute;
+    background-color: #c5f2ff;
+    opacity: 0.25;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    left: 0;
+}
+
 </style>
--- a/src_js/iconolab-bundle/src/components/editor/CommentList.vue	Mon May 15 14:44:14 2017 +0200
+++ b/src_js/iconolab-bundle/src/components/editor/CommentList.vue	Tue May 16 11:29:33 2017 +0200
@@ -34,7 +34,7 @@
         },
         watch: {
             annotation: function(annotation) {
-                if (annotation) {
+                if (annotation && annotation.annotation_guid) {
                     $.getJSON(this.commentsURL).then((comments) => this.comments = comments);
                 } else {
                     this.comments = [];