2020-10-24 23:57:45 +05:30
|
|
|
import { defaults } from 'lodash';
|
2021-03-11 19:13:27 +05:30
|
|
|
import Vue from 'vue';
|
|
|
|
import { TOOLBAR_ITEM_CONFIGS, VIDEO_ATTRIBUTES } from '../constants';
|
2020-07-28 23:09:34 +05:30
|
|
|
import ToolbarItem from '../toolbar_item.vue';
|
2020-10-24 23:57:45 +05:30
|
|
|
import buildCustomHTMLRenderer from './build_custom_renderer';
|
2021-03-11 19:13:27 +05:30
|
|
|
import buildHtmlToMarkdownRenderer from './build_html_to_markdown_renderer';
|
2021-01-03 14:25:43 +05:30
|
|
|
import sanitizeHTML from './sanitize_html';
|
2020-06-23 00:09:42 +05:30
|
|
|
|
2021-03-08 18:12:59 +05:30
|
|
|
const buildWrapper = (propsData) => {
|
2020-06-23 00:09:42 +05:30
|
|
|
const instance = new Vue({
|
|
|
|
render(createElement) {
|
|
|
|
return createElement(ToolbarItem, propsData);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
instance.$mount();
|
|
|
|
return instance.$el;
|
|
|
|
};
|
|
|
|
|
2021-03-08 18:12:59 +05:30
|
|
|
const buildVideoIframe = (src) => {
|
2021-01-03 14:25:43 +05:30
|
|
|
const wrapper = document.createElement('figure');
|
|
|
|
const iframe = document.createElement('iframe');
|
|
|
|
const videoAttributes = { ...VIDEO_ATTRIBUTES, src };
|
|
|
|
const wrapperClasses = ['gl-relative', 'gl-h-0', 'video_container'];
|
|
|
|
const iframeClasses = ['gl-absolute', 'gl-top-0', 'gl-left-0', 'gl-w-full', 'gl-h-full'];
|
|
|
|
|
|
|
|
wrapper.setAttribute('contenteditable', 'false');
|
|
|
|
wrapper.classList.add(...wrapperClasses);
|
|
|
|
iframe.classList.add(...iframeClasses);
|
|
|
|
Object.assign(iframe, videoAttributes);
|
|
|
|
|
|
|
|
wrapper.appendChild(iframe);
|
|
|
|
|
|
|
|
return wrapper;
|
|
|
|
};
|
|
|
|
|
2021-01-29 00:20:46 +05:30
|
|
|
const buildImg = (alt, originalSrc, file) => {
|
|
|
|
const img = document.createElement('img');
|
|
|
|
const src = file ? URL.createObjectURL(file) : originalSrc;
|
|
|
|
const attributes = { alt, src };
|
|
|
|
|
|
|
|
if (file) {
|
|
|
|
img.dataset.originalSrc = originalSrc;
|
|
|
|
}
|
|
|
|
|
|
|
|
Object.assign(img, attributes);
|
|
|
|
|
|
|
|
return img;
|
|
|
|
};
|
|
|
|
|
2021-03-08 18:12:59 +05:30
|
|
|
export const generateToolbarItem = (config) => {
|
2020-06-23 00:09:42 +05:30
|
|
|
const { icon, classes, event, command, tooltip, isDivider } = config;
|
|
|
|
|
|
|
|
if (isDivider) {
|
|
|
|
return 'divider';
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
type: 'button',
|
|
|
|
options: {
|
|
|
|
el: buildWrapper({ props: { icon, tooltip }, class: classes }),
|
|
|
|
event,
|
|
|
|
command,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
export const addCustomEventListener = (editorApi, event, handler) => {
|
|
|
|
editorApi.eventManager.addEventType(event);
|
|
|
|
editorApi.eventManager.listen(event, handler);
|
|
|
|
};
|
|
|
|
|
|
|
|
export const removeCustomEventListener = (editorApi, event, handler) =>
|
|
|
|
editorApi.eventManager.removeEventHandler(event, handler);
|
|
|
|
|
2021-01-29 00:20:46 +05:30
|
|
|
export const addImage = ({ editor }, { altText, imageUrl }, file) => {
|
|
|
|
if (editor.isWysiwygMode()) {
|
|
|
|
const img = buildImg(altText, imageUrl, file);
|
|
|
|
editor.getSquire().insertElement(img);
|
|
|
|
} else {
|
|
|
|
editor.insertText(`![${altText}](${imageUrl})`);
|
|
|
|
}
|
|
|
|
};
|
2020-06-23 00:09:42 +05:30
|
|
|
|
2021-01-03 14:25:43 +05:30
|
|
|
export const insertVideo = ({ editor }, url) => {
|
|
|
|
const videoIframe = buildVideoIframe(url);
|
|
|
|
|
|
|
|
if (editor.isWysiwygMode()) {
|
|
|
|
editor.getSquire().insertElement(videoIframe);
|
|
|
|
} else {
|
|
|
|
editor.insertText(videoIframe.outerHTML);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-03-08 18:12:59 +05:30
|
|
|
export const getMarkdown = (editorInstance) => editorInstance.invoke('getMarkdown');
|
2020-07-28 23:09:34 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* This function allow us to extend Toast UI HTML to Markdown renderer. It is
|
|
|
|
* a temporary measure because Toast UI does not provide an API
|
|
|
|
* to achieve this goal.
|
|
|
|
*/
|
2021-03-08 18:12:59 +05:30
|
|
|
export const registerHTMLToMarkdownRenderer = (editorApi) => {
|
2020-07-28 23:09:34 +05:30
|
|
|
const { renderer } = editorApi.toMarkOptions;
|
|
|
|
|
|
|
|
Object.assign(editorApi.toMarkOptions, {
|
|
|
|
renderer: renderer.constructor.factory(renderer, buildHtmlToMarkdownRenderer(renderer)),
|
|
|
|
});
|
|
|
|
};
|
2020-10-24 23:57:45 +05:30
|
|
|
|
2021-03-08 18:12:59 +05:30
|
|
|
export const getEditorOptions = (externalOptions) => {
|
2020-10-24 23:57:45 +05:30
|
|
|
return defaults({
|
|
|
|
customHTMLRenderer: buildCustomHTMLRenderer(externalOptions?.customRenderers),
|
2021-03-08 18:12:59 +05:30
|
|
|
toolbarItems: TOOLBAR_ITEM_CONFIGS.map((toolbarItem) => generateToolbarItem(toolbarItem)),
|
|
|
|
customHTMLSanitizer: (html) => sanitizeHTML(html),
|
2020-10-24 23:57:45 +05:30
|
|
|
});
|
|
|
|
};
|