From ee664acb356f8123f4f6b00b73c1e1cf0866c7fb Mon Sep 17 00:00:00 2001
From: GitLab Bot <gitlab-bot@gitlab.com>
Date: Thu, 20 Oct 2022 09:40:42 +0000
Subject: Add latest changes from gitlab-org/gitlab@15-5-stable-ee

---
 .../pages/shared/wikis/components/wiki_form.vue    | 221 +++++++++------------
 1 file changed, 91 insertions(+), 130 deletions(-)

(limited to 'app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue')

diff --git a/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue b/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue
index 9acc1cb62a1..7b9656de362 100644
--- a/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue
+++ b/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue
@@ -8,21 +8,19 @@ import {
   GlFormGroup,
   GlFormInput,
   GlFormSelect,
-  GlSegmentedControl,
 } from '@gitlab/ui';
-import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
-import axios from '~/lib/utils/axios_utils';
+import { getDraft, clearDraft, updateDraft } from '~/lib/utils/autosave';
 import csrf from '~/lib/utils/csrf';
 import { setUrlFragment } from '~/lib/utils/url_utility';
 import { s__, sprintf } from '~/locale';
 import Tracking from '~/tracking';
-import MarkdownField from '~/vue_shared/components/markdown/field.vue';
+import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
 import {
-  CONTENT_EDITOR_LOADED_ACTION,
   SAVED_USING_CONTENT_EDITOR_ACTION,
   WIKI_CONTENT_EDITOR_TRACKING_LABEL,
   WIKI_FORMAT_LABEL,
   WIKI_FORMAT_UPDATED_ACTION,
+  CONTENT_EDITOR_LOADED_ACTION,
 } from '../constants';
 
 const trackingMixin = Tracking.mixin({
@@ -36,6 +34,29 @@ const MARKDOWN_LINK_TEXT = {
   org: '[[page-slug]]',
 };
 
+function getPagePath(pageInfo) {
+  return pageInfo.persisted ? pageInfo.path : pageInfo.createPath;
+}
+
+const autosaveKey = (pageInfo, field) => {
+  const path = pageInfo.persisted ? pageInfo.path : pageInfo.createPath;
+
+  return `${path}/${field}`;
+};
+
+const titleAutosaveKey = (pageInfo) => autosaveKey(pageInfo, 'title');
+const formatAutosaveKey = (pageInfo) => autosaveKey(pageInfo, 'format');
+const contentAutosaveKey = (pageInfo) => autosaveKey(pageInfo, 'content');
+const commitAutosaveKey = (pageInfo) => autosaveKey(pageInfo, 'commit');
+
+const getTitle = (pageInfo) => getDraft(titleAutosaveKey(pageInfo)) || pageInfo.title?.trim() || '';
+const getFormat = (pageInfo) =>
+  getDraft(formatAutosaveKey(pageInfo)) || pageInfo.format || 'markdown';
+const getContent = (pageInfo) => getDraft(contentAutosaveKey(pageInfo)) || pageInfo.content || '';
+const getCommitMessage = (pageInfo) =>
+  getDraft(commitAutosaveKey(pageInfo)) || pageInfo.commitMessage || '';
+const getIsFormDirty = (pageInfo) => Boolean(getDraft(titleAutosaveKey(pageInfo)));
+
 export default {
   i18n: {
     title: {
@@ -74,10 +95,6 @@ export default {
     },
     cancel: s__('WikiPage|Cancel'),
   },
-  switchEditingControlOptions: [
-    { text: s__('Wiki Page|Source'), value: 'source' },
-    { text: s__('Wiki Page|Rich text'), value: 'richText' },
-  ],
   components: {
     GlIcon,
     GlForm,
@@ -87,26 +104,21 @@ export default {
     GlSprintf,
     GlLink,
     GlButton,
-    GlSegmentedControl,
-    MarkdownField,
-    LocalStorageSync,
-    ContentEditor: () =>
-      import(
-        /* webpackChunkName: 'content_editor' */ '~/content_editor/components/content_editor.vue'
-      ),
+    MarkdownEditor,
   },
   mixins: [trackingMixin],
   inject: ['formatOptions', 'pageInfo'],
   data() {
     return {
       editingMode: 'source',
-      title: this.pageInfo.title?.trim() || '',
-      format: this.pageInfo.format || 'markdown',
-      content: this.pageInfo.content || '',
-      commitMessage: '',
-      isDirty: false,
+      title: getTitle(this.pageInfo),
+      format: getFormat(this.pageInfo),
+      content: getContent(this.pageInfo),
+      commitMessage: getCommitMessage(this.pageInfo),
       contentEditorEmpty: false,
+      isContentEditorActive: false,
       switchEditingControlDisabled: false,
+      isFormDirty: getIsFormDirty(this.pageInfo),
     };
   },
   computed: {
@@ -117,7 +129,7 @@ export default {
       return csrf.token;
     },
     formAction() {
-      return this.pageInfo.persisted ? this.pageInfo.path : this.pageInfo.createPath;
+      return getPagePath(this.pageInfo);
     },
     helpPath() {
       return setUrlFragment(
@@ -162,15 +174,9 @@ export default {
     disableSubmitButton() {
       return this.noContent || !this.title;
     },
-    isContentEditorActive() {
-      return this.isMarkdownFormat && this.useContentEditor;
-    },
-    useContentEditor() {
-      return this.editingMode === 'richText';
-    },
   },
   mounted() {
-    this.updateCommitMessage();
+    if (!this.commitMessage) this.updateCommitMessage();
 
     window.addEventListener('beforeunload', this.onPageUnload);
   },
@@ -178,51 +184,45 @@ export default {
     window.removeEventListener('beforeunload', this.onPageUnload);
   },
   methods: {
-    renderMarkdown(content) {
-      return axios
-        .post(this.pageInfo.markdownPreviewPath, { text: content })
-        .then(({ data }) => data.body);
-    },
-
-    setEditingMode(editingMode) {
-      this.editingMode = editingMode;
-    },
-
     async handleFormSubmit(e) {
-      e.preventDefault();
+      this.isFormDirty = false;
 
-      if (this.useContentEditor) {
-        this.trackFormSubmit();
-      }
+      e.preventDefault();
 
+      this.trackFormSubmit();
       this.trackWikiFormat();
 
       // Wait until form field values are refreshed
       await this.$nextTick();
 
       e.target.submit();
+    },
 
-      this.isDirty = false;
+    updateDrafts() {
+      updateDraft(titleAutosaveKey(this.pageInfo), this.title);
+      updateDraft(formatAutosaveKey(this.pageInfo), this.format);
+      updateDraft(contentAutosaveKey(this.pageInfo), this.content);
+      updateDraft(commitAutosaveKey(this.pageInfo), this.commitMessage);
     },
 
-    handleContentChange() {
-      this.isDirty = true;
+    clearDrafts() {
+      clearDraft(titleAutosaveKey(this.pageInfo));
+      clearDraft(formatAutosaveKey(this.pageInfo));
+      clearDraft(contentAutosaveKey(this.pageInfo));
+      clearDraft(commitAutosaveKey(this.pageInfo));
     },
 
-    handleContentEditorChange({ empty, markdown, changed }) {
+    handleContentEditorChange({ empty, markdown }) {
       this.contentEditorEmpty = empty;
-      this.isDirty = changed;
       this.content = markdown;
     },
 
-    onPageUnload(event) {
-      if (!this.isDirty) return undefined;
-
-      event.preventDefault();
-
-      // eslint-disable-next-line no-param-reassign
-      event.returnValue = '';
-      return '';
+    onPageUnload() {
+      if (this.isFormDirty) {
+        this.updateDrafts();
+      } else {
+        this.clearDrafts();
+      }
     },
 
     updateCommitMessage() {
@@ -235,8 +235,13 @@ export default {
       this.commitMessage = newCommitMessage;
     },
 
-    trackContentEditorLoaded() {
-      this.track(CONTENT_EDITOR_LOADED_ACTION);
+    notifyContentEditorActive() {
+      this.isContentEditorActive = true;
+      this.trackContentEditorLoaded();
+    },
+
+    notifyContentEditorInactive() {
+      this.isContentEditorActive = false;
     },
 
     trackFormSubmit() {
@@ -256,12 +261,12 @@ export default {
       });
     },
 
-    enableSwitchEditingControl() {
-      this.switchEditingControlDisabled = false;
+    trackContentEditorLoaded() {
+      this.track(CONTENT_EDITOR_LOADED_ACTION);
     },
 
-    disableSwitchEditingControl() {
-      this.switchEditingControlDisabled = true;
+    submitFormWithShortcut() {
+      this.$refs.form.submit();
     },
   },
 };
@@ -269,10 +274,12 @@ export default {
 
 <template>
   <gl-form
+    ref="form"
     :action="formAction"
     method="post"
     class="wiki-form common-note-form gl-mt-3 js-quick-submit"
     @submit="handleFormSubmit"
+    @input="isFormDirty = true"
   >
     <input :value="csrfToken" type="hidden" name="authenticity_token" />
     <input v-if="pageInfo.persisted" type="hidden" name="_method" value="put" />
@@ -329,74 +336,23 @@ export default {
     <div class="row" data-testid="wiki-form-content-fieldset">
       <div class="col-sm-12 row-sm-5">
         <gl-form-group>
-          <div v-if="isMarkdownFormat" class="gl-display-flex gl-justify-content-start gl-mb-3">
-            <gl-segmented-control
-              data-testid="toggle-editing-mode-button"
-              data-qa-selector="editing_mode_button"
-              class="gl-display-flex"
-              :checked="editingMode"
-              :options="$options.switchEditingControlOptions"
-              :disabled="switchEditingControlDisabled"
-              @input="setEditingMode"
-            />
-          </div>
-          <local-storage-sync
-            storage-key="gl-wiki-content-editor-enabled"
-            :value="editingMode"
-            @input="setEditingMode"
-          />
-          <markdown-field
-            v-if="!isContentEditorActive"
-            :markdown-preview-path="pageInfo.markdownPreviewPath"
-            :can-attach-file="true"
-            :enable-autocomplete="true"
-            :textarea-value="content"
+          <markdown-editor
+            v-model="content"
+            :render-markdown-path="pageInfo.markdownPreviewPath"
             :markdown-docs-path="pageInfo.markdownHelpPath"
             :uploads-path="pageInfo.uploadsPath"
+            :enable-content-editor="isMarkdownFormat"
             :enable-preview="isMarkdownFormat"
-            class="bordered-box"
-          >
-            <template #textarea>
-              <textarea
-                id="wiki_content"
-                ref="textarea"
-                v-model="content"
-                name="wiki[content]"
-                class="note-textarea js-gfm-input js-autosize markdown-area"
-                dir="auto"
-                data-supports-quick-actions="false"
-                data-qa-selector="wiki_content_textarea"
-                :autofocus="pageInfo.persisted"
-                :aria-label="$options.i18n.content.label"
-                :placeholder="$options.i18n.content.placeholder"
-                @input="handleContentChange"
-              >
-              </textarea>
-            </template>
-          </markdown-field>
-          <div v-if="isContentEditorActive">
-            <content-editor
-              :render-markdown="renderMarkdown"
-              :uploads-path="pageInfo.uploadsPath"
-              :markdown="content"
-              @initialized="trackContentEditorLoaded"
-              @change="handleContentEditorChange"
-              @loading="disableSwitchEditingControl"
-              @loadingSuccess="enableSwitchEditingControl"
-              @loadingError="enableSwitchEditingControl"
-            />
-            <input
-              id="wiki_content"
-              v-model.trim="content"
-              type="hidden"
-              name="wiki[content]"
-              data-qa-selector="wiki_hidden_content"
-            />
-          </div>
-
-          <div class="clearfix"></div>
-          <div class="error-alert"></div>
-
+            :init-on-autofocus="pageInfo.persisted"
+            :form-field-placeholder="$options.i18n.content.placeholder"
+            :form-field-aria-label="$options.i18n.content.label"
+            form-field-id="wiki_content"
+            form-field-name="wiki[content]"
+            @contentEditor="notifyContentEditorActive"
+            @markdownField="notifyContentEditorInactive"
+            @keydown.ctrl.enter="submitFormShortcut"
+            @keydown.meta.enter="submitFormShortcut"
+          />
           <div class="form-text gl-text-gray-600">
             <gl-sprintf
               v-if="displayWikiSpecificMarkdownHelp"
@@ -447,9 +403,14 @@ export default {
         :disabled="disableSubmitButton"
         >{{ submitButtonText }}</gl-button
       >
-      <gl-button data-testid="wiki-cancel-button" :href="cancelFormPath" class="float-right">{{
-        $options.i18n.cancel
-      }}</gl-button>
+      <gl-button
+        data-testid="wiki-cancel-button"
+        :href="cancelFormPath"
+        class="float-right"
+        @click="isFormDirty = false"
+      >
+        {{ $options.i18n.cancel }}</gl-button
+      >
     </div>
   </gl-form>
 </template>
-- 
cgit v1.2.3

