issue_note_form.vue 3.5 KB
Newer Older
1
<script>
2
import markdownField from '../../vue_shared/components/markdown/field.vue';
3
import eventHub from '../event_hub';
4 5 6 7 8

export default {
  props: {
    noteBody: {
      type: String,
9 10
      required: false,
      default: '',
11
    },
12 13 14 15
    noteId: {
      type: Number,
      required: false,
    },
16 17 18 19 20 21 22 23
    updateHandler: {
      type: Function,
      required: true,
    },
    cancelHandler: {
      type: Function,
      required: true,
    },
24 25 26 27
    saveButtonTitle: {
      type: String,
      required: false,
      default: 'Save comment',
28
    },
29 30 31
  },
  data() {
    return {
32
      initialNote: this.noteBody,
33 34 35
      note: this.noteBody,
      markdownPreviewUrl: '',
      markdownDocsUrl: '',
36
      conflictWhileEditing: false,
37
    };
38
  },
39 40 41 42 43 44 45 46 47
  watch: {
    noteBody() {
      if (this.note === this.initialNote) {
        this.note = this.noteBody;
      } else {
        this.conflictWhileEditing = true;
      }
    },
  },
48
  components: {
49
    markdownField,
50 51 52 53 54 55 56
  },
  methods: {
    handleUpdate() {
      this.updateHandler({
        note: this.note,
      });
    },
57 58 59 60 61 62
    editMyLastNote() {
      if (this.note === '') {
        const discussion = $(this.$el).closest('.discussion-notes');
        const myLastNoteId = discussion.find('.js-my-note').last().attr('id');

        if (myLastNoteId) {
63
          eventHub.$emit('enterEditMode', {
64 65 66 67 68
            noteId: parseInt(myLastNoteId.replace('note_', ''), 10),
          });
        }
      }
    },
69
  },
70 71 72 73
  computed: {
    isDirty() {
      return this.initialNote !== this.note;
    },
74 75 76
    noteHash() {
      return `#note_${this.noteId}`;
    },
77
  },
78 79 80 81 82 83 84
  mounted() {
    const issuableDataEl = document.getElementById('js-issuable-app-initial-data');
    const issueData = JSON.parse(issuableDataEl.innerHTML.replace(/&quot;/g, '"'));
    const { markdownDocs, markdownPreviewUrl } = issueData;

    this.markdownDocsUrl = markdownDocs;
    this.markdownPreviewUrl = markdownPreviewUrl;
85
    this.$refs.textarea.focus();
86 87 88 89 90 91
  },
};
</script>

<template>
  <div class="note-edit-form">
92 93 94 95 96 97 98 99 100 101
    <div
      v-if="conflictWhileEditing"
      class="js-conflict-edit-warning alert alert-danger">
      This comment has changed since you started editing, please review the
      <a
        :href="noteHash"
        target="_blank"
        rel="noopener noreferrer">updated comment</a>
        to ensure information is not lost.
    </div>
102 103 104 105 106 107 108
    <form class="edit-note common-note-form">
      <markdown-field
        :markdown-preview-url="markdownPreviewUrl"
        :markdown-docs="markdownDocsUrl"
        :addSpacingClasses="false">
        <textarea
          id="note-body"
F
Fatih Acet 已提交
109
          name="note[note]"
110
          class="note-textarea js-gfm-input js-autosize markdown-area js-note-text"
111 112
          data-supports-slash-commands="true"
          data-supports-quick-actions="true"
113 114 115 116 117
          aria-label="Description"
          v-model="note"
          ref="textarea"
          slot="textarea"
          placeholder="Write a comment or drag your files here..."
118
          @keydown.meta.enter="handleUpdate"
119
          @keydown.up="editMyLastNote"
120
          @keydown.esc="cancelHandler(true)">
121 122 123 124 125 126 127
        </textarea>
      </markdown-field>
      <div class="note-form-actions clearfix">
        <button
          @click="handleUpdate"
          type="button"
          class="btn btn-nr btn-save">
128
          {{saveButtonTitle}}
129 130
        </button>
        <button
131
          @click="cancelHandler()"
132
          class="btn btn-nr btn-cancel note-edit-cancel"
133 134 135 136 137 138 139
          type="button">
          Cancel
        </button>
      </div>
    </form>
  </div>
</template>