@wangeditor-next/video-module 4.0.0 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/utils/dom.ts","../src/locale/index.ts","../src/locale/en.ts","../src/locale/zh-CN.ts","../src/module/alignment.ts","../src/module/elem-to-html.ts","../src/utils/util.ts","../src/module/menu/EditVideoSizeMenu.ts","../src/module/menu/EditVideoSrcMenu.ts","../src/constants/svg.ts","../src/module/helper/insert-video.ts","../src/module/menu/InsertVideoMenu.ts","../src/module/helper/upload-videos.ts","../src/module/menu/UploadVideoMenu.ts","../src/module/menu/VideoAlignMenu.ts","../src/module/parse-elem-html.ts","../src/module/render-elem.tsx","../src/module/index.ts","../src/module/pre-parse-html.ts","../src/module/menu/index.ts","../src/module/menu/config.ts","../src/module/plugin.ts"],"sourcesContent":["/**\n * @description DOM 操作\n * @author wangfupeng\n */\n\nimport $, {\n append, attr, Dom7Array, empty, focus, hasClass, html, on, parent, val,\n} from 'dom7'\n\nimport { videoStyle } from '../module/custom-types'\n\n// COMPAT: This is required to prevent TypeScript aliases from doing some very\n// weird things for Slate's types with the same name as globals. (2019/11/27)\n// https://github.com/microsoft/TypeScript/issues/35002\nimport DOMNode = globalThis.Node\nimport DOMComment = globalThis.Comment\nimport DOMElement = globalThis.Element\nimport DOMText = globalThis.Text\nimport DOMRange = globalThis.Range\nimport DOMSelection = globalThis.Selection\nimport DOMStaticRange = globalThis.StaticRange\n\nexport { Dom7Array } from 'dom7'\n\nif (append) { $.fn.append = append }\nif (on) { $.fn.on = on }\nif (focus) { $.fn.focus = focus }\nif (attr) { $.fn.attr = attr }\nif (val) { $.fn.val = val }\nif (html) { $.fn.html = html }\nif (parent) { $.fn.parent = parent }\nif (hasClass) { $.fn.hasClass = hasClass }\nif (empty) { $.fn.empty = empty }\n\nexport default $\n\n/**\n * 获取 tagName lower-case\n * @param $elem $elem\n */\nexport function getTagName($elem: Dom7Array): string {\n if ($elem.length) { return $elem[0].tagName.toLowerCase() }\n return ''\n}\n\n/**\n * 生成带 size 样式的 iframe html\n * @param iframeHtml iframe html string\n * @param width width\n * @param height height\n * @returns iframe html string with size style\n */\nexport function genSizeStyledIframeHtml(\n iframeHtml: string,\n width = 'auto',\n height = 'auto',\n style: videoStyle = {},\n classMode = false,\n): string {\n const $iframe = $(iframeHtml)\n const { width: styleWidth = '', height: styleHeight = '' } = style\n const widthData = styleWidth ? `data-w-e-style-width=\"${styleWidth}\"` : ''\n const heightData = styleHeight ? `data-w-e-style-height=\"${styleHeight}\"` : ''\n\n $iframe.attr('width', width)\n $iframe.attr('height', height)\n\n if (!classMode) {\n let styleStr = 'display: block; max-width: 100%;'\n\n if (styleWidth) { styleStr += ` width: ${styleWidth};` }\n if (styleHeight) { styleStr += ` height: ${styleHeight};` }\n $iframe.attr('style', styleStr)\n } else {\n if (widthData) { $iframe.attr('data-w-e-style-width', styleWidth) }\n if (heightData) { $iframe.attr('data-w-e-style-height', styleHeight) }\n $iframe.removeAttr('style')\n }\n return $iframe[0].outerHTML\n}\nexport {\n DOMComment, DOMElement, DOMNode, DOMRange, DOMSelection, DOMStaticRange, DOMText,\n}\n","/**\n * @description i18n entry\n * @author wangfupeng\n */\n\nimport { i18nAddResources } from '@wangeditor-next/core'\n\nimport enResources from './en'\nimport zhResources from './zh-CN'\n\ni18nAddResources('en', enResources)\ni18nAddResources('zh-CN', zhResources)\n","/**\n * @description i18n en\n * @author wangfupeng\n */\n\nexport default {\n videoModule: {\n delete: 'Delete',\n uploadVideo: 'Upload video',\n insertVideo: 'Insert video',\n videoSrc: 'Video source',\n videoSrcPlaceHolder: 'Video file url, or third-party <iframe>',\n videoPoster: 'Video poster',\n videoPosterPlaceHolder: 'Poster image url',\n ok: 'Ok',\n editSize: 'Edit size',\n edit: 'Edit video',\n width: 'Width',\n height: 'Height',\n alignLeft: 'Align video left',\n alignCenter: 'Center video',\n alignRight: 'Align video right',\n },\n}\n","/**\n * @description i18n zh-CN\n * @author wangfupeng\n */\n\nexport default {\n videoModule: {\n delete: '删除视频',\n uploadVideo: '上传视频',\n insertVideo: '插入视频',\n videoSrc: '视频地址',\n videoSrcPlaceHolder: '视频文件 url 或第三方 <iframe>',\n videoPoster: '视频封面',\n videoPosterPlaceHolder: '封面图片 url',\n ok: '确定',\n editSize: '修改尺寸',\n edit: '编辑视频',\n width: '宽度',\n height: '高度',\n alignLeft: '视频左对齐',\n alignCenter: '视频居中',\n alignRight: '视频右对齐',\n },\n}\n","/**\n * @description video alignment helpers\n */\n\nimport { Element } from 'slate'\n\nimport { VideoAlign, VideoElement } from './custom-types'\n\nexport const DEFAULT_VIDEO_ALIGN: VideoAlign = 'center'\n\nconst VIDEO_ALIGNS: VideoAlign[] = ['left', 'center', 'right']\n\nexport function normalizeVideoAlign(value: unknown): VideoAlign {\n if (typeof value !== 'string') {\n return DEFAULT_VIDEO_ALIGN\n }\n\n const align = value.trim().toLowerCase() as VideoAlign\n\n return VIDEO_ALIGNS.includes(align) ? align : DEFAULT_VIDEO_ALIGN\n}\n\nexport function getVideoAlign(elemNode: Element): VideoAlign {\n const { align } = elemNode as VideoElement\n\n if (align) {\n return normalizeVideoAlign(align)\n }\n\n // Import-only adapter for content created before video alignment became media-specific.\n const { textAlign } = elemNode as Element & { textAlign?: unknown }\n\n return normalizeVideoAlign(textAlign)\n}\n\nexport function getVideoAlignClass(align: VideoAlign): string {\n return `w-e-video-align-${align}`\n}\n\nexport function getVideoJustifyContent(align: VideoAlign): string {\n if (align === 'left') {\n return 'flex-start'\n }\n if (align === 'right') {\n return 'flex-end'\n }\n return 'center'\n}\n","/**\n * @description to html\n * @author wangfupeng\n */\n\nimport { getTextStyleMode, IDomEditor } from '@wangeditor-next/core'\nimport { Element } from 'slate'\n\nimport { genSizeStyledIframeHtml } from '../utils/dom'\nimport { getVideoAlign, getVideoAlignClass, getVideoJustifyContent } from './alignment'\nimport { VideoElement } from './custom-types'\n\nfunction videoToHtml(elemNode: Element, _childrenHtml?: string, editor?: IDomEditor): string {\n const {\n src = '',\n poster = '',\n width = 'auto',\n height = 'auto',\n style = {},\n } = elemNode as VideoElement\n const mode = getTextStyleMode(editor)\n const align = getVideoAlign(elemNode)\n const alignData = ` data-w-e-align=\"${align}\"`\n const containerAttrs = mode === 'class'\n ? `${alignData} class=\"w-e-video ${getVideoAlignClass(align)}\"`\n : `${alignData} style=\"display: flex; justify-content: ${getVideoJustifyContent(align)}; margin: 0; max-width: 100%; width: 100%;\"`\n let res = `<figure data-w-e-type=\"video\" data-w-e-is-void${containerAttrs}>\\n`\n\n if (src.trim().indexOf('<iframe ') === 0) {\n // iframe 形式\n const iframeHtml = genSizeStyledIframeHtml(src, width, height, style, mode === 'class')\n\n res += iframeHtml\n } else {\n // 其他,mp4 等 url 格式\n const { width: styleWidth = '', height: styleHeight = '' } = style\n\n if (mode === 'class') {\n const widthData = styleWidth ? ` data-w-e-style-width=\"${styleWidth}\"` : ''\n const heightData = styleHeight ? ` data-w-e-style-height=\"${styleHeight}\"` : ''\n\n res += `<video poster=\"${poster}\" controls=\"true\" width=\"${width}\" height=\"${height}\"${widthData}${heightData}><source src=\"${src}\" type=\"video/mp4\"/></video>`\n } else {\n let styleStr = 'display: block; max-width: 100%;'\n\n if (styleWidth) { styleStr += ` width: ${styleWidth};` }\n if (styleHeight) { styleStr += ` height: ${styleHeight};` }\n res += `<video poster=\"${poster}\" controls=\"true\" width=\"${width}\" height=\"${height}\" style=\"${styleStr}\"><source src=\"${src}\" type=\"video/mp4\"/></video>`\n }\n }\n res += '\\n</figure>'\n\n return res\n}\n\nexport const videoToHtmlConf = {\n type: 'video',\n elemToHtml: videoToHtml,\n}\n","/**\n * @description 工具函数\n * @author wangfupeng\n */\n\nimport { nanoid } from 'nanoid'\n\n/**\n * 获取随机数字符串\n * @param prefix 前缀\n * @returns 随机数字符串\n */\nexport function genRandomStr(prefix = 'r'): string {\n return `${prefix}-${nanoid()}`\n}\n\nexport function replaceSymbols(str: string) {\n return str.replace(/</g, '&lt;').replace(/>/g, '&gt;')\n}\n\nexport function styleStringToObject(styleString) {\n const styleObject = {}\n\n // 去掉字符串两端的空格,然后按分号分割\n const styles = styleString.trim().split(';')\n\n // 迭代每一个样式属性对\n styles.forEach(style => {\n if (style) {\n // 忽略空字符串\n const [property, value] = style.split(':')\n\n if (property && value) {\n // 去掉两端的空格并将结果存储在对象中\n styleObject[property.trim()] = value.trim()\n }\n }\n })\n\n return styleObject\n}\n","/**\n * @description 修改视频尺寸\n * @author wangfupeng\n */\n\nimport {\n DomEditor,\n genModalButtonElems,\n genModalInputElems,\n IDomEditor,\n IModalMenu,\n t,\n} from '@wangeditor-next/core'\nimport { Node as SlateNode, Transforms } from 'slate'\n\nimport $, { Dom7Array, DOMElement } from '../../utils/dom'\nimport { genRandomStr } from '../../utils/util'\nimport { VideoElement } from '../custom-types'\n\n/**\n * 生成唯一的 DOM ID\n */\nfunction genDomID(): string {\n return genRandomStr('w-e-insert-video')\n}\n\nclass EditorVideoSizeMenu implements IModalMenu {\n readonly title = t('videoModule.editSize')\n\n readonly tag = 'button'\n\n readonly showModal = true // 点击 button 时显示 modal\n\n readonly modalWidth = 320\n\n private $content: Dom7Array | null = null\n\n private readonly widthInputId = genDomID()\n\n private readonly heightInputId = genDomID()\n\n private readonly buttonId = genDomID()\n\n private getSelectedVideoNode(editor: IDomEditor): SlateNode | null {\n return DomEditor.getSelectedNodeByType(editor, 'video')\n }\n\n getValue(_editor: IDomEditor): string | boolean {\n // 插入菜单,不需要 value\n return ''\n }\n\n isActive(_editor: IDomEditor): boolean {\n // 任何时候,都不用激活 menu\n return false\n }\n\n exec(_editor: IDomEditor, _value: string | boolean) {\n // 点击菜单时,弹出 modal 之前,不需要执行其他代码\n // 此处空着即可\n }\n\n isDisabled(editor: IDomEditor): boolean {\n if (editor.selection == null) { return true }\n\n const videoNode = this.getSelectedVideoNode(editor)\n\n if (videoNode == null) {\n // 选区未处于 video node ,则禁用\n return true\n }\n return false\n }\n\n getModalPositionNode(editor: IDomEditor): SlateNode | null {\n return this.getSelectedVideoNode(editor)\n }\n\n getModalContentElem(editor: IDomEditor): DOMElement {\n const { widthInputId, heightInputId, buttonId } = this\n\n const [widthContainerElem, inputWidthElem] = genModalInputElems(\n t('videoModule.width'),\n widthInputId,\n 'auto',\n )\n const $inputWidth = $(inputWidthElem)\n const [heightContainerElem, inputHeightElem] = genModalInputElems(\n t('videoModule.height'),\n heightInputId,\n 'auto',\n )\n const $inputHeight = $(inputHeightElem)\n const [buttonContainerElem] = genModalButtonElems(buttonId, t('videoModule.ok'))\n\n const videoNode = this.getSelectedVideoNode(editor) as VideoElement\n\n if (this.$content == null) {\n // 第一次渲染\n const $content = $('<div></div>')\n\n // 绑定事件(第一次渲染时绑定,不要重复绑定)\n $content.on('click', `#${buttonId}`, e => {\n e.preventDefault()\n\n const rawWidth = $content.find(`#${widthInputId}`).val().trim()\n const rawHeight = $content.find(`#${heightInputId}`).val().trim()\n\n const isPercentage = (value: string) => /^\\d+(\\.\\d+)?%$/.test(value) // 检查是否为合法的百分比字符串\n const isNumeric = (value: string) => /^\\d+(\\.\\d+)?$/.test(value) // 检查是否为合法的数字\n\n let width = 'auto'\n let height = 'auto'\n\n if (isPercentage(rawWidth)) {\n width = rawWidth\n } else if (isNumeric(rawWidth)) {\n width = `${parseInt(rawWidth, 10)}px`\n }\n\n if (isPercentage(rawHeight)) {\n height = rawHeight\n } else if (isNumeric(rawHeight)) {\n height = `${parseInt(rawHeight, 10)}px`\n }\n\n const { style = {} } = videoNode as VideoElement\n\n editor.restoreSelection()\n const props: Partial<VideoElement> = {\n style: {\n ...style,\n width,\n height,\n },\n }\n // 修改尺寸\n\n Transforms.setNodes(editor, props, {\n match: n => DomEditor.checkNodeType(n, 'video'),\n })\n\n editor.hidePanelOrModal() // 隐藏 modal\n })\n\n this.$content = $content\n }\n\n const $content = this.$content\n\n // 先清空,再重新添加 DOM 内容\n $content.empty()\n $content.append(widthContainerElem)\n $content.append(heightContainerElem)\n $content.append(buttonContainerElem)\n\n if (videoNode == null) { return $content[0] }\n\n // 初始化 input 值\n const { style = {} } = videoNode\n const { width = '', height = '' } = style\n\n $inputWidth.val(width)\n $inputHeight.val(height)\n setTimeout(() => {\n $inputWidth.focus()\n })\n\n return $content[0]\n }\n}\n\nexport default EditorVideoSizeMenu\n","/**\n * @description editor video menu\n * @author\n */\n\nimport {\n DomEditor,\n genModalButtonElems,\n genModalInputElems,\n IDomEditor,\n IModalMenu,\n t,\n} from '@wangeditor-next/core'\nimport { Node as SlateNode, Transforms } from 'slate'\n\nimport { PENCIL_SVG } from '../../constants/svg'\nimport $, { Dom7Array, DOMElement } from '../../utils/dom'\nimport { genRandomStr } from '../../utils/util'\nimport { VideoElement } from '../custom-types'\n\n/**\n * 生成唯一的 DOM ID\n */\nfunction genDomID(): string {\n return genRandomStr('w-e-edit-video')\n}\n\nclass Editvideo implements IModalMenu {\n readonly title = t('videoModule.edit')\n\n readonly iconSvg = PENCIL_SVG\n\n readonly tag = 'button'\n\n readonly showModal = true // 点击 button 时显示 modal\n\n readonly modalWidth = 300\n\n private $content: Dom7Array | null = null\n\n private readonly srcInputId = genDomID()\n\n private readonly posterInputId = genDomID()\n\n private readonly buttonId = genDomID()\n\n private getSelectedVideoNode(editor: IDomEditor): SlateNode | null {\n return DomEditor.getSelectedNodeByType(editor, 'video')\n }\n\n getValue(_editor: IDomEditor): string | boolean {\n // 编辑视频,用不到 getValue\n return ''\n }\n\n isActive(_editor: IDomEditor): boolean {\n // 无需 active\n return false\n }\n\n exec(_editor: IDomEditor, _value: string | boolean) {\n // 点击菜单时,弹出 modal 之前,不需要执行其他代码\n // 此处空着即可\n }\n\n isDisabled(editor: IDomEditor): boolean {\n if (editor.selection == null) { return true }\n\n const videoNode = this.getSelectedVideoNode(editor)\n\n if (videoNode == null) {\n // 选区未处于 video node ,则禁用\n return true\n }\n return false\n }\n\n getModalPositionNode(editor: IDomEditor): SlateNode | null {\n return this.getSelectedVideoNode(editor)\n }\n\n getModalContentElem(editor: IDomEditor): DOMElement {\n const { srcInputId, posterInputId, buttonId } = this\n\n // 获取 input button elem\n const [srcContainerElem, inputSrcElem] = genModalInputElems(\n t('videoModule.videoSrc'),\n srcInputId,\n t('videoModule.videoSrcPlaceHolder'),\n )\n const [posterContainerElem, inputPosterElem] = genModalInputElems(\n t('videoModule.videoPoster'),\n posterInputId,\n t('videoModule.videoPosterPlaceHolder'),\n )\n const $inputSrc = $(inputSrcElem)\n const $inputPoster = $(inputPosterElem)\n const [buttonContainerElem] = genModalButtonElems(buttonId, t('videoModule.ok'))\n\n if (this.$content == null) {\n // 第一次渲染\n const $content = $('<div></div>')\n\n // 绑定事件(第一次渲染时绑定,不要重复绑定)\n $content.on('click', `#${buttonId}`, async e => {\n e.preventDefault()\n\n const src = $content.find(`#${srcInputId}`).val().trim()\n const poster = $content.find(`#${posterInputId}`).val().trim()\n // video 标签必须要加 key,只修改 src 不会触发重新渲染\n const videoId = genRandomStr('video-')\n\n const props: Partial<VideoElement> = {\n src,\n poster,\n key: videoId,\n }\n\n editor.restoreSelection()\n // 修改尺寸\n Transforms.setNodes(editor, props, {\n match: n => DomEditor.checkNodeType(n, 'video'),\n })\n editor.hidePanelOrModal() // 隐藏 modal\n })\n\n // 记录属性,重要\n this.$content = $content\n }\n\n const $content = this.$content\n\n $content.empty() // 先清空内容\n\n // append inputs and button\n $content.append(srcContainerElem)\n $content.append(posterContainerElem)\n $content.append(buttonContainerElem)\n\n const videoNode = this.getSelectedVideoNode(editor) as VideoElement\n\n if (videoNode == null) { return $content[0] }\n\n // 初始化 input 值\n const { src = '', poster = '' } = videoNode\n\n $inputSrc.val(src)\n $inputPoster.val(poster)\n\n // focus 一个 input(异步,此时 DOM 尚未渲染)\n setTimeout(() => {\n $inputSrc.focus()\n })\n\n return $content[0]\n }\n}\n\nexport default Editvideo\n","/**\n * @description icon svg\n * @author wangfupeng\n */\n\n/**\n * 【注意】svg 字符串的长度 ,否则会导致代码体积过大\n * 尽量选择 https://www.iconfont.cn/collections/detail?spm=a313x.7781069.0.da5a778a4&cid=20293\n * 找不到再从 iconfont.com 搜索\n */\n\n// 视频\nexport const VIDEO_SVG = '<svg viewBox=\"0 0 1024 1024\"><path d=\"M981.184 160.096C837.568 139.456 678.848 128 512 128S186.432 139.456 42.816 160.096C15.296 267.808 0 386.848 0 512s15.264 244.16 42.816 351.904C186.464 884.544 345.152 896 512 896s325.568-11.456 469.184-32.096C1008.704 756.192 1024 637.152 1024 512s-15.264-244.16-42.816-351.904zM384 704V320l320 192-320 192z\"></path></svg>'\n\n// 上传视频\nexport const UPLOAD_VIDEO_SVG = '<svg viewBox=\"0 0 1056 1024\"><path d=\"M805.902261 521.819882a251.441452 251.441452 0 0 0-251.011972 246.600033 251.051015 251.051015 0 1 0 502.023944 8.823877 253.237463 253.237463 0 0 0-251.011972-255.42391z m59.463561 240.001647v129.898403h-116.701631v-129.898403h-44.041298l101.279368-103.504859 101.279368 103.504859z\" p-id=\"6802\"></path><path d=\"M788.254507 0.000781H99.094092A98.663439 98.663439 0 0 0 0.001171 99.093701v590.067495a98.663439 98.663439 0 0 0 99.092921 99.092921h411.7549a266.434235 266.434235 0 0 1-2.186448-41.815807 275.843767 275.843767 0 0 1 275.180024-270.729042 270.650955 270.650955 0 0 1 103.504859 19.834201V99.093701A101.51363 101.51363 0 0 0 788.254507 0.000781zM295.054441 640.747004V147.507894l394.146189 246.600033z\"></path></svg>'\n\n// 编辑\nexport const PENCIL_SVG = '<svg viewBox=\"0 0 1024 1024\"><path d=\"M864 0a160 160 0 0 1 128 256l-64 64-224-224 64-64c26.752-20.096 59.968-32 96-32zM64 736l-64 288 288-64 592-592-224-224L64 736z m651.584-372.416l-448 448-55.168-55.168 448-448 55.168 55.168z\"></path></svg>'\n\n// 视频左对齐\nexport const VIDEO_ALIGN_LEFT_SVG =\n '<svg viewBox=\"0 0 1024 1024\"><path d=\"M768 793.6v102.4H51.2v-102.4h716.8z m204.8-230.4v102.4H51.2v-102.4h921.6z m-204.8-230.4v102.4H51.2v-102.4h716.8zM972.8 102.4v102.4H51.2V102.4h921.6z\"></path></svg>'\n\n// 视频居中\nexport const VIDEO_ALIGN_CENTER_SVG =\n '<svg viewBox=\"0 0 1024 1024\"><path d=\"M870.4 793.6v102.4H153.6v-102.4h716.8z m102.4-230.4v102.4H51.2v-102.4h921.6z m-102.4-230.4v102.4H153.6v-102.4h716.8zM972.8 102.4v102.4H51.2V102.4h921.6z\"></path></svg>'\n\n// 视频右对齐\nexport const VIDEO_ALIGN_RIGHT_SVG =\n '<svg viewBox=\"0 0 1024 1024\"><path d=\"M972.8 793.6v102.4H256v-102.4h716.8z m0-230.4v102.4H51.2v-102.4h921.6z m0-230.4v102.4H256v-102.4h716.8zM972.8 102.4v102.4H51.2V102.4h921.6z\"></path></svg>'\n\n// // 垃圾桶(删除)\n// export const TRASH_SVG =\n// '<svg viewBox=\"0 0 1024 1024\"><path d=\"M826.8032 356.5312c-19.328 0-36.3776 15.6928-36.3776 35.0464v524.2624c0 19.328-16 34.56-35.328 34.56H264.9344c-19.328 0-35.5072-15.3088-35.5072-34.56V390.0416c0-19.328-14.1568-35.0464-33.5104-35.0464s-33.5104 15.6928-33.5104 35.0464V915.712c0 57.9328 44.6208 108.288 102.528 108.288H755.2c57.9328 0 108.0832-50.4576 108.0832-108.288V391.4752c-0.1024-19.2512-17.1264-34.944-36.48-34.944z\" p-id=\"9577\"></path><path d=\"M437.1712 775.7568V390.6048c0-19.328-14.1568-35.0464-33.5104-35.0464s-33.5104 15.616-33.5104 35.0464v385.152c0 19.328 14.1568 35.0464 33.5104 35.0464s33.5104-15.7184 33.5104-35.0464zM649.7024 775.7568V390.6048c0-19.328-17.0496-35.0464-36.3776-35.0464s-36.3776 15.616-36.3776 35.0464v385.152c0 19.328 17.0496 35.0464 36.3776 35.0464s36.3776-15.7184 36.3776-35.0464zM965.0432 217.0368h-174.6176V145.5104c0-57.9328-47.2064-101.76-104.6528-101.76h-350.976c-57.8304 0-105.3952 43.8528-105.3952 101.76v71.5264H54.784c-19.4304 0-35.0464 14.1568-35.0464 33.5104 0 19.328 15.616 33.5104 35.0464 33.5104h910.3616c19.328 0 35.0464-14.1568 35.0464-33.5104 0-19.3536-15.6928-33.5104-35.1488-33.5104z m-247.3728 0H297.3952V145.5104c0-19.328 18.2016-34.7648 37.4272-34.7648h350.976c19.1488 0 31.872 15.1296 31.872 34.7648v71.5264z\"></path></svg>'\n","/**\n * @description insert video\n * @author wangfupeng\n */\n\nimport { DomEditor, IDomEditor } from '@wangeditor-next/core'\nimport { Transforms } from 'slate'\n\nimport { replaceSymbols } from '../../utils/util'\nimport { VideoElement } from '../custom-types'\n\n/**\n * 插入视频\n * @param editor editor\n * @param src video src\n * @param poster video poster\n */\nexport default async function (\n editor: IDomEditor,\n src: string,\n poster = '',\n width = '',\n height = '',\n) {\n if (!src) { return }\n\n // 还原选区\n editor.restoreSelection()\n\n // 校验\n const { onInsertedVideo, checkVideo, parseVideoSrc } = editor.getMenuConfig('insertVideo')\n const checkRes = await checkVideo(src, poster)\n\n if (typeof checkRes === 'string') {\n // 校验失败,给出提示\n editor.alert(checkRes, 'error')\n return\n }\n if (checkRes == null) {\n // 校验失败,不给提示\n return\n }\n\n // 转换 src\n let parsedSrc = await parseVideoSrc(src)\n\n if (parsedSrc.trim().indexOf('<iframe ') !== 0) {\n parsedSrc = replaceSymbols(parsedSrc)\n }\n\n // 新建一个 video node\n const video: VideoElement = {\n type: 'video',\n src: parsedSrc,\n poster,\n align: 'center',\n children: [{ text: '' }],\n style: {\n width,\n height,\n },\n }\n\n // 插入视频\n // 不使用此方式会比正常的选区选取先执行\n Promise.resolve().then(() => {\n if (DomEditor.isSelectedEmptyParagraph(editor)) {\n Transforms.removeNodes(editor, { mode: 'highest' })\n }\n Transforms.insertNodes(editor, video, { mode: 'highest' })\n })\n\n // 调用 callback\n onInsertedVideo(video)\n}\n","/**\n * @description insert video menu\n * @author wangfupeng\n */\n\nimport {\n DomEditor,\n genModalButtonElems,\n genModalInputElems,\n IDomEditor,\n IModalMenu,\n t,\n} from '@wangeditor-next/core'\nimport { Node, Range } from 'slate'\n\nimport { VIDEO_SVG } from '../../constants/svg'\nimport $, { Dom7Array, DOMElement } from '../../utils/dom'\nimport { genRandomStr } from '../../utils/util'\nimport insertVideo from '../helper/insert-video'\n\n/**\n * 生成唯一的 DOM ID\n */\nfunction genDomID(): string {\n return genRandomStr('w-e-insert-video')\n}\n\nclass InsertVideoMenu implements IModalMenu {\n readonly title = t('videoModule.insertVideo')\n\n readonly iconSvg = VIDEO_SVG\n\n readonly tag = 'button'\n\n readonly showModal = true // 点击 button 时显示 modal\n\n readonly modalWidth = 320\n\n private $content: Dom7Array | null = null\n\n private readonly srcInputId = genDomID()\n\n private readonly posterInputId = genDomID()\n\n private readonly buttonId = genDomID()\n\n getValue(_editor: IDomEditor): string | boolean {\n // 插入菜单,不需要 value\n return ''\n }\n\n isActive(_editor: IDomEditor): boolean {\n // 任何时候,都不用激活 menu\n return false\n }\n\n exec(_editor: IDomEditor, _value: string | boolean) {\n // 点击菜单时,弹出 modal 之前,不需要执行其他代码\n // 此处空着即可\n }\n\n isDisabled(editor: IDomEditor): boolean {\n const { selection } = editor\n\n if (selection == null) { return true }\n if (!Range.isCollapsed(selection)) { return true } // 选区非折叠,禁用\n\n const selectedElems = DomEditor.getSelectedElems(editor)\n const hasVoidOrPre = selectedElems.some(elem => {\n const type = DomEditor.getNodeType(elem)\n\n if (type === 'pre') { return true }\n if (editor.isVoid(elem)) { return true }\n return false\n })\n\n if (hasVoidOrPre) { return true } // void 或 pre ,禁用\n\n return false\n }\n\n getModalPositionNode(_editor: IDomEditor): Node | null {\n return null // modal 依据选区定位\n }\n\n getModalContentElem(editor: IDomEditor): DOMElement {\n const { srcInputId, posterInputId, buttonId } = this\n\n // 获取 input button elem\n const [srcContainerElem, inputSrcElem] = genModalInputElems(\n t('videoModule.videoSrc'),\n srcInputId,\n t('videoModule.videoSrcPlaceHolder'),\n )\n const [posterContainerElem, inputPosterElem] = genModalInputElems(\n t('videoModule.videoPoster'),\n posterInputId,\n t('videoModule.videoPosterPlaceHolder'),\n )\n const $inputSrc = $(inputSrcElem)\n const $inputPoster = $(inputPosterElem)\n const [buttonContainerElem] = genModalButtonElems(buttonId, t('videoModule.ok'))\n\n if (this.$content == null) {\n // 第一次渲染\n const $content = $('<div></div>')\n\n // 绑定事件(第一次渲染时绑定,不要重复绑定)\n $content.on('click', `#${buttonId}`, async e => {\n e.preventDefault()\n const src = $content.find(`#${srcInputId}`).val().trim()\n const poster = $content.find(`#${posterInputId}`).val().trim()\n\n await insertVideo(editor, src, poster)\n editor.hidePanelOrModal() // 隐藏 modal\n })\n\n // 记录属性,重要\n this.$content = $content\n }\n\n const $content = this.$content\n\n $content.empty() // 先清空内容\n\n // append inputs and button\n $content.append(srcContainerElem)\n $content.append(posterContainerElem)\n $content.append(buttonContainerElem)\n\n // 设置 input val\n $inputSrc.val('')\n $inputPoster.val('')\n\n // focus 一个 input(异步,此时 DOM 尚未渲染)\n setTimeout(() => {\n $inputSrc.focus()\n })\n\n return $content[0]\n }\n}\n\nexport default InsertVideoMenu\n","/**\n * @description upload video\n * @author wangfupeng\n */\n\nimport {\n IDomEditor, IUploader,\n IUploadFile, IUploadResultFile,\n} from '@wangeditor-next/core'\nimport { createUploader } from '@wangeditor-next/core/upload'\n\nimport insertVideo from './insert-video'\n\nfunction getMenuConfig(editor: IDomEditor) {\n // 获取配置,见 `./config.js`\n return editor.getMenuConfig('uploadVideo')\n}\n\n// 存储 editor uploader 的关系 - 缓存 uploader ,不重复创建\nconst EDITOR_TO_UPLOADER_MAP = new WeakMap<IDomEditor, IUploader>()\n\n/**\n * 获取 uploader 实例(并通过 editor 缓存)\n * @param editor editor\n */\nfunction getUploader(editor: IDomEditor): IUploader {\n let uploader = EDITOR_TO_UPLOADER_MAP.get(editor)\n\n if (uploader != null) { return uploader }\n\n const menuConfig = getMenuConfig(editor)\n const {\n onSuccess, onProgress, onFailed, customInsert, onError,\n } = menuConfig\n\n // 上传完成之后\n const successHandler = (file: IUploadResultFile, res: any) => {\n // 预期 res 格式:\n // 成功:{ errno: 0, data: { url, poster } }\n // 失败:{ errno: !0, message: '失败信息' }\n\n if (customInsert) {\n // 用户自定义插入视频,此时 res 格式可能不符合预期\n customInsert(res, (src, poster) => insertVideo(editor, src, poster))\n // success 回调\n onSuccess(file, res)\n return\n }\n\n const { errno = 1, data = {} } = res\n\n if (errno !== 0) {\n // failed 回调\n onFailed(file, res)\n return\n }\n\n const { url = '', poster = '' } = data\n\n insertVideo(editor, url, poster)\n\n // success 回调\n onSuccess(file, res)\n }\n\n // progress 显示进度条\n const progressHandler = (progress: number) => {\n editor.showProgressBar(progress)\n\n // 回调函数\n if (onProgress) { onProgress(progress) }\n }\n\n // onError 提示错误\n const errorHandler = (file: any, err: any, res: any) => {\n onError(file, err, res)\n }\n\n uploader = createUploader({\n ...menuConfig,\n onProgress: progressHandler,\n onSuccess: successHandler,\n onError: errorHandler,\n }, editor)\n EDITOR_TO_UPLOADER_MAP.set(editor, uploader)\n\n return uploader\n}\n\n/**\n * 上传视频文件\n * @param editor editor\n * @param file file\n */\nasync function uploadFile(editor: IDomEditor, files: File[]) {\n const uploader = getUploader(editor)\n const uploadList: IUploadFile[] = files.map(file => ({\n name: file.name,\n type: file.type,\n size: file.size,\n data: file,\n }))\n\n uploader.addFiles(uploadList)\n await uploader.upload()\n}\n\nexport default async function (editor: IDomEditor, files: FileList | null) {\n if (files == null) { return }\n const fileList = Array.prototype.slice.call(files)\n\n const uploadFileList : File[] = []\n // 获取菜单配置\n const { customUpload } = getMenuConfig(editor)\n\n // 按顺序上传\n for await (const file of fileList) {\n // 上传\n if (customUpload) {\n // 自定义上传\n await customUpload(file, (src, poster) => insertVideo(editor, src, poster), editor)\n } else {\n uploadFileList.push(file)\n }\n }\n // 默认上传\n if (uploadFileList.length > 0) { await uploadFile(editor, uploadFileList) }\n}\n","/**\n * @description upload video menu\n * @author wangfupeng\n */\n\nimport {\n DomEditor, IButtonMenu, IDomEditor, t,\n} from '@wangeditor-next/core'\nimport { Range } from 'slate'\n\nimport { UPLOAD_VIDEO_SVG } from '../../constants/svg'\nimport $ from '../../utils/dom'\nimport insertVideo from '../helper/insert-video'\nimport uploadVideos from '../helper/upload-videos'\n\nclass UploadVideoMenu implements IButtonMenu {\n readonly title = t('videoModule.uploadVideo')\n\n readonly iconSvg = UPLOAD_VIDEO_SVG\n\n readonly tag = 'button'\n\n getValue(_editor: IDomEditor): string | boolean {\n // 无需获取 val\n return ''\n }\n\n isActive(_editor: IDomEditor): boolean {\n // 任何时候,都不用激活 menu\n return false\n }\n\n exec(editor: IDomEditor, _value: string | boolean) {\n const { allowedFileTypes = [], customBrowseAndUpload } = this.getMenuConfig(editor)\n\n // 自定义选择图片,并上传,如图床\n if (customBrowseAndUpload) {\n customBrowseAndUpload((src, poster) => insertVideo(editor, src, poster))\n return\n }\n\n // 设置选择文件的类型\n let acceptAttr = ''\n\n if (allowedFileTypes.length > 0) {\n acceptAttr = `accept=\"${allowedFileTypes.join(', ')}\"`\n }\n\n // 添加 file input(每次重新创建 input)\n const $body = $('body')\n const $inputFile = $(`<input type=\"file\" ${acceptAttr} multiple/>`)\n\n $inputFile.hide()\n $body.append($inputFile)\n $inputFile.click()\n // 选中文件\n $inputFile.on('change', () => {\n const files = ($inputFile[0] as HTMLInputElement).files\n\n uploadVideos(editor, files) // 上传文件\n })\n }\n\n isDisabled(editor: IDomEditor): boolean {\n const { selection } = editor\n\n if (selection == null) { return true }\n if (!Range.isCollapsed(selection)) { return true } // 选区非折叠,禁用\n\n const selectedElems = DomEditor.getSelectedElems(editor)\n const hasVoidOrPre = selectedElems.some(elem => {\n const type = DomEditor.getNodeType(elem)\n\n if (type === 'pre') { return true }\n if (editor.isVoid(elem)) { return true }\n return false\n })\n\n if (hasVoidOrPre) { return true } // void 或 pre ,禁用\n\n return false\n }\n\n private getMenuConfig(editor: IDomEditor) {\n // 获取配置,见 `./config.js`\n return editor.getMenuConfig('uploadVideo')\n }\n}\n\nexport default UploadVideoMenu\n","/**\n * @description align video menu\n */\n\nimport { DomEditor, IButtonMenu, IDomEditor, t } from '@wangeditor-next/core'\nimport { Transforms } from 'slate'\n\nimport { getVideoAlign } from '../alignment'\nimport { VideoAlign, VideoElement } from '../custom-types'\n\nclass VideoAlignMenu implements IButtonMenu {\n readonly tag = 'button'\n\n readonly title: string\n\n constructor(\n readonly align: VideoAlign,\n titleKey: string,\n readonly iconSvg: string\n ) {\n this.title = t(titleKey)\n }\n\n private getSelectedVideo(editor: IDomEditor): VideoElement | null {\n return DomEditor.getSelectedNodeByType(editor, 'video') as VideoElement | null\n }\n\n getValue(editor: IDomEditor): string | boolean {\n const video = this.getSelectedVideo(editor)\n\n return video ? getVideoAlign(video) : false\n }\n\n isActive(editor: IDomEditor): boolean {\n return this.getValue(editor) === this.align\n }\n\n isDisabled(editor: IDomEditor): boolean {\n if (editor.selection == null) {\n return true\n }\n return this.getSelectedVideo(editor) == null\n }\n\n exec(editor: IDomEditor, _value: string | boolean): void {\n if (this.isDisabled(editor)) {\n return\n }\n\n const props: Partial<VideoElement> = { align: this.align }\n\n Transforms.setNodes(editor, props, {\n match: node => DomEditor.checkNodeType(node, 'video'),\n })\n }\n}\n\nexport default VideoAlignMenu\n","/**\n * @description parse html\n * @author wangfupeng\n */\n\nimport { IDomEditor } from '@wangeditor-next/core'\nimport { Descendant } from 'slate'\n\nimport $, { Dom7Array, DOMElement } from '../utils/dom'\nimport { styleStringToObject } from '../utils/util'\nimport { normalizeVideoAlign } from './alignment'\nimport { VideoAlign, VideoElement, videoStyle } from './custom-types'\n\nfunction genVideoElem(\n src: string,\n poster = '',\n width = 'auto',\n height = 'auto',\n style: videoStyle = {},\n align: VideoAlign = 'center',\n): VideoElement {\n return {\n type: 'video',\n src,\n poster,\n width,\n height,\n style,\n children: [{ text: '' }], // void 元素有一个空 text\n align,\n }\n}\n\nfunction getClassAlign($elem: Dom7Array): string {\n const classAttr = $elem.attr('class') || ''\n const classList = classAttr.trim().split(/\\s+/).filter(Boolean)\n\n for (let i = 0; i < classList.length; i += 1) {\n const className = classList[i]\n\n if (className.startsWith('w-e-video-align-')) {\n return className.replace('w-e-video-align-', '')\n }\n }\n\n return ''\n}\n\nfunction getVideoAlign($elem: Dom7Array): VideoAlign {\n const dataAlign = ($elem.attr('data-w-e-align') || '').trim()\n\n if (dataAlign) { return normalizeVideoAlign(dataAlign) }\n\n const containerStyle = styleStringToObject($elem.attr('style') || '')\n const justifyContent = containerStyle['justify-content']\n\n if (justifyContent === 'flex-start') { return 'left' }\n if (justifyContent === 'flex-end') { return 'right' }\n if (justifyContent === 'center') { return 'center' }\n\n const classAlign = getClassAlign($elem)\n\n if (classAlign) { return normalizeVideoAlign(classAlign) }\n\n // Import-only adapters for HTML generated by the previous text-alignment model.\n const legacyStyleAlign = containerStyle['text-align']\n const legacyDataAlign = ($elem.attr('data-w-e-text-align') || '').trim()\n\n return normalizeVideoAlign(legacyStyleAlign || legacyDataAlign)\n}\n\nfunction getVideoSizeStyle(styleStr: string): videoStyle {\n const parsedStyle = styleStringToObject(styleStr) as Record<string, string>\n const style: videoStyle = {}\n\n if (parsedStyle.width) { style.width = parsedStyle.width }\n if (parsedStyle.height) { style.height = parsedStyle.height }\n\n return style\n}\n\nfunction parseHtml(elem: DOMElement, _children: Descendant[], _editor: IDomEditor): VideoElement {\n const $elem = $(elem)\n let src = ''\n let poster = ''\n let width = 'auto'\n let height = 'auto'\n let style: videoStyle = {}\n let align: VideoAlign = 'center'\n // <iframe> 形式\n const $iframe = $elem.find('iframe')\n\n if ($iframe.length > 0) {\n width = $iframe.attr('width') || 'auto'\n height = $iframe.attr('height') || 'auto'\n const iframeStyleStr = $iframe.attr('style') || ''\n\n style = getVideoSizeStyle(iframeStyleStr)\n const iframeStyleWidth = $iframe.attr('data-w-e-style-width') || ''\n const iframeStyleHeight = $iframe.attr('data-w-e-style-height') || ''\n\n if (!style.width && iframeStyleWidth) { style.width = iframeStyleWidth }\n if (!style.height && iframeStyleHeight) { style.height = iframeStyleHeight }\n src = $iframe[0].outerHTML\n align = getVideoAlign($elem)\n return genVideoElem(src, poster, width, height, style, align)\n }\n\n // <video> 形式\n const $video = $elem.find('video')\n\n src = $video.attr('src') || ''\n if (!src) {\n if ($video.length > 0) {\n const $source = $video.find('source')\n\n src = $source.attr('src') || ''\n }\n }\n width = $video.attr('width') || 'auto'\n height = $video.attr('height') || 'auto'\n poster = $video.attr('poster') || ''\n const videoStyleStr = $video.attr('style') || ''\n\n style = getVideoSizeStyle(videoStyleStr)\n const videoStyleWidth = $video.attr('data-w-e-style-width') || ''\n const videoStyleHeight = $video.attr('data-w-e-style-height') || ''\n\n if (!style.width && videoStyleWidth) { style.width = videoStyleWidth }\n if (!style.height && videoStyleHeight) { style.height = videoStyleHeight }\n align = getVideoAlign($elem)\n return genVideoElem(src, poster, width, height, style, align)\n}\n\nexport const parseHtmlConf = {\n selector: 'figure[data-w-e-type=\"video\"],div[data-w-e-type=\"video\"]',\n parseElemHtml: parseHtml,\n}\n","/**\n * @description video render elem\n * @author wangfupeng\n */\n\nimport { DomEditor, IDomEditor } from '@wangeditor-next/core'\nimport { Element } from 'slate'\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport { h, jsx, VNode } from 'snabbdom'\n\nimport { genSizeStyledIframeHtml } from '../utils/dom'\nimport { getVideoAlign, getVideoAlignClass } from './alignment'\nimport { VideoElement } from './custom-types'\n\nfunction renderVideo(elemNode: Element, children: VNode[] | null, editor: IDomEditor): VNode {\n const {\n src = '',\n poster = '',\n key = '',\n width = 'auto',\n height = 'auto',\n style = {},\n } = elemNode as VideoElement\n const align = getVideoAlign(elemNode)\n const containerClassName = [\n 'w-e-video',\n 'w-e-textarea-video-container',\n getVideoAlignClass(align),\n ].join(' ')\n\n // 是否选中\n const selected = DomEditor.isNodeSelected(editor, elemNode)\n\n let vnode: VNode\n\n if (src.trim().indexOf('<iframe ') === 0) {\n // 增加尺寸样式\n const iframeHtml = genSizeStyledIframeHtml(src, width, height, style)\n\n // iframe 形式,第三方视频\n vnode = (\n <figure\n className={containerClassName}\n data-selected={selected ? 'true' : ''} // 标记为 选中\n data-w-e-align={align}\n innerHTML={iframeHtml} // 内嵌第三方 iframe 视频\n ></figure>\n )\n } else {\n // 其他,mp4 格式\n const videoVnode = (\n <video key={key} poster={poster} controls style={style}>\n <source src={src} type=\"video/mp4\" />\n {'Sorry, your browser doesn\\'t support embedded videos.\\n 抱歉,浏览器不支持 video 视频'}\n </video>\n )\n // @ts-ignore 添加尺寸\n\n if (width !== 'auto') { videoVnode.data.width = width }\n // @ts-ignore\n if (height !== 'auto') { videoVnode.data.height = height }\n\n vnode = (\n <figure\n className={containerClassName}\n data-selected={selected ? 'true' : ''} // 标记为 选中\n data-w-e-align={align}\n >\n {videoVnode}\n </figure>\n )\n }\n\n // 【注意】void node 中,renderElem 不用处理 children 。core 会统一处理。\n\n const containerVnode = h(\n 'div',\n {\n props: {\n contentEditable: false,\n },\n on: {\n mousedown: e => e.preventDefault(),\n },\n },\n vnode,\n )\n\n return containerVnode\n}\n\nconst renderVideoConf = {\n type: 'video', // 和 elemNode.type 一致\n renderElem: renderVideo,\n}\n\nexport { renderVideoConf }\n","/**\n * @description video module\n * @author wangfupeng\n */\n\nimport { IModuleConf } from '@wangeditor-next/core'\n\nimport { videoToHtmlConf } from './elem-to-html'\nimport {\n editorVideoSizeMenuConf,\n editorVideoSrcMenuConf,\n insertVideoMenuConf,\n uploadVideoMenuConf,\n videoAlignCenterMenuConf,\n videoAlignLeftMenuConf,\n videoAlignRightMenuConf,\n} from './menu/index'\nimport { parseHtmlConf } from './parse-elem-html'\nimport withVideo from './plugin'\nimport { preParseHtmlConf } from './pre-parse-html'\nimport { renderVideoConf } from './render-elem'\n\nconst video: Partial<IModuleConf> = {\n renderElems: [renderVideoConf],\n elemsToHtml: [videoToHtmlConf],\n preParseHtml: [preParseHtmlConf],\n parseElemsHtml: [parseHtmlConf],\n menus: [\n insertVideoMenuConf,\n uploadVideoMenuConf,\n editorVideoSizeMenuConf,\n editorVideoSrcMenuConf,\n videoAlignLeftMenuConf,\n videoAlignCenterMenuConf,\n videoAlignRightMenuConf,\n ],\n editorPlugin: withVideo,\n}\n\nexport default video\n","/**\n * @description pre parse html\n * @author wangfupeng\n */\n\nimport $, { DOMElement, getTagName } from '../utils/dom'\n\n/**\n * pre-prase video ,兼容 V4\n * @param elem elem\n */\nfunction preParse(elem: DOMElement): DOMElement {\n const $elem = $(elem)\n let $video = $elem\n\n const elemTagName = getTagName($elem)\n\n if (elemTagName === 'p') {\n // v4 的 video 或 iframe 是被 p 包裹的\n const children = $elem.children()\n\n if (children.length === 1) {\n const firstChild = children[0]\n const firstChildTagName = firstChild.tagName.toLowerCase()\n\n if (['iframe', 'video'].includes(firstChildTagName)) {\n // p 下面包含 iframe 或 video\n $video = $(firstChild)\n }\n }\n }\n\n const videoTagName = getTagName($video)\n\n if (videoTagName !== 'iframe' && videoTagName !== 'video') { return $video[0] }\n\n // 已经符合 V5 格式\n const $parent = $video.parent()\n\n if ($parent.attr('data-w-e-type') === 'video') { return $video[0] }\n\n const $container = $(\n '<figure data-w-e-type=\"video\" data-w-e-is-void data-w-e-align=\"center\" class=\"w-e-video w-e-video-align-center\"></figure>',\n )\n\n $container.append($video)\n\n return $container[0]\n}\n\nexport const preParseHtmlConf = {\n selector: 'iframe,video,p',\n preParseHtml: preParse,\n}\n","/**\n * @description video menu\n * @author wangfupeng\n */\n\nimport {\n VIDEO_ALIGN_CENTER_SVG,\n VIDEO_ALIGN_LEFT_SVG,\n VIDEO_ALIGN_RIGHT_SVG,\n} from '../../constants/svg'\nimport { genInsertVideoMenuConfig, genUploadVideoMenuConfig } from './config'\nimport EditorVideoSizeMenu from './EditVideoSizeMenu'\nimport EditorVideoSrcMenu from './EditVideoSrcMenu'\nimport InsertVideoMenu from './InsertVideoMenu'\n// import DeleteVideoMenu from './DeleteVideoMenu'\nimport UploadVideoMenu from './UploadVideoMenu'\nimport VideoAlignMenu from './VideoAlignMenu'\n\nexport const insertVideoMenuConf = {\n key: 'insertVideo',\n factory() {\n return new InsertVideoMenu()\n },\n\n // 默认的菜单菜单配置,将存储在 editorConfig.MENU_CONF[key] 中\n // 创建编辑器时,可通过 editorConfig.MENU_CONF[key] = {...} 来修改\n config: genInsertVideoMenuConfig(),\n}\n\nexport const uploadVideoMenuConf = {\n key: 'uploadVideo',\n factory() {\n return new UploadVideoMenu()\n },\n\n // 默认的菜单菜单配置,将存储在 editorConfig.MENU_CONF[key] 中\n // 创建编辑器时,可通过 editorConfig.MENU_CONF[key] = {...} 来修改\n config: genUploadVideoMenuConfig(),\n}\n\nexport const editorVideoSizeMenuConf = {\n key: 'editVideoSize',\n factory() {\n return new EditorVideoSizeMenu()\n },\n}\n\nexport const editorVideoSrcMenuConf = {\n key: 'editVideoSrc',\n factory() {\n return new EditorVideoSrcMenu()\n },\n}\n\nexport const videoAlignLeftMenuConf = {\n key: 'videoAlignLeft',\n factory() {\n return new VideoAlignMenu('left', 'videoModule.alignLeft', VIDEO_ALIGN_LEFT_SVG)\n },\n}\n\nexport const videoAlignCenterMenuConf = {\n key: 'videoAlignCenter',\n factory() {\n return new VideoAlignMenu('center', 'videoModule.alignCenter', VIDEO_ALIGN_CENTER_SVG)\n },\n}\n\nexport const videoAlignRightMenuConf = {\n key: 'videoAlignRight',\n factory() {\n return new VideoAlignMenu('right', 'videoModule.alignRight', VIDEO_ALIGN_RIGHT_SVG)\n },\n}\n\n// export const deleteVideoMenuConf = {\n// key: 'deleteVideo',\n// factory() {\n// return new DeleteVideoMenu()\n// },\n// }\n// 键盘能删除 video 了,注释掉这个菜单 wangfupeng 22.02.23\n","/**\n * @description video menu config\n * @author wangfupeng\n */\n\nimport { IUploadVideoConfig } from '@wangeditor-next/core'\n\nimport { VideoElement } from '../custom-types'\n\nexport function genUploadVideoMenuConfig(): IUploadVideoConfig {\n return {\n server: '', // server API 地址,需用户配置\n\n fieldName: 'wangeditor-uploaded-video', // formData 中,文件的 key\n maxFileSize: 10 * 1024 * 1024, // 10M\n maxNumberOfFiles: 5, // 最多上传 xx 个视频\n allowedFileTypes: ['video/*'],\n meta: {\n // 自定义上传参数,例如传递验证的 token 等。参数会被添加到 formData 中,一起上传到服务端。\n // 例如:token: 'xxxxx', x: 100\n },\n metaWithUrl: false,\n // headers: {\n // // 自定义 http headers\n // // 例如:Accept: 'text/x-json', a: 100,\n // },\n withCredentials: false,\n timeout: 30 * 1000, // 30s\n\n onBeforeUpload: (files: any) => files, // 返回 false 则终止上传\n onProgress: (_progress: number) => {\n /* on progress */\n },\n onSuccess: (_file: any, _res: any) => {\n /* on success */\n },\n onFailed: (file: any, res: any) => {\n /* on failed */\n console.error(`'${file.name}' upload failed`, res)\n },\n onError: (file: any, err: any, res: any) => {\n /* on error */\n /* on timeout */\n console.error(`'${file.name} upload error`, err, res)\n },\n\n // 自定义插入视频,用户配置\n // customInsert: (res, insertFn) => {},\n\n // 自定义上传视频,用户配置\n // customUpload: (file, insertFn) => {},\n\n // 自定义上传适配器,默认仍使用内置 Uppy\n // uploadAdapter: ({ config, editor }) => ({ addFiles() {}, upload: async () => {} }),\n\n // 自定义选择,并上传视频,如:图床 (用户配置)\n // customBrowseAndUpload: insertFn => {},\n }\n}\n\n/**\n * 生成插入网络视频的配置\n */\nexport function genInsertVideoMenuConfig() {\n return {\n onInsertedVideo(_node: VideoElement) {\n // 插入视频之后的 callback\n },\n\n /**\n * 检查 video ,支持 async\n * @param src src\n * @param poster poster\n */\n checkVideo(_src: string, _poster: string): boolean | string | undefined {\n // 1. 返回 true ,说明检查通过\n // 2. 返回一个字符串,说明检查未通过,编辑器会阻止插入。会 alert 出错误信息(即返回的字符串)\n // 3. 返回 undefined(即没有任何返回),说明检查未通过,编辑器会阻止插入\n return true\n },\n\n /**\n * 转换 video src\n * @param src src\n * @returns new src\n */\n parseVideoSrc(src: string): string {\n return src\n },\n }\n}\n","/**\n * @description editor 插件,重写 editor API\n * @author wangfupeng\n */\n\nimport { DomEditor, IDomEditor } from '@wangeditor-next/core'\nimport { Transforms } from 'slate'\n\nimport { CustomElement } from '../../../custom-types'\n\nfunction withVideo<T extends IDomEditor>(editor: T): T {\n const { isVoid, normalizeNode } = editor\n const newEditor = editor\n\n // 重写 isVoid\n newEditor.isVoid = (elem: CustomElement) => {\n const { type } = elem\n\n if (type === 'video') {\n return true\n }\n\n return isVoid(elem)\n }\n\n // 重写 normalizeNode\n newEditor.normalizeNode = ([node, path]) => {\n const type = DomEditor.getNodeType(node)\n\n // ----------------- video 后面必须跟一个 p header blockquote -----------------\n if (type === 'video') {\n // -------------- video 是 editor 最后一个节点,需要后面插入 p --------------\n const isLast = DomEditor.isLastNode(newEditor, node)\n\n if (isLast) {\n Transforms.insertNodes(newEditor, DomEditor.genEmptyParagraph(), { at: [path[0] + 1] })\n }\n }\n\n // 执行默认的 normalizeNode ,重要!!!\n return normalizeNode([node, path])\n }\n\n // 返回 editor ,重要!\n return newEditor\n}\n\nexport default withVideo\n"],"names":["getTagName","$elem","length","tagName","toLowerCase","genSizeStyledIframeHtml","iframeHtml","width","height","style","classMode","$iframe","$","_a","styleWidth","_b","styleHeight","widthData","concat","heightData","attr","removeAttr","styleStr","outerHTML","i18nAddResources","videoModule","delete","uploadVideo","insertVideo","videoSrc","videoSrcPlaceHolder","videoPoster","videoPosterPlaceHolder","ok","editSize","edit","alignLeft","alignCenter","alignRight","append","fn","on","focus","val","html","parent","hasClass","empty","DEFAULT_VIDEO_ALIGN","VIDEO_ALIGNS","normalizeVideoAlign","value","align","trim","includes","getVideoAlign","elemNode","textAlign","getVideoAlignClass","videoToHtmlConf","type","elemToHtml","_childrenHtml","editor","src","_c","poster","_d","_e","_f","mode","getTextStyleMode","alignData","containerAttrs","getVideoJustifyContent","res","indexOf","_g","_h","genRandomStr","prefix","nanoid","styleStringToObject","styleString","styleObject","split","forEach","__read","property","genDomID","EditorVideoSizeMenu","this","title","t","tag","showModal","modalWidth","$content","widthInputId","heightInputId","buttonId","prototype","getSelectedVideoNode","DomEditor","getSelectedNodeByType","getValue","_editor","isActive","exec","_value","isDisabled","selection","getModalPositionNode","getModalContentElem","genModalInputElems","widthContainerElem","inputWidthElem","$inputWidth","heightContainerElem","inputHeightElem","$inputHeight","buttonContainerElem","genModalButtonElems","videoNode","$content_1","e","preventDefault","rawWidth","find","rawHeight","isPercentage","test","isNumeric","parseInt","restoreSelection","props","__assign","Transforms","setNodes","match","n","checkNodeType","hidePanelOrModal","setTimeout","Editvideo","iconSvg","srcInputId","posterInputId","_this","srcContainerElem","inputSrcElem","posterContainerElem","inputPosterElem","$inputSrc","$inputPoster","__awaiter","videoId","key","editor_1","src_1","arguments","getMenuConfig","onInsertedVideo","checkVideo","parseVideoSrc","checkRes","sent","alert","parsedSrc","replace","video","children","text","Promise","resolve","then","isSelectedEmptyParagraph","removeNodes","insertNodes","InsertVideoMenu","Range","isCollapsed","getSelectedElems","some","elem","getNodeType","isVoid","EDITOR_TO_UPLOADER_MAP","WeakMap","uploadFile","files","uploader","get","menuConfig","onSuccess","onProgress","onFailed","customInsert","onError","createUploader","progress","showProgressBar","file","errno","data","url","err","set","getUploader","uploadList","map","name","size","addFiles","upload","UploadVideoMenu","allowedFileTypes","customBrowseAndUpload","acceptAttr","join","$body","$inputFile","hide","click","fileList","Array","slice","call","uploadFileList","customUpload","fileList_1","__asyncValues","fileList_1_1","push","uploadVideos","VideoAlignMenu","titleKey","getSelectedVideo","node","genVideoElem","dataAlign","containerStyle","justifyContent","classAlign","classList","filter","Boolean","i","className","startsWith","getClassAlign","legacyStyleAlign","legacyDataAlign","getVideoSizeStyle","parsedStyle","renderElems","renderElem","vnode","containerClassName","selected","isNodeSelected","jsx","innerHTML","videoVnode","controls","h","contentEditable","mousedown","elemsToHtml","preParseHtml","selector","$video","firstChild","firstChildTagName","videoTagName","$container","parseElemsHtml","parseElemHtml","_children","iframeStyleWidth","iframeStyleHeight","videoStyleWidth","videoStyleHeight","menus","factory","config","_node","_src","_poster","server","fieldName","maxFileSize","maxNumberOfFiles","meta","metaWithUrl","withCredentials","timeout","onBeforeUpload","_progress","_file","_res","console","error","EditorVideoSrcMenu","editorPlugin","normalizeNode","newEditor","path","isLastNode","genEmptyParagraph","at"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/utils/dom.ts","../src/locale/index.ts","../src/locale/en.ts","../src/locale/zh-CN.ts","../src/module/alignment.ts","../src/module/elem-to-html.ts","../src/utils/util.ts","../src/module/menu/EditVideoSizeMenu.ts","../src/module/menu/EditVideoSrcMenu.ts","../src/constants/svg.ts","../src/module/helper/insert-video.ts","../src/module/menu/InsertVideoMenu.ts","../src/module/helper/upload-videos.ts","../src/module/menu/UploadVideoMenu.ts","../src/module/menu/VideoAlignMenu.ts","../src/module/parse-elem-html.ts","../src/module/render-elem.tsx","../src/module/index.ts","../src/module/pre-parse-html.ts","../src/module/menu/index.ts","../src/module/menu/config.ts","../src/module/plugin.ts"],"sourcesContent":["/**\n * @description DOM 操作\n * @author wangfupeng\n */\n\nimport $, {\n append, attr, Dom7Array, empty, focus, hasClass, html, on, parent, val,\n} from 'dom7'\n\nimport { videoStyle } from '../module/custom-types'\n\n// COMPAT: This is required to prevent TypeScript aliases from doing some very\n// weird things for Slate's types with the same name as globals. (2019/11/27)\n// https://github.com/microsoft/TypeScript/issues/35002\nimport DOMNode = globalThis.Node\nimport DOMComment = globalThis.Comment\nimport DOMElement = globalThis.Element\nimport DOMText = globalThis.Text\nimport DOMRange = globalThis.Range\nimport DOMSelection = globalThis.Selection\nimport DOMStaticRange = globalThis.StaticRange\n\nexport type { Dom7Array } from 'dom7'\n\nif (append) { $.fn.append = append }\nif (on) { $.fn.on = on }\nif (focus) { $.fn.focus = focus }\nif (attr) { $.fn.attr = attr }\nif (val) { $.fn.val = val }\nif (html) { $.fn.html = html }\nif (parent) { $.fn.parent = parent }\nif (hasClass) { $.fn.hasClass = hasClass }\nif (empty) { $.fn.empty = empty }\n\nexport default $\n\n/**\n * 获取 tagName lower-case\n * @param $elem $elem\n */\nexport function getTagName($elem: Dom7Array): string {\n if ($elem.length) { return $elem[0].tagName.toLowerCase() }\n return ''\n}\n\n/**\n * 生成带 size 样式的 iframe html\n * @param iframeHtml iframe html string\n * @param width width\n * @param height height\n * @returns iframe html string with size style\n */\nexport function genSizeStyledIframeHtml(\n iframeHtml: string,\n width = 'auto',\n height = 'auto',\n style: videoStyle = {},\n classMode = false,\n): string {\n const $iframe = $(iframeHtml)\n const { width: styleWidth = '', height: styleHeight = '' } = style\n const widthData = styleWidth ? `data-w-e-style-width=\"${styleWidth}\"` : ''\n const heightData = styleHeight ? `data-w-e-style-height=\"${styleHeight}\"` : ''\n\n $iframe.attr('width', width)\n $iframe.attr('height', height)\n\n if (!classMode) {\n let styleStr = 'display: block; max-width: 100%;'\n\n if (styleWidth) { styleStr += ` width: ${styleWidth};` }\n if (styleHeight) { styleStr += ` height: ${styleHeight};` }\n $iframe.attr('style', styleStr)\n } else {\n if (widthData) { $iframe.attr('data-w-e-style-width', styleWidth) }\n if (heightData) { $iframe.attr('data-w-e-style-height', styleHeight) }\n $iframe.removeAttr('style')\n }\n return $iframe[0].outerHTML\n}\nexport {\n DOMComment, DOMElement, DOMNode, DOMRange, DOMSelection, DOMStaticRange, DOMText,\n}\n","/**\n * @description i18n entry\n * @author wangfupeng\n */\n\nimport { i18nAddResources } from '@wangeditor-next/core'\n\nimport enResources from './en'\nimport zhResources from './zh-CN'\n\ni18nAddResources('en', enResources)\ni18nAddResources('zh-CN', zhResources)\n","/**\n * @description i18n en\n * @author wangfupeng\n */\n\nexport default {\n videoModule: {\n delete: 'Delete',\n uploadVideo: 'Upload video',\n insertVideo: 'Insert video',\n videoSrc: 'Video source',\n videoSrcPlaceHolder: 'Video file url, or third-party <iframe>',\n videoPoster: 'Video poster',\n videoPosterPlaceHolder: 'Poster image url',\n ok: 'Ok',\n editSize: 'Edit size',\n edit: 'Edit video',\n width: 'Width',\n height: 'Height',\n alignLeft: 'Align video left',\n alignCenter: 'Center video',\n alignRight: 'Align video right',\n },\n}\n","/**\n * @description i18n zh-CN\n * @author wangfupeng\n */\n\nexport default {\n videoModule: {\n delete: '删除视频',\n uploadVideo: '上传视频',\n insertVideo: '插入视频',\n videoSrc: '视频地址',\n videoSrcPlaceHolder: '视频文件 url 或第三方 <iframe>',\n videoPoster: '视频封面',\n videoPosterPlaceHolder: '封面图片 url',\n ok: '确定',\n editSize: '修改尺寸',\n edit: '编辑视频',\n width: '宽度',\n height: '高度',\n alignLeft: '视频左对齐',\n alignCenter: '视频居中',\n alignRight: '视频右对齐',\n },\n}\n","/**\n * @description video alignment helpers\n */\n\nimport { Element } from 'slate'\n\nimport { VideoAlign, VideoElement } from './custom-types'\n\nexport const DEFAULT_VIDEO_ALIGN: VideoAlign = 'center'\n\nconst VIDEO_ALIGNS: VideoAlign[] = ['left', 'center', 'right']\n\nexport function normalizeVideoAlign(value: unknown): VideoAlign {\n if (typeof value !== 'string') {\n return DEFAULT_VIDEO_ALIGN\n }\n\n const align = value.trim().toLowerCase() as VideoAlign\n\n return VIDEO_ALIGNS.includes(align) ? align : DEFAULT_VIDEO_ALIGN\n}\n\nexport function getVideoAlign(elemNode: Element): VideoAlign {\n const { align } = elemNode as VideoElement\n\n if (align) {\n return normalizeVideoAlign(align)\n }\n\n // Import-only adapter for content created before video alignment became media-specific.\n const { textAlign } = elemNode as Element & { textAlign?: unknown }\n\n return normalizeVideoAlign(textAlign)\n}\n\nexport function getVideoAlignClass(align: VideoAlign): string {\n return `w-e-video-align-${align}`\n}\n\nexport function getVideoJustifyContent(align: VideoAlign): string {\n if (align === 'left') {\n return 'flex-start'\n }\n if (align === 'right') {\n return 'flex-end'\n }\n return 'center'\n}\n","/**\n * @description to html\n * @author wangfupeng\n */\n\nimport { getTextStyleMode, IDomEditor } from '@wangeditor-next/core'\nimport { Element } from 'slate'\n\nimport { genSizeStyledIframeHtml } from '../utils/dom'\nimport { getVideoAlign, getVideoAlignClass, getVideoJustifyContent } from './alignment'\nimport { VideoElement } from './custom-types'\n\nfunction videoToHtml(elemNode: Element, _childrenHtml?: string, editor?: IDomEditor): string {\n const {\n src = '',\n poster = '',\n width = 'auto',\n height = 'auto',\n style = {},\n } = elemNode as VideoElement\n const mode = getTextStyleMode(editor)\n const align = getVideoAlign(elemNode)\n const alignData = ` data-w-e-align=\"${align}\"`\n const containerAttrs = mode === 'class'\n ? `${alignData} class=\"w-e-video ${getVideoAlignClass(align)}\"`\n : `${alignData} style=\"display: flex; justify-content: ${getVideoJustifyContent(align)}; margin: 0; max-width: 100%; width: 100%;\"`\n let res = `<figure data-w-e-type=\"video\" data-w-e-is-void${containerAttrs}>\\n`\n\n if (src.trim().indexOf('<iframe ') === 0) {\n // iframe 形式\n const iframeHtml = genSizeStyledIframeHtml(src, width, height, style, mode === 'class')\n\n res += iframeHtml\n } else {\n // 其他,mp4 等 url 格式\n const { width: styleWidth = '', height: styleHeight = '' } = style\n\n if (mode === 'class') {\n const widthData = styleWidth ? ` data-w-e-style-width=\"${styleWidth}\"` : ''\n const heightData = styleHeight ? ` data-w-e-style-height=\"${styleHeight}\"` : ''\n\n res += `<video poster=\"${poster}\" controls=\"true\" width=\"${width}\" height=\"${height}\"${widthData}${heightData}><source src=\"${src}\" type=\"video/mp4\"/></video>`\n } else {\n let styleStr = 'display: block; max-width: 100%;'\n\n if (styleWidth) { styleStr += ` width: ${styleWidth};` }\n if (styleHeight) { styleStr += ` height: ${styleHeight};` }\n res += `<video poster=\"${poster}\" controls=\"true\" width=\"${width}\" height=\"${height}\" style=\"${styleStr}\"><source src=\"${src}\" type=\"video/mp4\"/></video>`\n }\n }\n res += '\\n</figure>'\n\n return res\n}\n\nexport const videoToHtmlConf = {\n type: 'video',\n elemToHtml: videoToHtml,\n}\n","/**\n * @description 工具函数\n * @author wangfupeng\n */\n\nimport { nanoid } from 'nanoid'\n\n/**\n * 获取随机数字符串\n * @param prefix 前缀\n * @returns 随机数字符串\n */\nexport function genRandomStr(prefix = 'r'): string {\n return `${prefix}-${nanoid()}`\n}\n\nexport function replaceSymbols(str: string) {\n return str.replace(/</g, '&lt;').replace(/>/g, '&gt;')\n}\n\nexport function styleStringToObject(styleString) {\n const styleObject = {}\n\n // 去掉字符串两端的空格,然后按分号分割\n const styles = styleString.trim().split(';')\n\n // 迭代每一个样式属性对\n styles.forEach(style => {\n if (style) {\n // 忽略空字符串\n const [property, value] = style.split(':')\n\n if (property && value) {\n // 去掉两端的空格并将结果存储在对象中\n styleObject[property.trim()] = value.trim()\n }\n }\n })\n\n return styleObject\n}\n","/**\n * @description 修改视频尺寸\n * @author wangfupeng\n */\n\nimport {\n DomEditor,\n genModalButtonElems,\n genModalInputElems,\n IDomEditor,\n IModalMenu,\n t,\n} from '@wangeditor-next/core'\nimport { Node as SlateNode, Transforms } from 'slate'\n\nimport $, { Dom7Array, DOMElement } from '../../utils/dom'\nimport { genRandomStr } from '../../utils/util'\nimport { VideoElement } from '../custom-types'\n\n/**\n * 生成唯一的 DOM ID\n */\nfunction genDomID(): string {\n return genRandomStr('w-e-insert-video')\n}\n\nclass EditorVideoSizeMenu implements IModalMenu {\n readonly title = t('videoModule.editSize')\n\n readonly tag = 'button'\n\n readonly showModal = true // 点击 button 时显示 modal\n\n readonly modalWidth = 320\n\n private $content: Dom7Array | null = null\n\n private readonly widthInputId = genDomID()\n\n private readonly heightInputId = genDomID()\n\n private readonly buttonId = genDomID()\n\n private getSelectedVideoNode(editor: IDomEditor): SlateNode | null {\n return DomEditor.getSelectedNodeByType(editor, 'video')\n }\n\n getValue(_editor: IDomEditor): string | boolean {\n // 插入菜单,不需要 value\n return ''\n }\n\n isActive(_editor: IDomEditor): boolean {\n // 任何时候,都不用激活 menu\n return false\n }\n\n exec(_editor: IDomEditor, _value: string | boolean) {\n // 点击菜单时,弹出 modal 之前,不需要执行其他代码\n // 此处空着即可\n }\n\n isDisabled(editor: IDomEditor): boolean {\n if (editor.selection == null) { return true }\n\n const videoNode = this.getSelectedVideoNode(editor)\n\n if (videoNode == null) {\n // 选区未处于 video node ,则禁用\n return true\n }\n return false\n }\n\n getModalPositionNode(editor: IDomEditor): SlateNode | null {\n return this.getSelectedVideoNode(editor)\n }\n\n getModalContentElem(editor: IDomEditor): DOMElement {\n const { widthInputId, heightInputId, buttonId } = this\n\n const [widthContainerElem, inputWidthElem] = genModalInputElems(\n t('videoModule.width'),\n widthInputId,\n 'auto',\n )\n const $inputWidth = $(inputWidthElem)\n const [heightContainerElem, inputHeightElem] = genModalInputElems(\n t('videoModule.height'),\n heightInputId,\n 'auto',\n )\n const $inputHeight = $(inputHeightElem)\n const [buttonContainerElem] = genModalButtonElems(buttonId, t('videoModule.ok'))\n\n const videoNode = this.getSelectedVideoNode(editor) as VideoElement\n\n if (this.$content == null) {\n // 第一次渲染\n const $content = $('<div></div>')\n\n // 绑定事件(第一次渲染时绑定,不要重复绑定)\n $content.on('click', `#${buttonId}`, e => {\n e.preventDefault()\n\n const rawWidth = $content.find(`#${widthInputId}`).val().trim()\n const rawHeight = $content.find(`#${heightInputId}`).val().trim()\n\n const isPercentage = (value: string) => /^\\d+(\\.\\d+)?%$/.test(value) // 检查是否为合法的百分比字符串\n const isNumeric = (value: string) => /^\\d+(\\.\\d+)?$/.test(value) // 检查是否为合法的数字\n\n let width = 'auto'\n let height = 'auto'\n\n if (isPercentage(rawWidth)) {\n width = rawWidth\n } else if (isNumeric(rawWidth)) {\n width = `${parseInt(rawWidth, 10)}px`\n }\n\n if (isPercentage(rawHeight)) {\n height = rawHeight\n } else if (isNumeric(rawHeight)) {\n height = `${parseInt(rawHeight, 10)}px`\n }\n\n const { style = {} } = videoNode as VideoElement\n\n editor.restoreSelection()\n const props: Partial<VideoElement> = {\n style: {\n ...style,\n width,\n height,\n },\n }\n // 修改尺寸\n\n Transforms.setNodes(editor, props, {\n match: n => DomEditor.checkNodeType(n, 'video'),\n })\n\n editor.hidePanelOrModal() // 隐藏 modal\n })\n\n this.$content = $content\n }\n\n const $content = this.$content\n\n // 先清空,再重新添加 DOM 内容\n $content.empty()\n $content.append(widthContainerElem)\n $content.append(heightContainerElem)\n $content.append(buttonContainerElem)\n\n if (videoNode == null) { return $content[0] }\n\n // 初始化 input 值\n const { style = {} } = videoNode\n const { width = '', height = '' } = style\n\n $inputWidth.val(width)\n $inputHeight.val(height)\n setTimeout(() => {\n $inputWidth.focus()\n })\n\n return $content[0]\n }\n}\n\nexport default EditorVideoSizeMenu\n","/**\n * @description editor video menu\n * @author\n */\n\nimport {\n DomEditor,\n genModalButtonElems,\n genModalInputElems,\n IDomEditor,\n IModalMenu,\n t,\n} from '@wangeditor-next/core'\nimport { Node as SlateNode, Transforms } from 'slate'\n\nimport { PENCIL_SVG } from '../../constants/svg'\nimport $, { Dom7Array, DOMElement } from '../../utils/dom'\nimport { genRandomStr } from '../../utils/util'\nimport { VideoElement } from '../custom-types'\n\n/**\n * 生成唯一的 DOM ID\n */\nfunction genDomID(): string {\n return genRandomStr('w-e-edit-video')\n}\n\nclass Editvideo implements IModalMenu {\n readonly title = t('videoModule.edit')\n\n readonly iconSvg = PENCIL_SVG\n\n readonly tag = 'button'\n\n readonly showModal = true // 点击 button 时显示 modal\n\n readonly modalWidth = 300\n\n private $content: Dom7Array | null = null\n\n private readonly srcInputId = genDomID()\n\n private readonly posterInputId = genDomID()\n\n private readonly buttonId = genDomID()\n\n private getSelectedVideoNode(editor: IDomEditor): SlateNode | null {\n return DomEditor.getSelectedNodeByType(editor, 'video')\n }\n\n getValue(_editor: IDomEditor): string | boolean {\n // 编辑视频,用不到 getValue\n return ''\n }\n\n isActive(_editor: IDomEditor): boolean {\n // 无需 active\n return false\n }\n\n exec(_editor: IDomEditor, _value: string | boolean) {\n // 点击菜单时,弹出 modal 之前,不需要执行其他代码\n // 此处空着即可\n }\n\n isDisabled(editor: IDomEditor): boolean {\n if (editor.selection == null) { return true }\n\n const videoNode = this.getSelectedVideoNode(editor)\n\n if (videoNode == null) {\n // 选区未处于 video node ,则禁用\n return true\n }\n return false\n }\n\n getModalPositionNode(editor: IDomEditor): SlateNode | null {\n return this.getSelectedVideoNode(editor)\n }\n\n getModalContentElem(editor: IDomEditor): DOMElement {\n const { srcInputId, posterInputId, buttonId } = this\n\n // 获取 input button elem\n const [srcContainerElem, inputSrcElem] = genModalInputElems(\n t('videoModule.videoSrc'),\n srcInputId,\n t('videoModule.videoSrcPlaceHolder'),\n )\n const [posterContainerElem, inputPosterElem] = genModalInputElems(\n t('videoModule.videoPoster'),\n posterInputId,\n t('videoModule.videoPosterPlaceHolder'),\n )\n const $inputSrc = $(inputSrcElem)\n const $inputPoster = $(inputPosterElem)\n const [buttonContainerElem] = genModalButtonElems(buttonId, t('videoModule.ok'))\n\n if (this.$content == null) {\n // 第一次渲染\n const $content = $('<div></div>')\n\n // 绑定事件(第一次渲染时绑定,不要重复绑定)\n $content.on('click', `#${buttonId}`, async e => {\n e.preventDefault()\n\n const src = $content.find(`#${srcInputId}`).val().trim()\n const poster = $content.find(`#${posterInputId}`).val().trim()\n // video 标签必须要加 key,只修改 src 不会触发重新渲染\n const videoId = genRandomStr('video-')\n\n const props: Partial<VideoElement> = {\n src,\n poster,\n key: videoId,\n }\n\n editor.restoreSelection()\n // 修改尺寸\n Transforms.setNodes(editor, props, {\n match: n => DomEditor.checkNodeType(n, 'video'),\n })\n editor.hidePanelOrModal() // 隐藏 modal\n })\n\n // 记录属性,重要\n this.$content = $content\n }\n\n const $content = this.$content\n\n $content.empty() // 先清空内容\n\n // append inputs and button\n $content.append(srcContainerElem)\n $content.append(posterContainerElem)\n $content.append(buttonContainerElem)\n\n const videoNode = this.getSelectedVideoNode(editor) as VideoElement\n\n if (videoNode == null) { return $content[0] }\n\n // 初始化 input 值\n const { src = '', poster = '' } = videoNode\n\n $inputSrc.val(src)\n $inputPoster.val(poster)\n\n // focus 一个 input(异步,此时 DOM 尚未渲染)\n setTimeout(() => {\n $inputSrc.focus()\n })\n\n return $content[0]\n }\n}\n\nexport default Editvideo\n","/**\n * @description icon svg\n * @author wangfupeng\n */\n\n/**\n * 【注意】svg 字符串的长度 ,否则会导致代码体积过大\n * 尽量选择 https://www.iconfont.cn/collections/detail?spm=a313x.7781069.0.da5a778a4&cid=20293\n * 找不到再从 iconfont.com 搜索\n */\n\n// 视频\nexport const VIDEO_SVG = '<svg viewBox=\"0 0 1024 1024\"><path d=\"M981.184 160.096C837.568 139.456 678.848 128 512 128S186.432 139.456 42.816 160.096C15.296 267.808 0 386.848 0 512s15.264 244.16 42.816 351.904C186.464 884.544 345.152 896 512 896s325.568-11.456 469.184-32.096C1008.704 756.192 1024 637.152 1024 512s-15.264-244.16-42.816-351.904zM384 704V320l320 192-320 192z\"></path></svg>'\n\n// 上传视频\nexport const UPLOAD_VIDEO_SVG = '<svg viewBox=\"0 0 1056 1024\"><path d=\"M805.902261 521.819882a251.441452 251.441452 0 0 0-251.011972 246.600033 251.051015 251.051015 0 1 0 502.023944 8.823877 253.237463 253.237463 0 0 0-251.011972-255.42391z m59.463561 240.001647v129.898403h-116.701631v-129.898403h-44.041298l101.279368-103.504859 101.279368 103.504859z\" p-id=\"6802\"></path><path d=\"M788.254507 0.000781H99.094092A98.663439 98.663439 0 0 0 0.001171 99.093701v590.067495a98.663439 98.663439 0 0 0 99.092921 99.092921h411.7549a266.434235 266.434235 0 0 1-2.186448-41.815807 275.843767 275.843767 0 0 1 275.180024-270.729042 270.650955 270.650955 0 0 1 103.504859 19.834201V99.093701A101.51363 101.51363 0 0 0 788.254507 0.000781zM295.054441 640.747004V147.507894l394.146189 246.600033z\"></path></svg>'\n\n// 编辑\nexport const PENCIL_SVG = '<svg viewBox=\"0 0 1024 1024\"><path d=\"M864 0a160 160 0 0 1 128 256l-64 64-224-224 64-64c26.752-20.096 59.968-32 96-32zM64 736l-64 288 288-64 592-592-224-224L64 736z m651.584-372.416l-448 448-55.168-55.168 448-448 55.168 55.168z\"></path></svg>'\n\n// 视频左对齐\nexport const VIDEO_ALIGN_LEFT_SVG =\n '<svg viewBox=\"0 0 1024 1024\"><path d=\"M768 793.6v102.4H51.2v-102.4h716.8z m204.8-230.4v102.4H51.2v-102.4h921.6z m-204.8-230.4v102.4H51.2v-102.4h716.8zM972.8 102.4v102.4H51.2V102.4h921.6z\"></path></svg>'\n\n// 视频居中\nexport const VIDEO_ALIGN_CENTER_SVG =\n '<svg viewBox=\"0 0 1024 1024\"><path d=\"M870.4 793.6v102.4H153.6v-102.4h716.8z m102.4-230.4v102.4H51.2v-102.4h921.6z m-102.4-230.4v102.4H153.6v-102.4h716.8zM972.8 102.4v102.4H51.2V102.4h921.6z\"></path></svg>'\n\n// 视频右对齐\nexport const VIDEO_ALIGN_RIGHT_SVG =\n '<svg viewBox=\"0 0 1024 1024\"><path d=\"M972.8 793.6v102.4H256v-102.4h716.8z m0-230.4v102.4H51.2v-102.4h921.6z m0-230.4v102.4H256v-102.4h716.8zM972.8 102.4v102.4H51.2V102.4h921.6z\"></path></svg>'\n\n// // 垃圾桶(删除)\n// export const TRASH_SVG =\n// '<svg viewBox=\"0 0 1024 1024\"><path d=\"M826.8032 356.5312c-19.328 0-36.3776 15.6928-36.3776 35.0464v524.2624c0 19.328-16 34.56-35.328 34.56H264.9344c-19.328 0-35.5072-15.3088-35.5072-34.56V390.0416c0-19.328-14.1568-35.0464-33.5104-35.0464s-33.5104 15.6928-33.5104 35.0464V915.712c0 57.9328 44.6208 108.288 102.528 108.288H755.2c57.9328 0 108.0832-50.4576 108.0832-108.288V391.4752c-0.1024-19.2512-17.1264-34.944-36.48-34.944z\" p-id=\"9577\"></path><path d=\"M437.1712 775.7568V390.6048c0-19.328-14.1568-35.0464-33.5104-35.0464s-33.5104 15.616-33.5104 35.0464v385.152c0 19.328 14.1568 35.0464 33.5104 35.0464s33.5104-15.7184 33.5104-35.0464zM649.7024 775.7568V390.6048c0-19.328-17.0496-35.0464-36.3776-35.0464s-36.3776 15.616-36.3776 35.0464v385.152c0 19.328 17.0496 35.0464 36.3776 35.0464s36.3776-15.7184 36.3776-35.0464zM965.0432 217.0368h-174.6176V145.5104c0-57.9328-47.2064-101.76-104.6528-101.76h-350.976c-57.8304 0-105.3952 43.8528-105.3952 101.76v71.5264H54.784c-19.4304 0-35.0464 14.1568-35.0464 33.5104 0 19.328 15.616 33.5104 35.0464 33.5104h910.3616c19.328 0 35.0464-14.1568 35.0464-33.5104 0-19.3536-15.6928-33.5104-35.1488-33.5104z m-247.3728 0H297.3952V145.5104c0-19.328 18.2016-34.7648 37.4272-34.7648h350.976c19.1488 0 31.872 15.1296 31.872 34.7648v71.5264z\"></path></svg>'\n","/**\n * @description insert video\n * @author wangfupeng\n */\n\nimport { DomEditor, IDomEditor } from '@wangeditor-next/core'\nimport { Transforms } from 'slate'\n\nimport { replaceSymbols } from '../../utils/util'\nimport { VideoElement } from '../custom-types'\n\n/**\n * 插入视频\n * @param editor editor\n * @param src video src\n * @param poster video poster\n */\nexport default async function (\n editor: IDomEditor,\n src: string,\n poster = '',\n width = '',\n height = '',\n) {\n if (!src) { return }\n\n // 还原选区\n editor.restoreSelection()\n\n // 校验\n const { onInsertedVideo, checkVideo, parseVideoSrc } = editor.getMenuConfig('insertVideo')\n const checkRes = await checkVideo(src, poster)\n\n if (typeof checkRes === 'string') {\n // 校验失败,给出提示\n editor.alert(checkRes, 'error')\n return\n }\n if (checkRes == null) {\n // 校验失败,不给提示\n return\n }\n\n // 转换 src\n let parsedSrc = await parseVideoSrc(src)\n\n if (parsedSrc.trim().indexOf('<iframe ') !== 0) {\n parsedSrc = replaceSymbols(parsedSrc)\n }\n\n // 新建一个 video node\n const video: VideoElement = {\n type: 'video',\n src: parsedSrc,\n poster,\n align: 'center',\n children: [{ text: '' }],\n style: {\n width,\n height,\n },\n }\n\n // 插入视频\n // 不使用此方式会比正常的选区选取先执行\n Promise.resolve().then(() => {\n if (DomEditor.isSelectedEmptyParagraph(editor)) {\n Transforms.removeNodes(editor, { mode: 'highest' })\n }\n Transforms.insertNodes(editor, video, { mode: 'highest' })\n })\n\n // 调用 callback\n onInsertedVideo(video)\n}\n","/**\n * @description insert video menu\n * @author wangfupeng\n */\n\nimport {\n DomEditor,\n genModalButtonElems,\n genModalInputElems,\n IDomEditor,\n IModalMenu,\n t,\n} from '@wangeditor-next/core'\nimport { Node, Range } from 'slate'\n\nimport { VIDEO_SVG } from '../../constants/svg'\nimport $, { Dom7Array, DOMElement } from '../../utils/dom'\nimport { genRandomStr } from '../../utils/util'\nimport insertVideo from '../helper/insert-video'\n\n/**\n * 生成唯一的 DOM ID\n */\nfunction genDomID(): string {\n return genRandomStr('w-e-insert-video')\n}\n\nclass InsertVideoMenu implements IModalMenu {\n readonly title = t('videoModule.insertVideo')\n\n readonly iconSvg = VIDEO_SVG\n\n readonly tag = 'button'\n\n readonly showModal = true // 点击 button 时显示 modal\n\n readonly modalWidth = 320\n\n private $content: Dom7Array | null = null\n\n private readonly srcInputId = genDomID()\n\n private readonly posterInputId = genDomID()\n\n private readonly buttonId = genDomID()\n\n getValue(_editor: IDomEditor): string | boolean {\n // 插入菜单,不需要 value\n return ''\n }\n\n isActive(_editor: IDomEditor): boolean {\n // 任何时候,都不用激活 menu\n return false\n }\n\n exec(_editor: IDomEditor, _value: string | boolean) {\n // 点击菜单时,弹出 modal 之前,不需要执行其他代码\n // 此处空着即可\n }\n\n isDisabled(editor: IDomEditor): boolean {\n const { selection } = editor\n\n if (selection == null) { return true }\n if (!Range.isCollapsed(selection)) { return true } // 选区非折叠,禁用\n\n const selectedElems = DomEditor.getSelectedElems(editor)\n const hasVoidOrPre = selectedElems.some(elem => {\n const type = DomEditor.getNodeType(elem)\n\n if (type === 'pre') { return true }\n if (editor.isVoid(elem)) { return true }\n return false\n })\n\n if (hasVoidOrPre) { return true } // void 或 pre ,禁用\n\n return false\n }\n\n getModalPositionNode(_editor: IDomEditor): Node | null {\n return null // modal 依据选区定位\n }\n\n getModalContentElem(editor: IDomEditor): DOMElement {\n const { srcInputId, posterInputId, buttonId } = this\n\n // 获取 input button elem\n const [srcContainerElem, inputSrcElem] = genModalInputElems(\n t('videoModule.videoSrc'),\n srcInputId,\n t('videoModule.videoSrcPlaceHolder'),\n )\n const [posterContainerElem, inputPosterElem] = genModalInputElems(\n t('videoModule.videoPoster'),\n posterInputId,\n t('videoModule.videoPosterPlaceHolder'),\n )\n const $inputSrc = $(inputSrcElem)\n const $inputPoster = $(inputPosterElem)\n const [buttonContainerElem] = genModalButtonElems(buttonId, t('videoModule.ok'))\n\n if (this.$content == null) {\n // 第一次渲染\n const $content = $('<div></div>')\n\n // 绑定事件(第一次渲染时绑定,不要重复绑定)\n $content.on('click', `#${buttonId}`, async e => {\n e.preventDefault()\n const src = $content.find(`#${srcInputId}`).val().trim()\n const poster = $content.find(`#${posterInputId}`).val().trim()\n\n await insertVideo(editor, src, poster)\n editor.hidePanelOrModal() // 隐藏 modal\n })\n\n // 记录属性,重要\n this.$content = $content\n }\n\n const $content = this.$content\n\n $content.empty() // 先清空内容\n\n // append inputs and button\n $content.append(srcContainerElem)\n $content.append(posterContainerElem)\n $content.append(buttonContainerElem)\n\n // 设置 input val\n $inputSrc.val('')\n $inputPoster.val('')\n\n // focus 一个 input(异步,此时 DOM 尚未渲染)\n setTimeout(() => {\n $inputSrc.focus()\n })\n\n return $content[0]\n }\n}\n\nexport default InsertVideoMenu\n","/**\n * @description upload video\n * @author wangfupeng\n */\n\nimport {\n IDomEditor, IUploader,\n IUploadFile, IUploadResultFile,\n} from '@wangeditor-next/core'\nimport { createUploader } from '@wangeditor-next/core/upload'\n\nimport insertVideo from './insert-video'\n\nfunction getMenuConfig(editor: IDomEditor) {\n // 获取配置,见 `./config.js`\n return editor.getMenuConfig('uploadVideo')\n}\n\n// 存储 editor uploader 的关系 - 缓存 uploader ,不重复创建\nconst EDITOR_TO_UPLOADER_MAP = new WeakMap<IDomEditor, IUploader>()\n\n/**\n * 获取 uploader 实例(并通过 editor 缓存)\n * @param editor editor\n */\nfunction getUploader(editor: IDomEditor): IUploader {\n let uploader = EDITOR_TO_UPLOADER_MAP.get(editor)\n\n if (uploader != null) { return uploader }\n\n const menuConfig = getMenuConfig(editor)\n const {\n onSuccess, onProgress, onFailed, customInsert, onError,\n } = menuConfig\n\n // 上传完成之后\n const successHandler = (file: IUploadResultFile, res: any) => {\n // 预期 res 格式:\n // 成功:{ errno: 0, data: { url, poster } }\n // 失败:{ errno: !0, message: '失败信息' }\n\n if (customInsert) {\n // 用户自定义插入视频,此时 res 格式可能不符合预期\n customInsert(res, (src, poster) => insertVideo(editor, src, poster))\n // success 回调\n onSuccess(file, res)\n return\n }\n\n const { errno = 1, data = {} } = res\n\n if (errno !== 0) {\n // failed 回调\n onFailed(file, res)\n return\n }\n\n const { url = '', poster = '' } = data\n\n insertVideo(editor, url, poster)\n\n // success 回调\n onSuccess(file, res)\n }\n\n // progress 显示进度条\n const progressHandler = (progress: number) => {\n editor.showProgressBar(progress)\n\n // 回调函数\n if (onProgress) { onProgress(progress) }\n }\n\n // onError 提示错误\n const errorHandler = (file: any, err: any, res: any) => {\n onError(file, err, res)\n }\n\n uploader = createUploader({\n ...menuConfig,\n onProgress: progressHandler,\n onSuccess: successHandler,\n onError: errorHandler,\n }, editor)\n EDITOR_TO_UPLOADER_MAP.set(editor, uploader)\n\n return uploader\n}\n\n/**\n * 上传视频文件\n * @param editor editor\n * @param file file\n */\nasync function uploadFile(editor: IDomEditor, files: File[]) {\n const uploader = getUploader(editor)\n const uploadList: IUploadFile[] = files.map(file => ({\n name: file.name,\n type: file.type,\n size: file.size,\n data: file,\n }))\n\n uploader.addFiles(uploadList)\n await uploader.upload()\n}\n\nexport default async function (editor: IDomEditor, files: FileList | null) {\n if (files == null) { return }\n const fileList = Array.prototype.slice.call(files)\n\n const uploadFileList : File[] = []\n // 获取菜单配置\n const { customUpload } = getMenuConfig(editor)\n\n // 按顺序上传\n for await (const file of fileList) {\n // 上传\n if (customUpload) {\n // 自定义上传\n await customUpload(file, (src, poster) => insertVideo(editor, src, poster), editor)\n } else {\n uploadFileList.push(file)\n }\n }\n // 默认上传\n if (uploadFileList.length > 0) { await uploadFile(editor, uploadFileList) }\n}\n","/**\n * @description upload video menu\n * @author wangfupeng\n */\n\nimport {\n DomEditor, IButtonMenu, IDomEditor, t,\n} from '@wangeditor-next/core'\nimport { Range } from 'slate'\n\nimport { UPLOAD_VIDEO_SVG } from '../../constants/svg'\nimport $ from '../../utils/dom'\nimport insertVideo from '../helper/insert-video'\nimport uploadVideos from '../helper/upload-videos'\n\nclass UploadVideoMenu implements IButtonMenu {\n readonly title = t('videoModule.uploadVideo')\n\n readonly iconSvg = UPLOAD_VIDEO_SVG\n\n readonly tag = 'button'\n\n getValue(_editor: IDomEditor): string | boolean {\n // 无需获取 val\n return ''\n }\n\n isActive(_editor: IDomEditor): boolean {\n // 任何时候,都不用激活 menu\n return false\n }\n\n exec(editor: IDomEditor, _value: string | boolean) {\n const { allowedFileTypes = [], customBrowseAndUpload } = this.getMenuConfig(editor)\n\n // 自定义选择图片,并上传,如图床\n if (customBrowseAndUpload) {\n customBrowseAndUpload((src, poster) => insertVideo(editor, src, poster))\n return\n }\n\n // 设置选择文件的类型\n let acceptAttr = ''\n\n if (allowedFileTypes.length > 0) {\n acceptAttr = `accept=\"${allowedFileTypes.join(', ')}\"`\n }\n\n // 添加 file input(每次重新创建 input)\n const $body = $('body')\n const $inputFile = $(`<input type=\"file\" ${acceptAttr} multiple/>`)\n\n $inputFile.hide()\n $body.append($inputFile)\n $inputFile.click()\n // 选中文件\n $inputFile.on('change', () => {\n const files = ($inputFile[0] as HTMLInputElement).files\n\n uploadVideos(editor, files) // 上传文件\n })\n }\n\n isDisabled(editor: IDomEditor): boolean {\n const { selection } = editor\n\n if (selection == null) { return true }\n if (!Range.isCollapsed(selection)) { return true } // 选区非折叠,禁用\n\n const selectedElems = DomEditor.getSelectedElems(editor)\n const hasVoidOrPre = selectedElems.some(elem => {\n const type = DomEditor.getNodeType(elem)\n\n if (type === 'pre') { return true }\n if (editor.isVoid(elem)) { return true }\n return false\n })\n\n if (hasVoidOrPre) { return true } // void 或 pre ,禁用\n\n return false\n }\n\n private getMenuConfig(editor: IDomEditor) {\n // 获取配置,见 `./config.js`\n return editor.getMenuConfig('uploadVideo')\n }\n}\n\nexport default UploadVideoMenu\n","/**\n * @description align video menu\n */\n\nimport { DomEditor, IButtonMenu, IDomEditor, t } from '@wangeditor-next/core'\nimport { Transforms } from 'slate'\n\nimport { getVideoAlign } from '../alignment'\nimport { VideoAlign, VideoElement } from '../custom-types'\n\nclass VideoAlignMenu implements IButtonMenu {\n readonly tag = 'button'\n\n readonly title: string\n\n constructor(\n readonly align: VideoAlign,\n titleKey: string,\n readonly iconSvg: string\n ) {\n this.title = t(titleKey)\n }\n\n private getSelectedVideo(editor: IDomEditor): VideoElement | null {\n return DomEditor.getSelectedNodeByType(editor, 'video') as VideoElement | null\n }\n\n getValue(editor: IDomEditor): string | boolean {\n const video = this.getSelectedVideo(editor)\n\n return video ? getVideoAlign(video) : false\n }\n\n isActive(editor: IDomEditor): boolean {\n return this.getValue(editor) === this.align\n }\n\n isDisabled(editor: IDomEditor): boolean {\n if (editor.selection == null) {\n return true\n }\n return this.getSelectedVideo(editor) == null\n }\n\n exec(editor: IDomEditor, _value: string | boolean): void {\n if (this.isDisabled(editor)) {\n return\n }\n\n const props: Partial<VideoElement> = { align: this.align }\n\n Transforms.setNodes(editor, props, {\n match: node => DomEditor.checkNodeType(node, 'video'),\n })\n }\n}\n\nexport default VideoAlignMenu\n","/**\n * @description parse html\n * @author wangfupeng\n */\n\nimport { IDomEditor } from '@wangeditor-next/core'\nimport { Descendant } from 'slate'\n\nimport $, { Dom7Array, DOMElement } from '../utils/dom'\nimport { styleStringToObject } from '../utils/util'\nimport { normalizeVideoAlign } from './alignment'\nimport { VideoAlign, VideoElement, videoStyle } from './custom-types'\n\nfunction genVideoElem(\n src: string,\n poster = '',\n width = 'auto',\n height = 'auto',\n style: videoStyle = {},\n align: VideoAlign = 'center',\n): VideoElement {\n return {\n type: 'video',\n src,\n poster,\n width,\n height,\n style,\n children: [{ text: '' }], // void 元素有一个空 text\n align,\n }\n}\n\nfunction getClassAlign($elem: Dom7Array): string {\n const classAttr = $elem.attr('class') || ''\n const classList = classAttr.trim().split(/\\s+/).filter(Boolean)\n\n for (let i = 0; i < classList.length; i += 1) {\n const className = classList[i]\n\n if (className.startsWith('w-e-video-align-')) {\n return className.replace('w-e-video-align-', '')\n }\n }\n\n return ''\n}\n\nfunction getVideoAlign($elem: Dom7Array): VideoAlign {\n const dataAlign = ($elem.attr('data-w-e-align') || '').trim()\n\n if (dataAlign) { return normalizeVideoAlign(dataAlign) }\n\n const containerStyle = styleStringToObject($elem.attr('style') || '')\n const justifyContent = containerStyle['justify-content']\n\n if (justifyContent === 'flex-start') { return 'left' }\n if (justifyContent === 'flex-end') { return 'right' }\n if (justifyContent === 'center') { return 'center' }\n\n const classAlign = getClassAlign($elem)\n\n if (classAlign) { return normalizeVideoAlign(classAlign) }\n\n // Import-only adapters for HTML generated by the previous text-alignment model.\n const legacyStyleAlign = containerStyle['text-align']\n const legacyDataAlign = ($elem.attr('data-w-e-text-align') || '').trim()\n\n return normalizeVideoAlign(legacyStyleAlign || legacyDataAlign)\n}\n\nfunction getVideoSizeStyle(styleStr: string): videoStyle {\n const parsedStyle = styleStringToObject(styleStr) as Record<string, string>\n const style: videoStyle = {}\n\n if (parsedStyle.width) { style.width = parsedStyle.width }\n if (parsedStyle.height) { style.height = parsedStyle.height }\n\n return style\n}\n\nfunction parseHtml(elem: DOMElement, _children: Descendant[], _editor: IDomEditor): VideoElement {\n const $elem = $(elem)\n let src = ''\n let poster = ''\n let width = 'auto'\n let height = 'auto'\n let style: videoStyle = {}\n let align: VideoAlign = 'center'\n // <iframe> 形式\n const $iframe = $elem.find('iframe')\n\n if ($iframe.length > 0) {\n width = $iframe.attr('width') || 'auto'\n height = $iframe.attr('height') || 'auto'\n const iframeStyleStr = $iframe.attr('style') || ''\n\n style = getVideoSizeStyle(iframeStyleStr)\n const iframeStyleWidth = $iframe.attr('data-w-e-style-width') || ''\n const iframeStyleHeight = $iframe.attr('data-w-e-style-height') || ''\n\n if (!style.width && iframeStyleWidth) { style.width = iframeStyleWidth }\n if (!style.height && iframeStyleHeight) { style.height = iframeStyleHeight }\n src = $iframe[0].outerHTML\n align = getVideoAlign($elem)\n return genVideoElem(src, poster, width, height, style, align)\n }\n\n // <video> 形式\n const $video = $elem.find('video')\n\n src = $video.attr('src') || ''\n if (!src) {\n if ($video.length > 0) {\n const $source = $video.find('source')\n\n src = $source.attr('src') || ''\n }\n }\n width = $video.attr('width') || 'auto'\n height = $video.attr('height') || 'auto'\n poster = $video.attr('poster') || ''\n const videoStyleStr = $video.attr('style') || ''\n\n style = getVideoSizeStyle(videoStyleStr)\n const videoStyleWidth = $video.attr('data-w-e-style-width') || ''\n const videoStyleHeight = $video.attr('data-w-e-style-height') || ''\n\n if (!style.width && videoStyleWidth) { style.width = videoStyleWidth }\n if (!style.height && videoStyleHeight) { style.height = videoStyleHeight }\n align = getVideoAlign($elem)\n return genVideoElem(src, poster, width, height, style, align)\n}\n\nexport const parseHtmlConf = {\n selector: 'figure[data-w-e-type=\"video\"],div[data-w-e-type=\"video\"]',\n parseElemHtml: parseHtml,\n}\n","/**\n * @description video render elem\n * @author wangfupeng\n */\n\nimport { DomEditor, IDomEditor } from '@wangeditor-next/core'\nimport { Element } from 'slate'\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport { h, jsx, VNode } from 'snabbdom'\n\nimport { genSizeStyledIframeHtml } from '../utils/dom'\nimport { getVideoAlign, getVideoAlignClass } from './alignment'\nimport { VideoElement } from './custom-types'\n\nfunction renderVideo(elemNode: Element, children: VNode[] | null, editor: IDomEditor): VNode {\n const {\n src = '',\n poster = '',\n key = '',\n width = 'auto',\n height = 'auto',\n style = {},\n } = elemNode as VideoElement\n const align = getVideoAlign(elemNode)\n const containerClassName = [\n 'w-e-video',\n 'w-e-textarea-video-container',\n getVideoAlignClass(align),\n ].join(' ')\n\n // 是否选中\n const selected = DomEditor.isNodeSelected(editor, elemNode)\n\n let vnode: VNode\n\n if (src.trim().indexOf('<iframe ') === 0) {\n // 增加尺寸样式\n const iframeHtml = genSizeStyledIframeHtml(src, width, height, style)\n\n // iframe 形式,第三方视频\n vnode = (\n <figure\n className={containerClassName}\n data-selected={selected ? 'true' : ''} // 标记为 选中\n data-w-e-align={align}\n innerHTML={iframeHtml} // 内嵌第三方 iframe 视频\n ></figure>\n )\n } else {\n // 其他,mp4 格式\n const videoVnode = (\n <video key={key} poster={poster} controls style={style}>\n <source src={src} type=\"video/mp4\" />\n {'Sorry, your browser doesn\\'t support embedded videos.\\n 抱歉,浏览器不支持 video 视频'}\n </video>\n )\n // @ts-ignore 添加尺寸\n\n if (width !== 'auto') { videoVnode.data.width = width }\n // @ts-ignore\n if (height !== 'auto') { videoVnode.data.height = height }\n\n vnode = (\n <figure\n className={containerClassName}\n data-selected={selected ? 'true' : ''} // 标记为 选中\n data-w-e-align={align}\n >\n {videoVnode}\n </figure>\n )\n }\n\n // 【注意】void node 中,renderElem 不用处理 children 。core 会统一处理。\n\n const containerVnode = h(\n 'div',\n {\n props: {\n contentEditable: false,\n },\n on: {\n mousedown: e => e.preventDefault(),\n },\n },\n vnode,\n )\n\n return containerVnode\n}\n\nconst renderVideoConf = {\n type: 'video', // 和 elemNode.type 一致\n renderElem: renderVideo,\n}\n\nexport { renderVideoConf }\n","/**\n * @description video module\n * @author wangfupeng\n */\n\nimport { IModuleConf } from '@wangeditor-next/core'\n\nimport { videoToHtmlConf } from './elem-to-html'\nimport {\n editorVideoSizeMenuConf,\n editorVideoSrcMenuConf,\n insertVideoMenuConf,\n uploadVideoMenuConf,\n videoAlignCenterMenuConf,\n videoAlignLeftMenuConf,\n videoAlignRightMenuConf,\n} from './menu/index'\nimport { parseHtmlConf } from './parse-elem-html'\nimport withVideo from './plugin'\nimport { preParseHtmlConf } from './pre-parse-html'\nimport { renderVideoConf } from './render-elem'\n\nconst video: Partial<IModuleConf> = {\n renderElems: [renderVideoConf],\n elemsToHtml: [videoToHtmlConf],\n preParseHtml: [preParseHtmlConf],\n parseElemsHtml: [parseHtmlConf],\n menus: [\n insertVideoMenuConf,\n uploadVideoMenuConf,\n editorVideoSizeMenuConf,\n editorVideoSrcMenuConf,\n videoAlignLeftMenuConf,\n videoAlignCenterMenuConf,\n videoAlignRightMenuConf,\n ],\n editorPlugin: withVideo,\n}\n\nexport default video\n","/**\n * @description pre parse html\n * @author wangfupeng\n */\n\nimport $, { DOMElement, getTagName } from '../utils/dom'\n\n/**\n * pre-prase video ,兼容 V4\n * @param elem elem\n */\nfunction preParse(elem: DOMElement): DOMElement {\n const $elem = $(elem)\n let $video = $elem\n\n const elemTagName = getTagName($elem)\n\n if (elemTagName === 'p') {\n // v4 的 video 或 iframe 是被 p 包裹的\n const children = $elem.children()\n\n if (children.length === 1) {\n const firstChild = children[0]\n const firstChildTagName = firstChild.tagName.toLowerCase()\n\n if (['iframe', 'video'].includes(firstChildTagName)) {\n // p 下面包含 iframe 或 video\n $video = $(firstChild)\n }\n }\n }\n\n const videoTagName = getTagName($video)\n\n if (videoTagName !== 'iframe' && videoTagName !== 'video') { return $video[0] }\n\n // 已经符合 V5 格式\n const $parent = $video.parent()\n\n if ($parent.attr('data-w-e-type') === 'video') { return $video[0] }\n\n const $container = $(\n '<figure data-w-e-type=\"video\" data-w-e-is-void data-w-e-align=\"center\" class=\"w-e-video w-e-video-align-center\"></figure>',\n )\n\n $container.append($video)\n\n return $container[0]\n}\n\nexport const preParseHtmlConf = {\n selector: 'iframe,video,p',\n preParseHtml: preParse,\n}\n","/**\n * @description video menu\n * @author wangfupeng\n */\n\nimport {\n VIDEO_ALIGN_CENTER_SVG,\n VIDEO_ALIGN_LEFT_SVG,\n VIDEO_ALIGN_RIGHT_SVG,\n} from '../../constants/svg'\nimport { genInsertVideoMenuConfig, genUploadVideoMenuConfig } from './config'\nimport EditorVideoSizeMenu from './EditVideoSizeMenu'\nimport EditorVideoSrcMenu from './EditVideoSrcMenu'\nimport InsertVideoMenu from './InsertVideoMenu'\n// import DeleteVideoMenu from './DeleteVideoMenu'\nimport UploadVideoMenu from './UploadVideoMenu'\nimport VideoAlignMenu from './VideoAlignMenu'\n\nexport const insertVideoMenuConf = {\n key: 'insertVideo',\n factory() {\n return new InsertVideoMenu()\n },\n\n // 默认的菜单菜单配置,将存储在 editorConfig.MENU_CONF[key] 中\n // 创建编辑器时,可通过 editorConfig.MENU_CONF[key] = {...} 来修改\n config: genInsertVideoMenuConfig(),\n}\n\nexport const uploadVideoMenuConf = {\n key: 'uploadVideo',\n factory() {\n return new UploadVideoMenu()\n },\n\n // 默认的菜单菜单配置,将存储在 editorConfig.MENU_CONF[key] 中\n // 创建编辑器时,可通过 editorConfig.MENU_CONF[key] = {...} 来修改\n config: genUploadVideoMenuConfig(),\n}\n\nexport const editorVideoSizeMenuConf = {\n key: 'editVideoSize',\n factory() {\n return new EditorVideoSizeMenu()\n },\n}\n\nexport const editorVideoSrcMenuConf = {\n key: 'editVideoSrc',\n factory() {\n return new EditorVideoSrcMenu()\n },\n}\n\nexport const videoAlignLeftMenuConf = {\n key: 'videoAlignLeft',\n factory() {\n return new VideoAlignMenu('left', 'videoModule.alignLeft', VIDEO_ALIGN_LEFT_SVG)\n },\n}\n\nexport const videoAlignCenterMenuConf = {\n key: 'videoAlignCenter',\n factory() {\n return new VideoAlignMenu('center', 'videoModule.alignCenter', VIDEO_ALIGN_CENTER_SVG)\n },\n}\n\nexport const videoAlignRightMenuConf = {\n key: 'videoAlignRight',\n factory() {\n return new VideoAlignMenu('right', 'videoModule.alignRight', VIDEO_ALIGN_RIGHT_SVG)\n },\n}\n\n// export const deleteVideoMenuConf = {\n// key: 'deleteVideo',\n// factory() {\n// return new DeleteVideoMenu()\n// },\n// }\n// 键盘能删除 video 了,注释掉这个菜单 wangfupeng 22.02.23\n","/**\n * @description video menu config\n * @author wangfupeng\n */\n\nimport { IUploadVideoConfig } from '@wangeditor-next/core'\n\nimport { VideoElement } from '../custom-types'\n\nexport function genUploadVideoMenuConfig(): IUploadVideoConfig {\n return {\n server: '', // server API 地址,需用户配置\n\n fieldName: 'wangeditor-uploaded-video', // formData 中,文件的 key\n maxFileSize: 10 * 1024 * 1024, // 10M\n maxNumberOfFiles: 5, // 最多上传 xx 个视频\n allowedFileTypes: ['video/*'],\n meta: {\n // 自定义上传参数,例如传递验证的 token 等。参数会被添加到 formData 中,一起上传到服务端。\n // 例如:token: 'xxxxx', x: 100\n },\n metaWithUrl: false,\n // headers: {\n // // 自定义 http headers\n // // 例如:Accept: 'text/x-json', a: 100,\n // },\n withCredentials: false,\n timeout: 30 * 1000, // 30s\n\n onBeforeUpload: (files: any) => files, // 返回 false 则终止上传\n onProgress: (_progress: number) => {\n /* on progress */\n },\n onSuccess: (_file: any, _res: any) => {\n /* on success */\n },\n onFailed: (file: any, res: any) => {\n /* on failed */\n console.error(`'${file.name}' upload failed`, res)\n },\n onError: (file: any, err: any, res: any) => {\n /* on error */\n /* on timeout */\n console.error(`'${file.name} upload error`, err, res)\n },\n\n // 自定义插入视频,用户配置\n // customInsert: (res, insertFn) => {},\n\n // 自定义上传视频,用户配置\n // customUpload: (file, insertFn) => {},\n\n // 自定义上传适配器,默认仍使用内置 Uppy\n // uploadAdapter: ({ config, editor }) => ({ addFiles() {}, upload: async () => {} }),\n\n // 自定义选择,并上传视频,如:图床 (用户配置)\n // customBrowseAndUpload: insertFn => {},\n }\n}\n\n/**\n * 生成插入网络视频的配置\n */\nexport function genInsertVideoMenuConfig() {\n return {\n onInsertedVideo(_node: VideoElement) {\n // 插入视频之后的 callback\n },\n\n /**\n * 检查 video ,支持 async\n * @param src src\n * @param poster poster\n */\n checkVideo(_src: string, _poster: string): boolean | string | undefined {\n // 1. 返回 true ,说明检查通过\n // 2. 返回一个字符串,说明检查未通过,编辑器会阻止插入。会 alert 出错误信息(即返回的字符串)\n // 3. 返回 undefined(即没有任何返回),说明检查未通过,编辑器会阻止插入\n return true\n },\n\n /**\n * 转换 video src\n * @param src src\n * @returns new src\n */\n parseVideoSrc(src: string): string {\n return src\n },\n }\n}\n","/**\n * @description editor 插件,重写 editor API\n * @author wangfupeng\n */\n\nimport { DomEditor, IDomEditor } from '@wangeditor-next/core'\nimport { Transforms } from 'slate'\n\nimport { CustomElement } from '../../../custom-types'\n\nfunction withVideo<T extends IDomEditor>(editor: T): T {\n const { isVoid, normalizeNode } = editor\n const newEditor = editor\n\n // 重写 isVoid\n newEditor.isVoid = (elem: CustomElement) => {\n const { type } = elem\n\n if (type === 'video') {\n return true\n }\n\n return isVoid(elem)\n }\n\n // 重写 normalizeNode\n newEditor.normalizeNode = ([node, path]) => {\n const type = DomEditor.getNodeType(node)\n\n // ----------------- video 后面必须跟一个 p header blockquote -----------------\n if (type === 'video') {\n // -------------- video 是 editor 最后一个节点,需要后面插入 p --------------\n const isLast = DomEditor.isLastNode(newEditor, node)\n\n if (isLast) {\n Transforms.insertNodes(newEditor, DomEditor.genEmptyParagraph(), { at: [path[0] + 1] })\n }\n }\n\n // 执行默认的 normalizeNode ,重要!!!\n return normalizeNode([node, path])\n }\n\n // 返回 editor ,重要!\n return newEditor\n}\n\nexport default withVideo\n"],"names":["getTagName","$elem","length","tagName","toLowerCase","genSizeStyledIframeHtml","iframeHtml","width","height","style","classMode","$iframe","$","_a","styleWidth","_b","styleHeight","widthData","concat","heightData","attr","removeAttr","styleStr","outerHTML","i18nAddResources","videoModule","delete","uploadVideo","insertVideo","videoSrc","videoSrcPlaceHolder","videoPoster","videoPosterPlaceHolder","ok","editSize","edit","alignLeft","alignCenter","alignRight","append","fn","on","focus","val","html","parent","hasClass","empty","DEFAULT_VIDEO_ALIGN","VIDEO_ALIGNS","normalizeVideoAlign","value","align","trim","includes","getVideoAlign","elemNode","textAlign","getVideoAlignClass","videoToHtmlConf","type","elemToHtml","_childrenHtml","editor","src","_c","poster","_d","_e","_f","mode","getTextStyleMode","alignData","containerAttrs","getVideoJustifyContent","res","indexOf","_g","_h","genRandomStr","prefix","nanoid","styleStringToObject","styleString","styleObject","split","forEach","__read","property","genDomID","EditorVideoSizeMenu","this","title","t","tag","showModal","modalWidth","$content","widthInputId","heightInputId","buttonId","prototype","getSelectedVideoNode","DomEditor","getSelectedNodeByType","getValue","_editor","isActive","exec","_value","isDisabled","selection","getModalPositionNode","getModalContentElem","genModalInputElems","widthContainerElem","inputWidthElem","$inputWidth","heightContainerElem","inputHeightElem","$inputHeight","buttonContainerElem","genModalButtonElems","videoNode","$content_1","e","preventDefault","rawWidth","find","rawHeight","isPercentage","test","isNumeric","parseInt","restoreSelection","props","__assign","Transforms","setNodes","match","n","checkNodeType","hidePanelOrModal","setTimeout","Editvideo","iconSvg","srcInputId","posterInputId","_this","srcContainerElem","inputSrcElem","posterContainerElem","inputPosterElem","$inputSrc","$inputPoster","__awaiter","videoId","key","editor_1","src_1","arguments","getMenuConfig","onInsertedVideo","checkVideo","parseVideoSrc","checkRes","sent","alert","parsedSrc","replace","video","children","text","Promise","resolve","then","isSelectedEmptyParagraph","removeNodes","insertNodes","InsertVideoMenu","Range","isCollapsed","getSelectedElems","some","elem","getNodeType","isVoid","EDITOR_TO_UPLOADER_MAP","WeakMap","uploadFile","files","uploader","get","menuConfig","onSuccess","onProgress","onFailed","customInsert","onError","createUploader","progress","showProgressBar","file","errno","data","url","err","set","getUploader","uploadList","map","name","size","addFiles","upload","UploadVideoMenu","allowedFileTypes","customBrowseAndUpload","acceptAttr","join","$body","$inputFile","hide","click","fileList","Array","slice","call","uploadFileList","customUpload","fileList_1","__asyncValues","fileList_1_1","push","uploadVideos","VideoAlignMenu","titleKey","getSelectedVideo","node","genVideoElem","dataAlign","containerStyle","justifyContent","classAlign","classList","filter","Boolean","i","className","startsWith","getClassAlign","legacyStyleAlign","legacyDataAlign","getVideoSizeStyle","parsedStyle","renderElems","renderElem","vnode","containerClassName","selected","isNodeSelected","jsx","innerHTML","videoVnode","controls","h","contentEditable","mousedown","elemsToHtml","preParseHtml","selector","$video","firstChild","firstChildTagName","videoTagName","$container","parseElemsHtml","parseElemHtml","_children","iframeStyleWidth","iframeStyleHeight","videoStyleWidth","videoStyleHeight","menus","factory","config","_node","_src","_poster","server","fieldName","maxFileSize","maxNumberOfFiles","meta","metaWithUrl","withCredentials","timeout","onBeforeUpload","_progress","_file","_res","console","error","EditorVideoSrcMenu","editorPlugin","normalizeNode","newEditor","path","isLastNode","genEmptyParagraph","at"],"mappings":"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"}
@@ -11,7 +11,7 @@ import DOMText = globalThis.Text;
11
11
  import DOMRange = globalThis.Range;
12
12
  import DOMSelection = globalThis.Selection;
13
13
  import DOMStaticRange = globalThis.StaticRange;
14
- export { Dom7Array } from 'dom7';
14
+ export type { Dom7Array } from 'dom7';
15
15
  export default $;
16
16
  /**
17
17
  * 获取 tagName lower-case
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wangeditor-next/video-module",
3
- "version": "4.0.0",
3
+ "version": "6.2.0",
4
4
  "description": "wangEditor video module",
5
5
  "author": "cycleccc <2991205548@qq.com>",
6
6
  "type": "module",
@@ -37,11 +37,11 @@
37
37
  "peerDependencies": {
38
38
  "@uppy/core": "^2.1.4 || ^5.0.0",
39
39
  "@uppy/xhr-upload": "^2.0.7 || ^5.0.0",
40
- "@wangeditor-next/core": ">=1.9.6",
41
40
  "dom7": "^3.0.0 || ^4.0.0",
42
41
  "nanoid": "^5.0.0",
43
42
  "slate": "^0.124.0",
44
- "snabbdom": "^3.6.0"
43
+ "snabbdom": "^3.6.0",
44
+ "@wangeditor-next/core": "^6.2.0"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@wangeditor-next-shared/rollup-config": "^0.0.2"
@@ -1,22 +0,0 @@
1
- /**
2
- * @description image element
3
- * @author wangfupeng
4
- */
5
- type EmptyText = {
6
- text: '';
7
- };
8
- export type ImageStyle = {
9
- width?: string;
10
- height?: string;
11
- };
12
- export type ImageElement = {
13
- type: 'image';
14
- src: string;
15
- alt?: string;
16
- href?: string;
17
- width?: string;
18
- height?: string;
19
- style?: ImageStyle;
20
- children: EmptyText[];
21
- };
22
- export {};
@@ -1,7 +0,0 @@
1
- import { Editor, Span } from 'slate';
2
- import { WithTableOptions } from './options';
3
- /**
4
- * Determines whether two paths belong to the same types by checking
5
- * if they share a common ancestor node of type table
6
- */
7
- export declare function hasCommon(editor: Editor, [path, another]: Span, ...types: Array<keyof WithTableOptions['blocks']>): boolean;
@@ -1,5 +0,0 @@
1
- export * from './has-common';
2
- export * from './is-of-type';
3
- export * from './matrices';
4
- export * from './point';
5
- export * from './types';
@@ -1,6 +0,0 @@
1
- import { Editor, Element, Node, NodeMatch } from 'slate';
2
- import { WithTableOptions } from './options';
3
- import { WithType } from './types';
4
- export declare function isElement<T extends Element>(node: Node): node is WithType<T>;
5
- /** @returns a `NodeMatch` function which is used to match the elements of a specific `type`. */
6
- export declare function isOfType<T extends WithType<Element>>(editor: Editor, ...types: Array<keyof WithTableOptions['blocks']>): NodeMatch<T>;
@@ -1,9 +0,0 @@
1
- import { Editor, Location, NodeEntry } from 'slate';
2
- import { CellElement, NodeEntryWithContext } from './types';
3
- /** Generates a matrix for each table section (`thead`, `tbody`, `tfoot`) */
4
- export declare function matrices(editor: Editor, options?: {
5
- at?: Location;
6
- }): Generator<NodeEntry<CellElement>[][]>;
7
- export declare function filledMatrix(editor: Editor, options?: {
8
- at?: Location;
9
- }): NodeEntryWithContext[][];
@@ -1,25 +0,0 @@
1
- import { CustomTypes, ExtendedType } from 'slate';
2
- type ElementType = ExtendedType<'Element', CustomTypes>['type'];
3
- export interface WithTableOptions {
4
- blocks: {
5
- td: ElementType;
6
- th: ElementType;
7
- content: ElementType;
8
- tr: ElementType;
9
- table: ElementType;
10
- tbody: ElementType;
11
- tfoot: ElementType;
12
- thead: ElementType;
13
- };
14
- }
15
- export declare const DEFAULT_WITH_TABLE_OPTIONS: {
16
- blocks: {
17
- td: string;
18
- th: string;
19
- content: string;
20
- tr: string;
21
- table: string;
22
- tbody: string;
23
- };
24
- };
25
- export {};
@@ -1,7 +0,0 @@
1
- export declare class Point {
2
- x: number;
3
- y: number;
4
- constructor(x: number, y: number);
5
- static valueOf(x: number, y: number): Point;
6
- static equals(point: Point, another: Point): boolean;
7
- }
@@ -1,19 +0,0 @@
1
- import { Element, NodeEntry } from 'slate';
2
- export type CellElement = WithType<{
3
- rowSpan?: number;
4
- colSpan?: number;
5
- hidden?: boolean;
6
- } & Element>;
7
- /** Extends an element with the "type" property */
8
- export type WithType<T extends Element> = T & Record<'type', unknown>;
9
- export type NodeEntryWithContext = [
10
- NodeEntry<CellElement>,
11
- {
12
- rtl: number;
13
- ltr: number;
14
- ttb: number;
15
- btt: number;
16
- }
17
- ];
18
- export type SelectionMode = 'start' | 'end' | 'all';
19
- export type Edge = 'start' | 'end' | 'top' | 'bottom';