src_js/iconolab-bundle/src/components/editor/AnnotationForm.vue
author ymh <ymh.work@gmail.com>
Wed, 06 Jun 2018 16:21:54 +0200
changeset 539 08e2513dbc2f
parent 504 11a862e01b04
permissions -rw-r--r--
Upgrade webpack to 4, upgrade vue.js, and some style changes

<template>
    <div>
        <button
            data-intro="Proposez une nouvelle version" data-position="left"
            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>
            <span v-if="readonly">Modifier</span>
            <i class="fa fa-ban" v-if="!readonly"></i>
            <span v-if="!readonly">Annuler</span>
        </button>
        <div v-if="!annotation" class="alert alert-warning text-center">
            Aucune annotation sélectionnée
        </div>
        <form v-bind:action="formAction" method="post">
            <slot>
                <!-- CSRF token -->
            </slot>
            <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" 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">
                <label v-if="!readonly || description" class="small text-muted">Description</label>
                <textarea class="form-control" name="description" v-model="description" v-if="!readonly" placeholder="Décrivez ce que vous voyez"></textarea>
                <p v-if="readonly && description" v-bind:class="{ 'text-muted': !description }" v-html="descriptionComputed">{{ descriptionComputed || 'Pas de description' }}</p>
            </div>
            <div v-if="annotation" class="form-group form-group-sm">
                <label class="small text-muted">Mots-clés</label>
                <tag-list ref="taglist"
                    v-bind:original-tags="annotation.tags"
                    v-bind:readonly="readonly"
                    @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 && 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">{{ submitButtonText }}</button>
        </form>
    </div>
</template>

<script>
import TagList from "../tagform/TagList.vue";
import _ from "lodash";
import showdown from "showdown";
import moment from "moment";

const converter = new showdown.Converter();

var defaults = {
  title: "",
  description: "",
  fragment: "",
  tags: [],
  readonly: true
};

export default {
  props: {
    annotation: {
      type: Object,
      default: function() {
        return null;
      }
    },
    isAuthenticated: {
      type: Boolean,
      default: false
    },
    revisionsUrl: String,
    authorUrl: String,
    newAnnotationUrl: String,
    editAnnotationUrl: String
  },
  components: {
    "tag-list": TagList
  },
  data() {
    return defaults;
  },
  mounted() {
    if (this.annotation) {
      this.loadAnnotation(this.annotation);
    }
  },
  watch: {
    annotation: function(annotation) {
      if (annotation) {
        this.loadAnnotation(annotation);
      } else {
        this.reset();
      }
    }
  },
  computed: {
    descriptionComputed: function() {
      return converter.makeHtml(this.description);
    },
    lastRevisionText: function() {
      if (this.annotation) {
        var date = moment(this.annotation.created).locale("fr");
        return (
          "Dernière version " +
          date.fromNow() +
          " par " +
          this.annotation.author
        );
      }
    },
    revisionsUrlComputed: function() {
      if (this.annotation) {
        return this.revisionsUrl.replace(
          ":annotation_guid",
          this.annotation.annotation_guid
        );
      }
    },
    authorUrlComputed: function() {
      if (this.annotation) {
        return this.authorUrl.replace("--username--", this.annotation.author);
      }
    },
    dateComputed: function() {
      if (this.annotation) {
        return moment(this.annotation.created)
          .locale("fr")
          .fromNow();
      }
    },
    formAction: function() {
      if (this.annotation) {
        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 {
          tag_input:
            typeof tag.tag_link === "string" && tag.tag_link.length
              ? tag.tag_link
              : tag.tag_label,
          tag_label: tag.tag_label,
          accuracy: tag.accuracy,
          relevancy: tag.relevancy
        };
      });

      return JSON.stringify(tags);
    },
    hasChanged: function() {
      if (!this.annotation) {
        return false;
      }

      return (
        this.title !== this.annotation.title ||
        this.description !== this.annotation.description ||
        !_.isEqual(this.annotation.tags, this.tags)
      );
    }
  },
  methods: {
    onCancelClick: function() {
      if (this.isNewAnnotation) {
        this.$emit("close");
      } else {
        this.readonly = !this.readonly;
      }
    },
    onTagsChange: function(tags) {
      this.tags = tags;
    },
    reset: function() {
      Object.assign(this, defaults);
    },
    loadAnnotation(annotation) {
      // Make sure we have an actual copy
      Object.assign(this, {
        title: annotation.title,
        description: annotation.description,
        fragment: annotation.fragment,
        tags: annotation.tags.slice(),
        readonly: !this.isNewAnnotation
      });

      if (!annotation.annotation_guid) {
        setTimeout(() => {
          $(this.$refs.title).focus();
        }, 500);
      }
    }
  }
};
</script>

<style scoped>
form {
  margin-bottom: 20px;
  clear: both;
}

label {
  font-weight: normal;
}
</style>