From f75425d13bc9f6003021fd4b5d6451ae096c09b7 Mon Sep 17 00:00:00 2001 From: vben Date: Thu, 22 Oct 2020 23:56:33 +0800 Subject: [PATCH] perf: review tinymce code --- src/components/Tinymce/src/Editor.vue | 148 ++++++++++++++--- .../src/{lib/TinyMCE.ts => getTinymce.ts} | 5 +- src/components/Tinymce/src/helper.ts | 81 ++++++++++ .../Tinymce/src/lib/ScriptLoader.ts | 72 --------- src/components/Tinymce/src/lib/Utils.ts | 151 ------------------ .../Tinymce/src/lib/components/Editor.ts | 111 ------------- .../src/lib/components/EditorPropTypes.ts | 46 ------ src/components/Tinymce/src/lib/global.d.ts | 4 - src/components/Tinymce/src/lib/index.ts | 3 - src/components/Tinymce/src/props.ts | 10 +- src/router/menus/modules/demo/charts.ts | 10 +- src/router/menus/modules/demo/comp.ts | 36 ++--- src/router/menus/modules/demo/editor.ts | 16 +- src/router/menus/modules/demo/excel.ts | 10 +- src/router/menus/modules/demo/exception.ts | 12 +- src/router/menus/modules/demo/feat.ts | 26 +-- src/router/menus/modules/demo/form.ts | 14 +- src/router/menus/modules/demo/iframe.ts | 6 +- src/router/menus/modules/demo/permission.ts | 16 +- src/router/menus/modules/demo/table.ts | 28 ++-- src/router/routes/modules/demo/comp.ts | 26 --- src/router/routes/modules/demo/editor.ts | 27 ++++ src/utils/is.ts | 4 + src/utils/uuid.ts | 8 + .../demo/{comp => editor}/tinymce/Editor.vue | 2 +- .../demo/{comp => editor}/tinymce/index.vue | 11 +- 26 files changed, 349 insertions(+), 534 deletions(-) rename src/components/Tinymce/src/{lib/TinyMCE.ts => getTinymce.ts} (76%) create mode 100644 src/components/Tinymce/src/helper.ts delete mode 100644 src/components/Tinymce/src/lib/ScriptLoader.ts delete mode 100644 src/components/Tinymce/src/lib/Utils.ts delete mode 100644 src/components/Tinymce/src/lib/components/Editor.ts delete mode 100644 src/components/Tinymce/src/lib/components/EditorPropTypes.ts delete mode 100644 src/components/Tinymce/src/lib/global.d.ts delete mode 100644 src/components/Tinymce/src/lib/index.ts rename src/views/demo/{comp => editor}/tinymce/Editor.vue (96%) rename src/views/demo/{comp => editor}/tinymce/index.vue (52%) diff --git a/src/components/Tinymce/src/Editor.vue b/src/components/Tinymce/src/Editor.vue index 3fa97265..e0b9b5f0 100644 --- a/src/components/Tinymce/src/Editor.vue +++ b/src/components/Tinymce/src/Editor.vue @@ -1,59 +1,169 @@ diff --git a/src/components/Tinymce/src/lib/TinyMCE.ts b/src/components/Tinymce/src/getTinymce.ts similarity index 76% rename from src/components/Tinymce/src/lib/TinyMCE.ts rename to src/components/Tinymce/src/getTinymce.ts index 37a79253..6c4e7a3b 100644 --- a/src/components/Tinymce/src/lib/TinyMCE.ts +++ b/src/components/Tinymce/src/getTinymce.ts @@ -1,9 +1,6 @@ const getGlobal = (): any => (typeof window !== 'undefined' ? window : global); -const getTinymce = () => { +export const getTinymce = () => { const global = getGlobal(); - return global && global.tinymce ? global.tinymce : null; }; - -export { getTinymce }; diff --git a/src/components/Tinymce/src/helper.ts b/src/components/Tinymce/src/helper.ts new file mode 100644 index 00000000..2526ae78 --- /dev/null +++ b/src/components/Tinymce/src/helper.ts @@ -0,0 +1,81 @@ +const validEvents = [ + 'onActivate', + 'onAddUndo', + 'onBeforeAddUndo', + 'onBeforeExecCommand', + 'onBeforeGetContent', + 'onBeforeRenderUI', + 'onBeforeSetContent', + 'onBeforePaste', + 'onBlur', + 'onChange', + 'onClearUndos', + 'onClick', + 'onContextMenu', + 'onCopy', + 'onCut', + 'onDblclick', + 'onDeactivate', + 'onDirty', + 'onDrag', + 'onDragDrop', + 'onDragEnd', + 'onDragGesture', + 'onDragOver', + 'onDrop', + 'onExecCommand', + 'onFocus', + 'onFocusIn', + 'onFocusOut', + 'onGetContent', + 'onHide', + 'onInit', + 'onKeyDown', + 'onKeyPress', + 'onKeyUp', + 'onLoadContent', + 'onMouseDown', + 'onMouseEnter', + 'onMouseLeave', + 'onMouseMove', + 'onMouseOut', + 'onMouseOver', + 'onMouseUp', + 'onNodeChange', + 'onObjectResizeStart', + 'onObjectResized', + 'onObjectSelected', + 'onPaste', + 'onPostProcess', + 'onPostRender', + 'onPreProcess', + 'onProgressState', + 'onRedo', + 'onRemove', + 'onReset', + 'onSaveContent', + 'onSelectionChange', + 'onSetAttrib', + 'onSetContent', + 'onShow', + 'onSubmit', + 'onUndo', + 'onVisualAid', +]; + +const isValidKey = (key: string) => validEvents.indexOf(key) !== -1; + +export const bindHandlers = (initEvent: Event, listeners: any, editor: any): void => { + Object.keys(listeners) + .filter(isValidKey) + .forEach((key: string) => { + const handler = listeners[key]; + if (typeof handler === 'function') { + if (key === 'onInit') { + handler(initEvent, editor); + } else { + editor.on(key.substring(2), (e: any) => handler(e, editor)); + } + } + }); +}; diff --git a/src/components/Tinymce/src/lib/ScriptLoader.ts b/src/components/Tinymce/src/lib/ScriptLoader.ts deleted file mode 100644 index d747505d..00000000 --- a/src/components/Tinymce/src/lib/ScriptLoader.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { uuid } from './Utils'; - -export type callbackFn = () => void; -export interface IStateObj { - listeners: callbackFn[]; - scriptId: string; - scriptLoaded: boolean; -} - -const createState = (): IStateObj => { - return { - listeners: [], - scriptId: uuid('tiny-script'), - scriptLoaded: false - }; -}; - -interface ScriptLoader { - load: (doc: Document, url: string, callback: callbackFn) => void; - reinitialize: () => void; -} - -const CreateScriptLoader = (): ScriptLoader => { - let state: IStateObj = createState(); - - const injectScriptTag = (scriptId: string, doc: Document, url: string, callback: callbackFn) => { - const scriptTag = doc.createElement('script'); - scriptTag.referrerPolicy = 'origin'; - scriptTag.type = 'application/javascript'; - scriptTag.id = scriptId; - scriptTag.src = url; - - const handler = () => { - scriptTag.removeEventListener('load', handler); - callback(); - }; - scriptTag.addEventListener('load', handler); - if (doc.head) { - doc.head.appendChild(scriptTag); - } - }; - - const load = (doc: Document, url: string, callback: callbackFn) => { - if (state.scriptLoaded) { - callback(); - } else { - state.listeners.push(callback); - if (!doc.getElementById(state.scriptId)) { - injectScriptTag(state.scriptId, doc, url, () => { - state.listeners.forEach((fn) => fn()); - state.scriptLoaded = true; - }); - } - } - }; - - // Only to be used by tests. - const reinitialize = () => { - state = createState(); - }; - - return { - load, - reinitialize - }; -}; - -const ScriptLoader = CreateScriptLoader(); - -export { - ScriptLoader -}; \ No newline at end of file diff --git a/src/components/Tinymce/src/lib/Utils.ts b/src/components/Tinymce/src/lib/Utils.ts deleted file mode 100644 index 2685ee93..00000000 --- a/src/components/Tinymce/src/lib/Utils.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { ComponentPublicInstance } from 'vue'; - -const validEvents = [ - 'onActivate', - 'onAddUndo', - 'onBeforeAddUndo', - 'onBeforeExecCommand', - 'onBeforeGetContent', - 'onBeforeRenderUI', - 'onBeforeSetContent', - 'onBeforePaste', - 'onBlur', - 'onChange', - 'onClearUndos', - 'onClick', - 'onContextMenu', - 'onCopy', - 'onCut', - 'onDblclick', - 'onDeactivate', - 'onDirty', - 'onDrag', - 'onDragDrop', - 'onDragEnd', - 'onDragGesture', - 'onDragOver', - 'onDrop', - 'onExecCommand', - 'onFocus', - 'onFocusIn', - 'onFocusOut', - 'onGetContent', - 'onHide', - 'onInit', - 'onKeyDown', - 'onKeyPress', - 'onKeyUp', - 'onLoadContent', - 'onMouseDown', - 'onMouseEnter', - 'onMouseLeave', - 'onMouseMove', - 'onMouseOut', - 'onMouseOver', - 'onMouseUp', - 'onNodeChange', - 'onObjectResizeStart', - 'onObjectResized', - 'onObjectSelected', - 'onPaste', - 'onPostProcess', - 'onPostRender', - 'onPreProcess', - 'onProgressState', - 'onRedo', - 'onRemove', - 'onReset', - 'onSaveContent', - 'onSelectionChange', - 'onSetAttrib', - 'onSetContent', - 'onShow', - 'onSubmit', - 'onUndo', - 'onVisualAid' -]; - -const isValidKey = (key: string) => validEvents.indexOf(key) !== -1; - -const bindHandlers = (initEvent: Event, listeners: any, editor: any): void => { - Object.keys(listeners) - .filter(isValidKey) - .forEach((key: string) => { - const handler = listeners[key]; - if (typeof handler === 'function') { - if (key === 'onInit') { - handler(initEvent, editor); - } else { - editor.on(key.substring(2), (e: any) => handler(e, editor)); - } - } - }); -}; - -const bindModelHandlers = (ctx: ComponentPublicInstance, editor: any) => { - const modelEvents = ctx.$props.modelEvents ? ctx.$props.modelEvents : null; - const normalizedEvents = Array.isArray(modelEvents) ? modelEvents.join(' ') : modelEvents; - // @ts-ignore - ctx.$watch('modelValue', (val: string, prevVal: string) => { - if (editor && typeof val === 'string' && val !== prevVal && val !== editor.getContent({ format: ctx.$props.outputFormat })) { - editor.setContent(val); - } - }); - - editor.on(normalizedEvents ? normalizedEvents : 'change keyup undo redo', () => { - ctx.$emit('update:modelValue', editor.getContent({ format: ctx.$props.outputFormat })); - }); -}; - -const initEditor = (initEvent: Event, ctx: ComponentPublicInstance, editor: any) => { - const value = ctx.$props.modelValue ? ctx.$props.modelValue : ''; - const initialValue = ctx.$props.initialValue ? ctx.$props.initialValue : ''; - - editor.setContent(value || initialValue); - - // checks if the v-model shorthand is used (which sets an v-on:input listener) and then binds either - // specified the events or defaults to "change keyup" event and emits the editor content on that event - if (ctx.$attrs['onUpdate:modelValue']) { - bindModelHandlers(ctx, editor); - } - - bindHandlers(initEvent, ctx.$attrs, editor); -}; - -let unique = 0; - -const uuid = (prefix: string): string => { - const time = Date.now(); - const random = Math.floor(Math.random() * 1000000000); - - unique++; - - return prefix + '_' + random + unique + String(time); -}; - -const isTextarea = (element: Element | null): element is HTMLTextAreaElement => { - return element !== null && element.tagName.toLowerCase() === 'textarea'; -}; - -const normalizePluginArray = (plugins?: string | string[]): string[] => { - if (typeof plugins === 'undefined' || plugins === '') { - return []; - } - - return Array.isArray(plugins) ? plugins : plugins.split(' '); -}; - -const mergePlugins = (initPlugins: string | string[], inputPlugins?: string | string[]) => - normalizePluginArray(initPlugins).concat(normalizePluginArray(inputPlugins)); - -const isNullOrUndefined = (value: any): value is null | undefined => value === null || value === undefined; - -export { - bindHandlers, - bindModelHandlers, - initEditor, - uuid, - isTextarea, - mergePlugins, - isNullOrUndefined -}; \ No newline at end of file diff --git a/src/components/Tinymce/src/lib/components/Editor.ts b/src/components/Tinymce/src/lib/components/Editor.ts deleted file mode 100644 index 1317515f..00000000 --- a/src/components/Tinymce/src/lib/components/Editor.ts +++ /dev/null @@ -1,111 +0,0 @@ -/** - * Copyright (c) 2018-present, Ephox, Inc. - * - * This source code is licensed under the Apache 2 license found in the - * LICENSE file in the root directory of this source tree. - * - */ - -// import { ThisTypedComponentOptionsWithRecordProps } from 'vue/types/options'; -// import { CreateElement, Vue } from 'vue/types/vue'; - -import { ScriptLoader } from '../ScriptLoader'; -import { getTinymce } from '../TinyMCE'; -import { initEditor, isTextarea, mergePlugins, uuid, isNullOrUndefined } from '../Utils'; -import { editorProps, IPropTypes } from './EditorPropTypes'; -import { h, defineComponent, ComponentPublicInstance } from 'vue' - - -export interface IEditor { - $props: Partial -} - -declare module '@vue/runtime-core' { - interface ComponentCustomProperties { - elementId: string; - element: Element | null; - editor: any; - inlineEditor: boolean; - $props: Partial; - } -} - - -const renderInline = (id: string, tagName?: string) => { - return h(tagName ? tagName : 'div', { - id - }); -}; - -const renderIframe = (id: string) => { - return h('textarea', { - id, - visibility: 'hidden' - }); -}; - -const initialise = (ctx: ComponentPublicInstance) => () => { - const finalInit = { - ...ctx.$props.init, - readonly: ctx.$props.disabled, - selector: `#${ctx.elementId}`, - plugins: mergePlugins(ctx.$props.init && ctx.$props.init.plugins, ctx.$props.plugins), - toolbar: ctx.$props.toolbar || (ctx.$props.init && ctx.$props.init.toolbar), - inline: ctx.inlineEditor, - setup: (editor: any) => { - ctx.editor = editor; - editor.on('init', (e: Event) => initEditor(e, ctx, editor)); - - if (ctx.$props.init && typeof ctx.$props.init.setup === 'function') { - ctx.$props.init.setup(editor); - } - } - }; - - if (isTextarea(ctx.element)) { - ctx.element.style.visibility = ''; - } - - getTinymce().init(finalInit); -}; - -export const Editor = defineComponent({ - props: editorProps, - created() { - this.elementId = this.$props.id || uuid('tiny-vue'); - this.inlineEditor = (this.$props.init && this.$props.init.inline) || this.$props.inline; - }, - watch: { - disabled() { - (this as any).editor.setMode(this.disabled ? 'readonly' : 'design'); - } - }, - mounted() { - this.element = this.$el; - - if (getTinymce() !== null) { - initialise(this)(); - } else if (this.element && this.element.ownerDocument) { - const channel = this.$props.cloudChannel ? this.$props.cloudChannel : '5'; - const apiKey = this.$props.apiKey ? this.$props.apiKey : 'no-api-key'; - - const scriptSrc = isNullOrUndefined(this.$props.tinymceScriptSrc) ? - `https://cdn.tiny.cloud/1/${apiKey}/tinymce/${channel}/tinymce.min.js` : - this.$props.tinymceScriptSrc; - - ScriptLoader.load( - this.element.ownerDocument, - scriptSrc, - initialise(this) - ); - } - }, - beforeUnmount() { - if (getTinymce() !== null) { - getTinymce().remove(this.editor); - } - }, - render() { - return this.inlineEditor ? renderInline(this.elementId, this.$props.tagName) : renderIframe(this.elementId); - } -}) diff --git a/src/components/Tinymce/src/lib/components/EditorPropTypes.ts b/src/components/Tinymce/src/lib/components/EditorPropTypes.ts deleted file mode 100644 index 23619fef..00000000 --- a/src/components/Tinymce/src/lib/components/EditorPropTypes.ts +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) 2018-present, Ephox, Inc. - * - * This source code is licensed under the Apache 2 license found in the - * LICENSE file in the root directory of this source tree. - * - */ - -export type CopyProps = { [P in keyof T]: any }; - -export interface IPropTypes { - apiKey: string; - cloudChannel: string; - id: string; - init: any; - initialValue: string; - outputFormat: 'html' | 'text'; - inline: boolean; - modelEvents: string[] | string; - plugins: string[] | string; - tagName: string; - toolbar: string[] | string; - modelValue: string; - disabled: boolean; - tinymceScriptSrc: string; -} - -export const editorProps: CopyProps = { - apiKey: String, - cloudChannel: String, - id: String, - init: Object, - initialValue: String, - inline: Boolean, - modelEvents: [String, Array], - plugins: [String, Array], - tagName: String, - toolbar: [String, Array], - modelValue: String, - disabled: Boolean, - tinymceScriptSrc: String, - outputFormat: { - type: String, - validator: (prop: string) => prop === 'html' || prop === 'text' - }, -}; diff --git a/src/components/Tinymce/src/lib/global.d.ts b/src/components/Tinymce/src/lib/global.d.ts deleted file mode 100644 index d1785b3d..00000000 --- a/src/components/Tinymce/src/lib/global.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Global compile-time constants -declare var __DEV__: boolean -declare var __BROWSER__: boolean -declare var __CI__: boolean diff --git a/src/components/Tinymce/src/lib/index.ts b/src/components/Tinymce/src/lib/index.ts deleted file mode 100644 index 7cf759e6..00000000 --- a/src/components/Tinymce/src/lib/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { Editor } from './components/Editor'; - -export default Editor; diff --git a/src/components/Tinymce/src/props.ts b/src/components/Tinymce/src/props.ts index 8f7e227d..231ae19d 100644 --- a/src/components/Tinymce/src/props.ts +++ b/src/components/Tinymce/src/props.ts @@ -1,12 +1,6 @@ import { PropType } from 'vue'; export const basicProps = { - id: { - type: String as PropType, - default: () => { - return `tinymce-${new Date().getTime()}${(Math.random() * 1000).toFixed(0)}`; - }, - }, menubar: { type: String as PropType, default: 'file edit insert view format table', @@ -15,6 +9,10 @@ export const basicProps = { type: String as PropType, // default: '' }, + modelValue: { + type: String as PropType, + // default: '' + }, // 高度 height: { type: [Number, String] as PropType, diff --git a/src/router/menus/modules/demo/charts.ts b/src/router/menus/modules/demo/charts.ts index 77967992..fd8c6db6 100644 --- a/src/router/menus/modules/demo/charts.ts +++ b/src/router/menus/modules/demo/charts.ts @@ -6,23 +6,23 @@ const menu: MenuModule = { path: '/charts', children: [ { - path: '/apexChart', + path: 'apexChart', name: 'ApexChart', }, { - path: '/echarts', + path: 'echarts', name: 'Echarts', children: [ { - path: '/map', + path: 'map', name: '地图', }, { - path: '/line', + path: 'line', name: '折线图', }, { - path: '/pie', + path: 'pie', name: '饼图', }, ], diff --git a/src/router/menus/modules/demo/comp.ts b/src/router/menus/modules/demo/comp.ts index c477de29..b8b47a73 100644 --- a/src/router/menus/modules/demo/comp.ts +++ b/src/router/menus/modules/demo/comp.ts @@ -6,16 +6,16 @@ const menu: MenuModule = { path: '/comp', children: [ { - path: '/basic', + path: 'basic', name: '基础组件', }, { - path: '/countTo', + path: 'countTo', name: '数字动画', }, { - path: '/scroll', + path: 'scroll', name: '滚动组件', children: [ { @@ -33,53 +33,39 @@ const menu: MenuModule = { ], }, { - path: '/modal', + path: 'modal', name: '弹窗扩展', }, { - path: '/drawer', + path: 'drawer', name: '抽屉扩展', }, { - path: '/desc', + path: 'desc', name: '详情组件', }, { - path: '/verify', + path: 'verify', name: '验证组件', children: [ { - path: '/drag', + path: 'drag', name: '拖拽校验', }, { - path: '/rotate', + path: 'rotate', name: '图片还原校验', }, ], }, { - path: '/qrcode', + path: 'qrcode', name: '二维码组件', }, { - path: '/strength-meter', + path: 'strength-meter', name: '密码强度组件', }, - { - path: '/tinymce', - name: '富文本', - children: [ - { - path: '/index', - name: '基础使用', - }, - { - path: '/editor', - name: '嵌入form使用', - }, - ], - }, ], }, }; diff --git a/src/router/menus/modules/demo/editor.ts b/src/router/menus/modules/demo/editor.ts index 0fbdaa2f..eb307dca 100644 --- a/src/router/menus/modules/demo/editor.ts +++ b/src/router/menus/modules/demo/editor.ts @@ -6,9 +6,23 @@ const menu: MenuModule = { path: '/editor', children: [ { - path: '/markdown', + path: 'markdown', name: 'markdown编辑器', }, + { + path: 'tinymce', + name: '富文本', + children: [ + { + path: 'index', + name: '基础使用', + }, + // { + // path: 'editor', + // name: '嵌入form使用', + // }, + ], + }, ], }, }; diff --git a/src/router/menus/modules/demo/excel.ts b/src/router/menus/modules/demo/excel.ts index affef81f..53a619ba 100644 --- a/src/router/menus/modules/demo/excel.ts +++ b/src/router/menus/modules/demo/excel.ts @@ -6,23 +6,21 @@ const menu: MenuModule = { path: '/excel', children: [ { - path: '/customExport', + path: 'customExport', name: '选择导出格式', }, { - path: '/jsonExport', + path: 'jsonExport', name: 'JSON数据导出', }, { - path: '/arrayExport', + path: 'arrayExport', name: 'Array数据导出', }, { - path: '/importExcel', + path: 'importExcel', name: '导入', }, - // ], - // }, ], }, }; diff --git a/src/router/menus/modules/demo/exception.ts b/src/router/menus/modules/demo/exception.ts index 7e5bf4eb..a3e11986 100644 --- a/src/router/menus/modules/demo/exception.ts +++ b/src/router/menus/modules/demo/exception.ts @@ -6,27 +6,27 @@ const menu: MenuModule = { path: '/exception', children: [ { - path: '/404', + path: '404', name: '404', }, { - path: '/500', + path: '500', name: '500', }, { - path: '/net-work-error', + path: 'net-work-error', name: '网络错误', }, { - path: '/page-time-out', + path: 'page-time-out', name: '页面超时', }, { - path: '/not-data', + path: 'not-data', name: '无数据', }, { - path: '/error-log', + path: 'error-log', name: '错误日志', }, ], diff --git a/src/router/menus/modules/demo/feat.ts b/src/router/menus/modules/demo/feat.ts index 83f854ee..603c43ed 100644 --- a/src/router/menus/modules/demo/feat.ts +++ b/src/router/menus/modules/demo/feat.ts @@ -6,55 +6,55 @@ const menu: MenuModule = { path: '/feat', children: [ { - path: '/icon', + path: 'icon', name: '图标', }, { - path: '/tabs', + path: 'tabs', name: '标签页操作', }, { - path: '/context-menu', + path: 'context-menu', name: '右键菜单', }, { - path: '/click-out-side', + path: 'click-out-side', name: 'ClickOutSide', }, { - path: '/img-preview', + path: 'img-preview', name: '图片预览', }, { - path: '/i18n', + path: 'i18n', name: '国际化', }, { - path: '/copy', + path: 'copy', name: '剪切板', }, { - path: '/msg', + path: 'msg', name: '消息提示', }, { - path: '/watermark', + path: 'watermark', name: '水印', }, { - path: '/full-screen', + path: 'full-screen', name: '全屏', }, { - path: '/testTab', + path: 'testTab', name: '带参Tab', children: [ { - path: '/id1', + path: 'id1', name: '带参tab1', }, { - path: '/id2', + path: 'id2', name: '带参tab2', }, ], diff --git a/src/router/menus/modules/demo/form.ts b/src/router/menus/modules/demo/form.ts index d1c5c68b..01a8e321 100644 --- a/src/router/menus/modules/demo/form.ts +++ b/src/router/menus/modules/demo/form.ts @@ -6,31 +6,31 @@ const menu: MenuModule = { name: 'Form', children: [ { - path: '/basic', + path: 'basic', name: '基础表单', }, { - path: '/useForm', + path: 'useForm', name: 'useForm', }, { - path: '/refForm', + path: 'refForm', name: 'RefForm', }, { - path: '/advancedForm', + path: 'advancedForm', name: '可收缩表单', }, { - path: '/ruleForm', + path: 'ruleForm', name: '表单校验', }, { - path: '/dynamicForm', + path: 'dynamicForm', name: '动态表单', }, { - path: '/customerForm', + path: 'customerForm', name: '自定义组件', }, ], diff --git a/src/router/menus/modules/demo/iframe.ts b/src/router/menus/modules/demo/iframe.ts index cf340455..14b10249 100644 --- a/src/router/menus/modules/demo/iframe.ts +++ b/src/router/menus/modules/demo/iframe.ts @@ -6,15 +6,15 @@ const menu: MenuModule = { path: '/frame', children: [ { - path: '/antv', + path: 'antv', name: 'antVue文档(内嵌)', }, { - path: '/doc', + path: 'doc', name: '项目文档(内嵌)', }, { - path: '/docExternal', + path: 'docExternal', name: '项目文档(外链)', }, ], diff --git a/src/router/menus/modules/demo/permission.ts b/src/router/menus/modules/demo/permission.ts index 237d207c..2fc6dacc 100644 --- a/src/router/menus/modules/demo/permission.ts +++ b/src/router/menus/modules/demo/permission.ts @@ -6,37 +6,37 @@ const menu: MenuModule = { path: '/permission', children: [ { - path: '/front', + path: 'front', name: '基于前端', children: [ { - path: '/page', + path: 'page', name: '页面权限', }, { - path: '/btn', + path: 'btn', name: '按钮权限', }, { - path: '/auth-pageA', + path: 'auth-pageA', name: '权限测试页A', }, { - path: '/auth-pageB', + path: 'auth-pageB', name: '权限测试页B', }, ], }, { - path: '/back', + path: 'back', name: '基于后台', children: [ { - path: '/page', + path: 'page', name: '页面权限', }, { - path: '/btn', + path: 'btn', name: '按钮权限', }, ], diff --git a/src/router/menus/modules/demo/table.ts b/src/router/menus/modules/demo/table.ts index 7bad75c9..555d60ea 100644 --- a/src/router/menus/modules/demo/table.ts +++ b/src/router/menus/modules/demo/table.ts @@ -6,59 +6,59 @@ const menu: MenuModule = { name: 'Table', children: [ { - path: '/basic', + path: 'basic', name: '基础表格', }, { - path: '/treeTable', + path: 'treeTable', name: '树形表格', }, { - path: '/fetchTable', + path: 'fetchTable', name: '远程加载', }, { - path: '/fixedColumn', + path: 'fixedColumn', name: '固定列', }, { - path: '/customerCell', + path: 'customerCell', name: '自定义列', }, { - path: '/formTable', + path: 'formTable', name: '开启搜索区域', }, { - path: '/useTable', + path: 'useTable', name: 'UseTable', }, { - path: '/refTable', + path: 'refTable', name: 'RefTable', }, { - path: '/multipleHeader', + path: 'multipleHeader', name: '多级表头', }, { - path: '/mergeHeader', + path: 'mergeHeader', name: '合并单元格', }, { - path: '/expandTable', + path: 'expandTable', name: '可展开表格', }, { - path: '/fixedHeight', + path: 'fixedHeight', name: '定高/头部自定义', }, { - path: '/footerTable', + path: 'footerTable', name: '表尾行合计', }, { - path: '/editCellTable', + path: 'editCellTable', name: '可编辑单元格', }, ], diff --git a/src/router/routes/modules/demo/comp.ts b/src/router/routes/modules/demo/comp.ts index 934dd24d..dc7c687e 100644 --- a/src/router/routes/modules/demo/comp.ts +++ b/src/router/routes/modules/demo/comp.ts @@ -136,31 +136,5 @@ export default { title: '密码强度组件', }, }, - { - path: '/tinymce', - name: 'TinymceDemo', - meta: { - title: '富文本', - }, - redirect: '/comp/tinymce/index', - children: [ - { - path: 'index', - name: 'Tinymce', - component: () => import('/@/views/demo/comp/tinymce/index.vue'), - meta: { - title: '基础使用', - }, - }, - { - path: 'editor', - name: 'TinymceEditor', - component: () => import('/@/views/demo/comp/tinymce/Editor.vue'), - meta: { - title: '嵌入form使用', - }, - }, - ], - }, ], } as AppRouteModule; diff --git a/src/router/routes/modules/demo/editor.ts b/src/router/routes/modules/demo/editor.ts index 482a0bd3..cf54ea33 100644 --- a/src/router/routes/modules/demo/editor.ts +++ b/src/router/routes/modules/demo/editor.ts @@ -23,5 +23,32 @@ export default { title: 'markdown编辑器', }, }, + { + path: '/tinymce', + name: 'TinymceDemo', + meta: { + title: '富文本', + }, + redirect: '/editor/tinymce/index', + children: [ + { + path: 'index', + name: 'TinymceBasicDemo', + component: () => import('/@/views/demo/editor/tinymce/index.vue'), + meta: { + title: '基础使用', + }, + }, + // TODO + // { + // path: 'editor', + // name: 'TinymceFormDemo', + // component: () => import('/@/views/demo/comp/tinymce/Editor.vue'), + // meta: { + // title: '嵌入form使用', + // }, + // }, + ], + }, ], } as AppRouteModule; diff --git a/src/utils/is.ts b/src/utils/is.ts index 99ef156e..5657c1ca 100644 --- a/src/utils/is.ts +++ b/src/utils/is.ts @@ -67,3 +67,7 @@ export const isServer = typeof window === 'undefined'; export function isImageDom(o: Element) { return o && ['IMAGE', 'IMG'].includes(o.tagName); } + +export const isTextarea = (element: Element | null): element is HTMLTextAreaElement => { + return element !== null && element.tagName.toLowerCase() === 'textarea'; +}; diff --git a/src/utils/uuid.ts b/src/utils/uuid.ts index f9a24cf6..6b66f65b 100644 --- a/src/utils/uuid.ts +++ b/src/utils/uuid.ts @@ -17,3 +17,11 @@ export function buildUUID(): string { } return uuid.replace(/-/g, ''); } + +let unique = 0; +export function snowUuid(prefix: string): string { + const time = Date.now(); + const random = Math.floor(Math.random() * 1000000000); + unique++; + return prefix + '_' + random + unique + String(time); +} diff --git a/src/views/demo/comp/tinymce/Editor.vue b/src/views/demo/editor/tinymce/Editor.vue similarity index 96% rename from src/views/demo/comp/tinymce/Editor.vue rename to src/views/demo/editor/tinymce/Editor.vue index 2b9de95a..b5f9bb03 100644 --- a/src/views/demo/comp/tinymce/Editor.vue +++ b/src/views/demo/editor/tinymce/Editor.vue @@ -43,7 +43,7 @@ }, ]; export default defineComponent({ - components: { BasicForm, CollapseContainer, Tinymce }, + components: { BasicForm, CollapseContainer }, setup() { const { createMessage } = useMessage(); diff --git a/src/views/demo/comp/tinymce/index.vue b/src/views/demo/editor/tinymce/index.vue similarity index 52% rename from src/views/demo/comp/tinymce/index.vue rename to src/views/demo/editor/tinymce/index.vue index 53921928..b3c2e5e5 100644 --- a/src/views/demo/comp/tinymce/index.vue +++ b/src/views/demo/editor/tinymce/index.vue @@ -1,19 +1,24 @@ -- GitLab