From d110f38d9075f9061869d8427773dd499aee92b6 Mon Sep 17 00:00:00 2001
From: Fatih Acet <acetfatih@gmail.com>
Date: Thu, 15 Jun 2017 02:36:53 +0300
Subject: [PATCH] IssueNotesRefactor: Implement note edit widget.

---
 .../notes/components/issue_note.vue           | 29 ++++++-
 .../notes/components/issue_note_actions.vue   |  7 +-
 .../notes/components/issue_note_body.vue      | 32 +++++++-
 .../notes/components/issue_note_form.vue      | 82 +++++++++++++++++++
 .../notes/components/issue_note_header.vue    |  4 +-
 5 files changed, 147 insertions(+), 7 deletions(-)
 create mode 100644 app/assets/javascripts/notes/components/issue_note_form.vue

diff --git a/app/assets/javascripts/notes/components/issue_note.vue b/app/assets/javascripts/notes/components/issue_note.vue
index 1043776010e..ef18ff4b45f 100644
--- a/app/assets/javascripts/notes/components/issue_note.vue
+++ b/app/assets/javascripts/notes/components/issue_note.vue
@@ -11,6 +11,11 @@ export default {
       required: true,
     },
   },
+  data() {
+    return {
+      isEditing: false,
+    }
+  },
   components: {
     UserAvatarLink,
     IssueNoteHeader,
@@ -22,11 +27,24 @@ export default {
       return this.note.author;
     },
   },
+  methods: {
+    editHandler() {
+      this.isEditing = true;
+    },
+    formUpdateHandler(data) {
+      console.log('update requested', data);
+    },
+    formCancelHandler() {
+      this.isEditing = false;
+    },
+  },
 };
 </script>
 
 <template>
-  <li class="note timeline-entry">
+  <li
+    class="note timeline-entry"
+    :class="{ 'is-editing': isEditing }">
     <div class="timeline-entry-inner">
       <div class="timeline-icon">
         <user-avatar-link
@@ -47,9 +65,14 @@ export default {
             :canAward="note.emoji_awardable"
             :canEdit="note.can_edit"
             :canDelete="note.can_edit"
-            :reportAbusePath="note.report_abuse_path" />
+            :reportAbusePath="note.report_abuse_path"
+            :editHandler="editHandler" />
         </div>
-        <issue-note-body :note="note" />
+        <issue-note-body
+          :note="note"
+          :isEditing="isEditing"
+          :formUpdateHandler="formUpdateHandler"
+          :formCancelHandler="formCancelHandler" />
       </div>
     </div>
   </li>
diff --git a/app/assets/javascripts/notes/components/issue_note_actions.vue b/app/assets/javascripts/notes/components/issue_note_actions.vue
index 35828a959e1..126f844b330 100644
--- a/app/assets/javascripts/notes/components/issue_note_actions.vue
+++ b/app/assets/javascripts/notes/components/issue_note_actions.vue
@@ -21,6 +21,10 @@ export default {
       type: Boolean,
       required: true,
     },
+    editHandler: {
+      type: Function,
+      required: true,
+    },
   },
   data() {
     return {
@@ -70,8 +74,9 @@ export default {
         <template v-if="canEdit">
           <li>
             <button
+              @click="editHandler"
               type="button"
-              class="js-note-edit btn btn-transparent">
+              class="btn btn-transparent">
               Edit comment
             </button>
           </li>
diff --git a/app/assets/javascripts/notes/components/issue_note_body.vue b/app/assets/javascripts/notes/components/issue_note_body.vue
index 08f367e0496..e5c3ddf0d0c 100644
--- a/app/assets/javascripts/notes/components/issue_note_body.vue
+++ b/app/assets/javascripts/notes/components/issue_note_body.vue
@@ -1,6 +1,7 @@
 <script>
 import IssueNoteEditedText from './issue_note_edited_text.vue';
 import IssueNoteAwardsList from './issue_note_awards_list.vue';
+import IssueNoteForm from './issue_note_form.vue';
 
 export default {
   props: {
@@ -8,19 +9,48 @@ export default {
       type: Object,
       required: true,
     },
+    isEditing: {
+      type: Boolean,
+      required: false,
+      default: false,
+    },
+    formUpdateHandler: {
+      type: Function,
+      required: true,
+    },
+    formCancelHandler: {
+      type: Function,
+      required: true,
+    }
   },
   components: {
     IssueNoteEditedText,
     IssueNoteAwardsList,
+    IssueNoteForm,
+  },
+  methods: {
+    renderGFM() {
+      $(this.$refs['note-body']).renderGFM();
+    },
+  },
+  mounted() {
+    this.renderGFM();
   },
 };
 </script>
 
 <template>
-  <div class="note-body">
+  <div
+    ref="note-body"
+    class="note-body">
     <div
       v-html="note.note_html"
       class="note-text md"></div>
+    <issue-note-form
+      v-if="isEditing"
+      :updateHandler="formUpdateHandler"
+      :cancelHandler="formCancelHandler"
+      :noteBody="note.note" />
     <issue-note-edited-text
       v-if="note.last_edited_by"
       :editedAt="note.last_edited_at"
diff --git a/app/assets/javascripts/notes/components/issue_note_form.vue b/app/assets/javascripts/notes/components/issue_note_form.vue
new file mode 100644
index 00000000000..93d4acbb20a
--- /dev/null
+++ b/app/assets/javascripts/notes/components/issue_note_form.vue
@@ -0,0 +1,82 @@
+<script>
+import MarkdownField from '../../vue_shared/components/markdown/field.vue';
+
+export default {
+  props: {
+    noteBody: {
+      type: String,
+      required: true,
+    },
+    updateHandler: {
+      type: Function,
+      required: true,
+    },
+    cancelHandler: {
+      type: Function,
+      required: true,
+    },
+  },
+  data() {
+    return {
+      note: this.noteBody,
+      markdownPreviewUrl: '',
+      markdownDocsUrl: '',
+    }
+  },
+  components: {
+    MarkdownField,
+  },
+  methods: {
+    handleUpdate() {
+      this.updateHandler({
+        note: this.note,
+      });
+    },
+  },
+  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;
+  },
+};
+</script>
+
+<template>
+  <div class="note-edit-form">
+    <form class="edit-note common-note-form">
+      <markdown-field
+        :markdown-preview-url="markdownPreviewUrl"
+        :markdown-docs="markdownDocsUrl"
+        :addSpacingClasses="false">
+        <textarea
+          id="note-body"
+          class="note-textarea js-gfm-input js-autosize markdown-area"
+          data-supports-slash-commands="false"
+          aria-label="Description"
+          v-model="note"
+          ref="textarea"
+          slot="textarea"
+          placeholder="Write a comment or drag your files here..."
+          @keydown.meta.enter="handleUpdate">
+        </textarea>
+      </markdown-field>
+      <div class="note-form-actions clearfix">
+        <button
+          @click="handleUpdate"
+          type="button"
+          class="btn btn-nr btn-save">
+          Save comment
+        </button>
+        <button
+          @click="cancelHandler"
+          class="btn btn-nr btn-cancel"
+          type="button">
+          Cancel
+        </button>
+      </div>
+    </form>
+  </div>
+</template>
diff --git a/app/assets/javascripts/notes/components/issue_note_header.vue b/app/assets/javascripts/notes/components/issue_note_header.vue
index 8d7b2ee7231..d267d1db7fa 100644
--- a/app/assets/javascripts/notes/components/issue_note_header.vue
+++ b/app/assets/javascripts/notes/components/issue_note_header.vue
@@ -33,7 +33,7 @@ export default {
     TimeAgoTooltip,
   },
   methods: {
-    doShit() {
+    toggle() {
       this.$store.commit('toggleDiscussion', {
         discussionId: this.discussionId,
       });
@@ -66,7 +66,7 @@ export default {
       v-if="includeToggle"
       class="discussion-actions">
       <button
-        @click="doShit"
+        @click="toggle"
         class="note-action-button discussion-toggle-button js-toggle-button"
         type="button">
           <i
-- 
2.30.9