Skip to content
代码片段 群组 项目
提交 156a0050 编辑于 作者: Kushal Pandya's avatar Kushal Pandya
浏览文件

Merge branch 'himkp-ce-autosave' into 'master'

Add support for autosave in markdown_editor

See merge request https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114052



Merged-by: default avatarKushal Pandya <kushal@gitlab.com>
Approved-by: default avatarKushal Pandya <kushal@gitlab.com>
Co-authored-by: default avatarHimanshu Kapoor <hkapoor@gitlab.com>
No related branches found
No related tags found
无相关合并请求
<script>
import axios from '~/lib/utils/axios_utils';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import { updateDraft, clearDraft, getDraft } from '~/lib/utils/autosave';
import { EDITING_MODE_MARKDOWN_FIELD, EDITING_MODE_CONTENT_EDITOR } from '../../constants';
import MarkdownField from './field.vue';
......@@ -52,10 +53,15 @@ export default {
required: false,
default: false,
},
autosaveKey: {
type: String,
required: false,
default: null,
},
},
data() {
return {
markdown: this.value || '',
markdown: this.value || (this.autosaveKey ? getDraft(this.autosaveKey) : '') || '',
editingMode: EDITING_MODE_MARKDOWN_FIELD,
autofocused: false,
};
......@@ -72,19 +78,27 @@ export default {
watch: {
value(val) {
this.markdown = val;
this.saveDraft();
},
},
mounted() {
this.autofocusTextarea();
this.saveDraft();
},
methods: {
updateMarkdownFromContentEditor({ markdown }) {
this.markdown = markdown;
this.$emit('input', markdown);
this.saveDraft();
},
updateMarkdownFromMarkdownField({ target }) {
this.markdown = target.value;
this.$emit('input', target.value);
this.saveDraft();
},
renderMarkdown(markdown) {
return axios.post(this.renderMarkdownPath, { text: markdown }).then(({ data }) => data.body);
......@@ -110,6 +124,11 @@ export default {
setEditorAsAutofocused() {
this.autofocused = true;
},
saveDraft() {
if (!this.autosaveKey) return;
if (this.markdown) updateDraft(this.autosaveKey, this.markdown);
else clearDraft(this.autosaveKey);
},
},
};
</script>
......
......@@ -9,10 +9,13 @@ import BubbleMenu from '~/content_editor/components/bubble_menus/bubble_menu.vue
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
import { stubComponent } from 'helpers/stub_component';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
jest.mock('~/emoji');
describe('vue_shared/component/markdown/markdown_editor', () => {
useLocalStorageSpy();
let wrapper;
const value = 'test markdown';
const renderMarkdownPath = '/api/markdown';
......@@ -64,6 +67,8 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
afterEach(() => {
mock.restore();
localStorage.clear();
});
it('displays markdown field by default', () => {
......@@ -102,6 +107,42 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
});
});
describe('autosave', () => {
it('automatically saves the textarea value to local storage if autosaveKey is defined', () => {
buildWrapper({ propsData: { autosaveKey: 'issue/1234', value: 'This is **markdown**' } });
expect(localStorage.getItem('autosave/issue/1234')).toBe('This is **markdown**');
});
it("loads value from local storage if autosaveKey is defined, and value isn't", () => {
localStorage.setItem('autosave/issue/1234', 'This is **markdown**');
buildWrapper({ propsData: { autosaveKey: 'issue/1234', value: '' } });
expect(findTextarea().element.value).toBe('This is **markdown**');
});
it("doesn't load value from local storage if autosaveKey is defined, and value is", () => {
localStorage.setItem('autosave/issue/1234', 'This is **markdown**');
buildWrapper({ propsData: { autosaveKey: 'issue/1234' } });
expect(findTextarea().element.value).toBe('test markdown');
});
it('does not save the textarea value to local storage if autosaveKey is not defined', () => {
buildWrapper({ propsData: { value: 'This is **markdown**' } });
expect(localStorage.setItem).not.toHaveBeenCalled();
});
it('does not save the textarea value to local storage if value is empty', () => {
buildWrapper({ propsData: { autosaveKey: 'issue/1234', value: '' } });
expect(localStorage.setItem).not.toHaveBeenCalled();
});
});
it('renders markdown field textarea', () => {
buildWrapper({ propsData: { supportsQuickActions: true } });
......@@ -158,6 +199,16 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
expect(wrapper.emitted('input')).toEqual([[newValue]]);
});
it('autosaves the markdown value to local storage', async () => {
buildWrapper({ propsData: { autosaveKey: 'issue/1234' } });
const newValue = 'new value';
await findTextarea().setValue(newValue);
expect(localStorage.getItem('autosave/issue/1234')).toBe(newValue);
});
describe('when autofocus is true', () => {
beforeEach(async () => {
buildWrapper({ attachTo: document.body, propsData: { autofocus: true } });
......@@ -219,7 +270,7 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
describe(`when editingMode is ${EDITING_MODE_CONTENT_EDITOR}`, () => {
beforeEach(() => {
buildWrapper();
buildWrapper({ propsData: { autosaveKey: 'issue/1234' } });
findMarkdownField().vm.$emit('enableContentEditor');
});
......@@ -244,6 +295,14 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
expect(wrapper.emitted('input')).toEqual([[newValue]]);
});
it('autosaves the content editor value to local storage', async () => {
const newValue = 'new value';
await findContentEditor().vm.$emit('change', { markdown: newValue });
expect(localStorage.getItem('autosave/issue/1234')).toBe(newValue);
});
it('bubbles up keydown event', () => {
const event = new Event('keydown');
......
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册