@opentiny/fluent-editor 4.1.0 → 4.1.1
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.
- package/es/config/editor.config.es.js +1 -1
- package/es/config/editor.config.es.js.map +1 -1
- package/es/config/i18n/en-us.es.js +4 -1
- package/es/config/i18n/en-us.es.js.map +1 -1
- package/es/config/i18n/zh-cn.es.js +4 -1
- package/es/config/i18n/zh-cn.es.js.map +1 -1
- package/es/core/fluent-editor.es.js +29 -4
- package/es/core/fluent-editor.es.js.map +1 -1
- package/es/fluent-editor.es.js +2 -11
- package/es/fluent-editor.es.js.map +1 -1
- package/es/formats/strike.es.js +1 -1
- package/es/formats/strike.es.js.map +1 -1
- package/es/index.es.js +3 -3
- package/es/index.es.js.map +1 -1
- package/es/modules/counter.es.js +2 -3
- package/es/modules/counter.es.js.map +1 -1
- package/es/modules/custom-clipboard.es.js +13 -1
- package/es/modules/custom-clipboard.es.js.map +1 -1
- package/es/modules/custom-image/blot-formatter.es.js +2 -2
- package/es/modules/custom-image/blot-formatter.es.js.map +1 -1
- package/es/modules/custom-image/index.es.js +1 -1
- package/es/modules/custom-image/preview/preview-modal.es.js +17 -6
- package/es/modules/custom-image/preview/preview-modal.es.js.map +1 -1
- package/es/modules/custom-image/specs/custom-image-spec.es.js.map +1 -1
- package/es/modules/custom-uploader.es.js.map +1 -1
- package/es/modules/file/modules/file-module.es.js.map +1 -1
- package/es/modules/flow-chart/i18n/index.es.js +3 -5
- package/es/modules/flow-chart/i18n/index.es.js.map +1 -1
- package/es/modules/flow-chart/modules/context-menu.es.js +10 -13
- package/es/modules/flow-chart/modules/context-menu.es.js.map +1 -1
- package/es/modules/flow-chart/modules/control-panel.es.js +13 -16
- package/es/modules/flow-chart/modules/control-panel.es.js.map +1 -1
- package/es/modules/index.es.js +2 -2
- package/es/modules/index.es.js.map +1 -1
- package/es/modules/link/modules/tooltip.es.js +42 -27
- package/es/modules/link/modules/tooltip.es.js.map +1 -1
- package/es/modules/mind-map/i18n/index.es.js +3 -5
- package/es/modules/mind-map/i18n/index.es.js.map +1 -1
- package/es/modules/mind-map/modules/context-menu.es.js +11 -11
- package/es/modules/mind-map/modules/context-menu.es.js.map +1 -1
- package/es/modules/mind-map/modules/control-panel.es.js +7 -9
- package/es/modules/mind-map/modules/control-panel.es.js.map +1 -1
- package/es/modules/shortcut-key/index.es.js +6 -6
- package/es/modules/shortcut-key/index.es.js.map +1 -1
- package/es/modules/table-up/index.es.js +23 -33
- package/es/modules/table-up/index.es.js.map +1 -1
- package/es/modules/toolbar/toolbar-tip.es.js +27 -5
- package/es/modules/toolbar/toolbar-tip.es.js.map +1 -1
- package/es/themes/snow.es.js +2 -2
- package/es/themes/snow.es.js.map +1 -1
- package/lib/config/editor.config.cjs.js +1 -1
- package/lib/config/editor.config.cjs.js.map +1 -1
- package/lib/config/i18n/en-us.cjs.js +4 -1
- package/lib/config/i18n/en-us.cjs.js.map +1 -1
- package/lib/config/i18n/zh-cn.cjs.js +4 -1
- package/lib/config/i18n/zh-cn.cjs.js.map +1 -1
- package/lib/core/fluent-editor.cjs.js +29 -4
- package/lib/core/fluent-editor.cjs.js.map +1 -1
- package/lib/fluent-editor.cjs.js +2 -11
- package/lib/fluent-editor.cjs.js.map +1 -1
- package/lib/formats/strike.cjs.js +1 -1
- package/lib/formats/strike.cjs.js.map +1 -1
- package/lib/index.cjs.js +16 -5
- package/lib/index.cjs.js.map +1 -1
- package/lib/modules/counter.cjs.js +2 -3
- package/lib/modules/counter.cjs.js.map +1 -1
- package/lib/modules/custom-clipboard.cjs.js +13 -1
- package/lib/modules/custom-clipboard.cjs.js.map +1 -1
- package/lib/modules/custom-image/blot-formatter.cjs.js +2 -2
- package/lib/modules/custom-image/blot-formatter.cjs.js.map +1 -1
- package/lib/modules/custom-image/index.cjs.js +1 -1
- package/lib/modules/custom-image/preview/preview-modal.cjs.js +17 -6
- package/lib/modules/custom-image/preview/preview-modal.cjs.js.map +1 -1
- package/lib/modules/custom-image/specs/custom-image-spec.cjs.js.map +1 -1
- package/lib/modules/custom-uploader.cjs.js.map +1 -1
- package/lib/modules/file/modules/file-module.cjs.js.map +1 -1
- package/lib/modules/flow-chart/i18n/index.cjs.js +3 -5
- package/lib/modules/flow-chart/i18n/index.cjs.js.map +1 -1
- package/lib/modules/flow-chart/modules/context-menu.cjs.js +10 -13
- package/lib/modules/flow-chart/modules/context-menu.cjs.js.map +1 -1
- package/lib/modules/flow-chart/modules/control-panel.cjs.js +13 -16
- package/lib/modules/flow-chart/modules/control-panel.cjs.js.map +1 -1
- package/lib/modules/index.cjs.js +14 -2
- package/lib/modules/index.cjs.js.map +1 -1
- package/lib/modules/link/modules/tooltip.cjs.js +42 -27
- package/lib/modules/link/modules/tooltip.cjs.js.map +1 -1
- package/lib/modules/mind-map/i18n/index.cjs.js +3 -5
- package/lib/modules/mind-map/i18n/index.cjs.js.map +1 -1
- package/lib/modules/mind-map/modules/context-menu.cjs.js +11 -11
- package/lib/modules/mind-map/modules/context-menu.cjs.js.map +1 -1
- package/lib/modules/mind-map/modules/control-panel.cjs.js +7 -9
- package/lib/modules/mind-map/modules/control-panel.cjs.js.map +1 -1
- package/lib/modules/shortcut-key/index.cjs.js +4 -4
- package/lib/modules/shortcut-key/index.cjs.js.map +1 -1
- package/lib/modules/table-up/index.cjs.js +23 -33
- package/lib/modules/table-up/index.cjs.js.map +1 -1
- package/lib/modules/toolbar/toolbar-tip.cjs.js +26 -4
- package/lib/modules/toolbar/toolbar-tip.cjs.js.map +1 -1
- package/lib/themes/snow.cjs.js +2 -2
- package/lib/themes/snow.cjs.js.map +1 -1
- package/package.json +3 -2
- package/style.css +149 -144
- package/types/config/editor.config.d.ts +4 -2
- package/types/config/i18n/en-us.d.ts +4 -1
- package/types/config/i18n/zh-cn.d.ts +4 -1
- package/types/config/types/editor-modules.interface.d.ts +3 -2
- package/types/core/fluent-editor.d.ts +1 -1
- package/types/modules/custom-clipboard.d.ts +2 -0
- package/types/modules/custom-image/index.d.ts +1 -1
- package/types/modules/custom-image/preview/preview-modal.d.ts +1 -0
- package/types/modules/flow-chart/i18n/index.d.ts +1 -1
- package/types/modules/index.d.ts +2 -1
- package/types/modules/link/modules/tooltip.d.ts +1 -0
- package/types/modules/mind-map/i18n/index.d.ts +1 -1
- package/types/modules/table-up/index.d.ts +3 -26
- package/es/modules/i18n.es.js +0 -62
- package/es/modules/i18n.es.js.map +0 -1
- package/lib/modules/i18n.cjs.js +0 -62
- package/lib/modules/i18n.cjs.js.map +0 -1
- package/types/modules/i18n.d.ts +0 -14
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fluent-editor.cjs.js","sources":["../../../src/core/fluent-editor.ts"],"sourcesContent":["import type { ExpandedQuillOptions } from 'quill'\nimport type { IEditorConfig } from '../config/types'\nimport type { FileUploader } from '../modules/custom-uploader'\nimport Quill from 'quill'\nimport { defaultLanguage } from '../config'\nimport
|
|
1
|
+
{"version":3,"file":"fluent-editor.cjs.js","sources":["../../../src/core/fluent-editor.ts"],"sourcesContent":["import type { ExpandedQuillOptions } from 'quill'\nimport type { I18n, I18nOptions } from 'quill-i18n'\nimport type { IEditorConfig } from '../config/types'\nimport type { FileUploader } from '../modules/custom-uploader'\nimport Quill from 'quill'\nimport { defaultLanguage } from '../config'\nimport { EN_US } from '../config/i18n/en-us'\nimport { ZH_CN } from '../config/i18n/zh-cn'\nimport { merge } from '../utils/merge'\n\n// Temporary backward-compat syntax support: `_i18n\"key\"`\n// TODO: remove this legacy syntax support in a future major version.\nconst LEGACY_I18N_KEY_REGEX = /^_i18n(?:\"([^\"]+)\"|'([^']+)'|`([^`]+)`)$/\n\nfunction resolveLegacyI18nKey(name: string): string {\n const key = name.trim()\n const matched = key.match(LEGACY_I18N_KEY_REGEX)\n if (!matched) return name\n return matched[1] || matched[2] || matched[3] || name\n}\n\nclass FluentEditor extends Quill {\n isFullscreen: boolean = false\n declare options: IEditorConfig & ExpandedQuillOptions\n declare uploader: FileUploader\n\n static register(...args: any[]): void {\n super.register(...args as Parameters<typeof Quill.register>)\n }\n\n get lang() {\n const i18nModule = this.getModule('i18n') as I18n\n return i18nModule ? i18nModule.getLocale() : defaultLanguage\n }\n\n constructor(container: HTMLElement | string, options: IEditorConfig = {}) {\n if (!options.modules) options.modules = {}\n if (!options.modules.i18n) options.modules.i18n = {}\n\n const i18nOptions = options.modules.i18n as I18nOptions\n const defaultMessages = {\n 'en-US': EN_US,\n 'zh-CN': ZH_CN,\n }\n const userMessages = i18nOptions.messages || {}\n i18nOptions.messages = merge({}, defaultMessages, userMessages)\n\n if (!i18nOptions.interpolate) {\n i18nOptions.interpolate = (template: string, params: Record<string, any>) => {\n return template.replaceAll(/\\{\\{([\\w]+)\\}\\}/g, (match, key) => params[key] != null ? String(params[key]) : match)\n }\n }\n\n super(container, options)\n }\n\n getLangText(name: string, params?: Record<string, any>, defaultValue?: string) {\n const i18nModule = this.getModule('i18n') as I18n\n if (!i18nModule) return name\n return i18nModule.t(resolveLegacyI18nKey(name), params, defaultValue)\n }\n}\n\nexport default FluentEditor\n"],"names":["EN_US","ZH_CN","merge","defaultLanguage"],"mappings":";;;;;;;;;;;AAYA,MAAM,wBAAwB;AAE9B,SAAS,qBAAqB,MAAsB;AAClD,QAAM,MAAM,KAAK,KAAA;AACjB,QAAM,UAAU,IAAI,MAAM,qBAAqB;AAC/C,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,QAAQ,CAAC,KAAK,QAAQ,CAAC,KAAK,QAAQ,CAAC,KAAK;AACnD;AAEA,MAAM,qBAAqB,MAAM;AAAA,EAc/B,YAAY,WAAiC,UAAyB,IAAI;AACxE,QAAI,CAAC,QAAQ,QAAS,SAAQ,UAAU,CAAA;AACxC,QAAI,CAAC,QAAQ,QAAQ,KAAM,SAAQ,QAAQ,OAAO,CAAA;AAElD,UAAM,cAAc,QAAQ,QAAQ;AACpC,UAAM,kBAAkB;AAAA,MACtB,SAASA,KAAAA;AAAAA,MACT,SAASC,KAAAA;AAAAA,IAAA;AAEX,UAAM,eAAe,YAAY,YAAY,CAAA;AAC7C,gBAAY,WAAWC,MAAAA,MAAM,CAAA,GAAI,iBAAiB,YAAY;AAE9D,QAAI,CAAC,YAAY,aAAa;AAC5B,kBAAY,cAAc,CAAC,UAAkB,WAAgC;AAC3E,eAAO,SAAS,WAAW,oBAAoB,CAAC,OAAO,QAAQ,OAAO,GAAG,KAAK,OAAO,OAAO,OAAO,GAAG,CAAC,IAAI,KAAK;AAAA,MAClH;AAAA,IACF;AAEA,UAAM,WAAW,OAAO;AA/B1B,wCAAwB;AAAA,EAgCxB;AAAA,EA5BA,OAAO,YAAY,MAAmB;AACpC,UAAM,SAAS,GAAG,IAAyC;AAAA,EAC7D;AAAA,EAEA,IAAI,OAAO;AACT,UAAM,aAAa,KAAK,UAAU,MAAM;AACxC,WAAO,aAAa,WAAW,UAAA,IAAcC,cAAAA;AAAAA,EAC/C;AAAA,EAuBA,YAAY,MAAc,QAA8B,cAAuB;AAC7E,UAAM,aAAa,KAAK,UAAU,MAAM;AACxC,QAAI,CAAC,WAAY,QAAO;AACxB,WAAO,WAAW,EAAE,qBAAqB,IAAI,GAAG,QAAQ,YAAY;AAAA,EACtE;AACF;;"}
|
package/lib/fluent-editor.cjs.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
|
+
const I18n = require("quill-i18n");
|
|
3
4
|
require("./attributors/index.cjs.js");
|
|
4
|
-
const enUs = require("./config/i18n/en-us.cjs.js");
|
|
5
|
-
const zhCn = require("./config/i18n/zh-cn.cjs.js");
|
|
6
5
|
const fluentEditor = require("./core/fluent-editor.cjs.js");
|
|
7
6
|
require("./formats/index.cjs.js");
|
|
8
7
|
const index$3 = require("./modules/ai/index.cjs.js");
|
|
@@ -14,7 +13,6 @@ const divider = require("./modules/divider.cjs.js");
|
|
|
14
13
|
const emoji = require("./modules/emoji.cjs.js");
|
|
15
14
|
require("./modules/file/index.cjs.js");
|
|
16
15
|
const index = require("./modules/flow-chart/index.cjs.js");
|
|
17
|
-
const i18n = require("./modules/i18n.cjs.js");
|
|
18
16
|
require("./modules/link/index.cjs.js");
|
|
19
17
|
require("./modules/mathlive/index.cjs.js");
|
|
20
18
|
require("./modules/mention/index.cjs.js");
|
|
@@ -39,13 +37,6 @@ const emoji$1 = require("./formats/emoji.cjs.js");
|
|
|
39
37
|
const fontSize = require("./attributors/font-size.cjs.js");
|
|
40
38
|
const lineHeight = require("./attributors/line-height.cjs.js");
|
|
41
39
|
const fontStyle = require("./attributors/font-style.cjs.js");
|
|
42
|
-
i18n.I18N.register(
|
|
43
|
-
{
|
|
44
|
-
"en-US": enUs.EN_US,
|
|
45
|
-
"zh-CN": zhCn.ZH_CN
|
|
46
|
-
},
|
|
47
|
-
true
|
|
48
|
-
);
|
|
49
40
|
fluentEditor.default.register(
|
|
50
41
|
{
|
|
51
42
|
"attributors/style/font": fontStyle.FontStyle,
|
|
@@ -65,7 +56,7 @@ fluentEditor.default.register(
|
|
|
65
56
|
"modules/counter": counter.default,
|
|
66
57
|
"modules/emoji": emoji.EmojiModule,
|
|
67
58
|
"modules/file": fileModule.FileModule,
|
|
68
|
-
"modules/i18n":
|
|
59
|
+
"modules/i18n": I18n,
|
|
69
60
|
"modules/image": blotFormatter.BlotFormatter,
|
|
70
61
|
"modules/mathlive": module$1.MathliveModule,
|
|
71
62
|
"modules/ai": index$3.AI,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fluent-editor.cjs.js","sources":["../../src/fluent-editor.ts"],"sourcesContent":["import { FontStyle, LineHeightStyle, SizeStyle, TextIndentStyle } from './attributors'\nimport
|
|
1
|
+
{"version":3,"file":"fluent-editor.cjs.js","sources":["../../src/fluent-editor.ts"],"sourcesContent":["import I18n from 'quill-i18n'\nimport { FontStyle, LineHeightStyle, SizeStyle, TextIndentStyle } from './attributors'\nimport FluentEditor from './core/fluent-editor'\nimport { EmojiBlot, SoftBreak, StrikeBlot, Video } from './formats'\nimport { AI } from './modules/ai' // AI\nimport Counter from './modules/counter' // 字符统计\nimport { CustomClipboard } from './modules/custom-clipboard' // 粘贴板\nimport { BlotFormatter } from './modules/custom-image' // 图片\nimport { FileUploader } from './modules/custom-uploader' // 上传\nimport { DividerBlot } from './modules/divider' // 分割线\nimport { EmojiModule } from './modules/emoji'\nimport { FileModule } from './modules/file' // 文件\nimport { FlowChartModule } from './modules/flow-chart' // 流程图\nimport { LinkBlot } from './modules/link' // 超链接\nimport { MathliveModule } from './modules/mathlive' // latex公式\nimport { Mention } from './modules/mention' // @提醒\nimport { MindMapModule } from './modules/mind-map' // 思维导图\nimport { ShortCutKey } from './modules/shortcut-key'\nimport Syntax from './modules/syntax' // 代码块高亮\nimport { BetterToolbar } from './modules/toolbar' // 工具栏\nimport { ColorPicker, Picker } from './modules/toolbar/better-picker'\nimport SnowTheme from './themes/snow'\nimport Icons from './ui/icons'\n\nFluentEditor.register(\n {\n 'attributors/style/font': FontStyle,\n 'attributors/style/size': SizeStyle,\n 'attributors/style/line-height': LineHeightStyle,\n\n 'formats/font': FontStyle,\n 'formats/line-height': LineHeightStyle,\n 'formats/size': SizeStyle,\n 'formats/emoji': EmojiBlot,\n 'formats/softBreak': SoftBreak,\n 'formats/strike': StrikeBlot,\n 'formats/text-indent': TextIndentStyle,\n 'formats/video': Video,\n 'formats/divider': DividerBlot,\n 'formats/link': LinkBlot,\n\n 'modules/clipboard': CustomClipboard,\n 'modules/counter': Counter,\n 'modules/emoji': EmojiModule,\n 'modules/file': FileModule,\n 'modules/i18n': I18n,\n 'modules/image': BlotFormatter,\n 'modules/mathlive': MathliveModule,\n 'modules/ai': AI,\n 'modules/mention': Mention,\n 'modules/syntax': Syntax,\n 'modules/toolbar': BetterToolbar,\n 'modules/uploader': FileUploader,\n 'modules/shortcut-key': ShortCutKey,\n 'modules/mind-map': MindMapModule,\n 'modules/flow-chart': FlowChartModule,\n\n 'themes/snow': SnowTheme,\n\n 'ui/icons': Icons,\n 'ui/picker': Picker,\n 'ui/color-picker': ColorPicker,\n },\n true, // 覆盖内部模块\n)\n\nexport default FluentEditor\n"],"names":["FluentEditor","FontStyle","SizeStyle","LineHeightStyle","EmojiBlot","SoftBreak","StrikeBlot","TextIndentStyle","Video","DividerBlot","LinkBlot","CustomClipboard","Counter","EmojiModule","FileModule","BlotFormatter","MathliveModule","AI","Mention","Syntax","BetterToolbar","FileUploader","ShortCutKey","MindMapModule","FlowChartModule","SnowTheme","Icons","Picker","ColorPicker"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwBAA,aAAAA,QAAa;AAAA,EACX;AAAA,IACE,0BAA0BC,UAAAA;AAAAA,IAC1B,0BAA0BC,SAAAA;AAAAA,IAC1B,iCAAiCC,WAAAA;AAAAA,IAEjC,gBAAgBF,UAAAA;AAAAA,IAChB,uBAAuBE,WAAAA;AAAAA,IACvB,gBAAgBD,SAAAA;AAAAA,IAChB,iBAAiBE,QAAAA;AAAAA,IACjB,qBAAqBC,UAAAA;AAAAA,IACrB,kBAAkBC,OAAAA;AAAAA,IAClB,uBAAuBC,WAAAA;AAAAA,IACvB,iBAAiBC,MAAAA;AAAAA,IACjB,mBAAmBC,QAAAA;AAAAA,IACnB,gBAAgBC,KAAAA;AAAAA,IAEhB,qBAAqBC,gBAAAA;AAAAA,IACrB,mBAAmBC,QAAAA;AAAAA,IACnB,iBAAiBC,MAAAA;AAAAA,IACjB,gBAAgBC,WAAAA;AAAAA,IAChB,gBAAgB;AAAA,IAChB,iBAAiBC,cAAAA;AAAAA,IACjB,oBAAoBC,SAAAA;AAAAA,IACpB,cAAcC,QAAAA;AAAAA,IACd,mBAAmBC,QAAAA;AAAAA,IACnB,kBAAkBC,OAAAA;AAAAA,IAClB,mBAAmBC,cAAAA;AAAAA,IACnB,oBAAoBC,eAAAA;AAAAA,IACpB,wBAAwBC,QAAAA;AAAAA,IACxB,oBAAoBC,QAAAA;AAAAA,IACpB,sBAAsBC,MAAAA;AAAAA,IAEtB,eAAeC,KAAAA;AAAAA,IAEf,YAAYC,MAAAA;AAAAA,IACZ,aAAaC,aAAAA;AAAAA,IACb,mBAAmBC,aAAAA;AAAAA,EAAA;AAAA,EAErB;AAAA;AACF;;"}
|
|
@@ -9,7 +9,7 @@ class StrikeBlot extends Inline {
|
|
|
9
9
|
// 此处删除了formats方法,当前tag非span,则并不需要进行特殊处理去重写formats方法
|
|
10
10
|
}
|
|
11
11
|
__publicField(StrikeBlot, "blotName", "strike");
|
|
12
|
-
__publicField(StrikeBlot, "tagName", "
|
|
12
|
+
__publicField(StrikeBlot, "tagName", "s");
|
|
13
13
|
__publicField(StrikeBlot, "className", "ql-custom-strike");
|
|
14
14
|
exports.StrikeBlot = StrikeBlot;
|
|
15
15
|
//# sourceMappingURL=strike.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"strike.cjs.js","sources":["../../../src/formats/strike.ts"],"sourcesContent":["import type TypeInline from 'quill/blots/inline'\nimport Quill from 'quill'\n\nconst Inline = Quill.import('blots/inline') as typeof TypeInline\n\nexport class StrikeBlot extends Inline {\n static blotName = 'strike'\n static tagName = '
|
|
1
|
+
{"version":3,"file":"strike.cjs.js","sources":["../../../src/formats/strike.ts"],"sourcesContent":["import type TypeInline from 'quill/blots/inline'\nimport Quill from 'quill'\n\nconst Inline = Quill.import('blots/inline') as typeof TypeInline\n\nexport class StrikeBlot extends Inline {\n static blotName = 'strike'\n static tagName = 's'\n static className = 'ql-custom-strike'\n // 此处删除了formats方法,当前tag非span,则并不需要进行特殊处理去重写formats方法\n}\n"],"names":[],"mappings":";;;;;;AAGA,MAAM,SAAS,MAAM,OAAO,cAAc;AAEnC,MAAM,mBAAmB,OAAO;AAAA;AAKvC;AAJE,cADW,YACJ,YAAW;AAClB,cAFW,YAEJ,WAAU;AACjB,cAHW,YAGJ,aAAY;;"}
|
package/lib/index.cjs.js
CHANGED
|
@@ -28,10 +28,10 @@ const toolbar = require("./modules/custom-image/actions/toolbar.cjs.js");
|
|
|
28
28
|
const toolbarAction = require("./modules/custom-image/actions/toolbar-action.cjs.js");
|
|
29
29
|
const blotFormatter = require("./modules/custom-image/blot-formatter.cjs.js");
|
|
30
30
|
const image = require("./modules/custom-image/image.cjs.js");
|
|
31
|
+
const previewModal = require("./modules/custom-image/preview/preview-modal.cjs.js");
|
|
31
32
|
const blotSpec = require("./modules/custom-image/specs/blot-spec.cjs.js");
|
|
32
33
|
const customImageSpec = require("./modules/custom-image/specs/custom-image-spec.cjs.js");
|
|
33
34
|
const imageSpec = require("./modules/custom-image/specs/image-spec.cjs.js");
|
|
34
|
-
const previewModal = require("./modules/custom-image/preview/preview-modal.cjs.js");
|
|
35
35
|
const customUploader = require("./modules/custom-uploader.cjs.js");
|
|
36
36
|
const divider = require("./modules/divider.cjs.js");
|
|
37
37
|
const emoji$1 = require("./modules/emoji.cjs.js");
|
|
@@ -39,7 +39,6 @@ const file = require("./modules/file/formats/file.cjs.js");
|
|
|
39
39
|
const fileBar = require("./modules/file/modules/file-bar.cjs.js");
|
|
40
40
|
const fileModule = require("./modules/file/modules/file-module.cjs.js");
|
|
41
41
|
const index$1 = require("./modules/flow-chart/index.cjs.js");
|
|
42
|
-
const i18n = require("./modules/i18n.cjs.js");
|
|
43
42
|
const link = require("./modules/link/formats/link.cjs.js");
|
|
44
43
|
const tooltip = require("./modules/link/modules/tooltip.cjs.js");
|
|
45
44
|
const formats = require("./modules/mathlive/formats.cjs.js");
|
|
@@ -53,6 +52,7 @@ const index$4 = require("./modules/table-up/index.cjs.js");
|
|
|
53
52
|
const betterPicker = require("./modules/toolbar/better-picker.cjs.js");
|
|
54
53
|
const betterToolbar = require("./modules/toolbar/better-toolbar.cjs.js");
|
|
55
54
|
const toolbarTip = require("./modules/toolbar/toolbar-tip.cjs.js");
|
|
55
|
+
const I18n = require("quill-i18n");
|
|
56
56
|
exports.getListValue = index.getListValue;
|
|
57
57
|
exports.inputFile = index.inputFile;
|
|
58
58
|
exports.namespace = index.namespace;
|
|
@@ -130,11 +130,11 @@ exports.ImageToolbar = toolbar.ImageToolbar;
|
|
|
130
130
|
exports.ImageToolbarAction = toolbarAction.ImageToolbarAction;
|
|
131
131
|
exports.BlotFormatter = blotFormatter.BlotFormatter;
|
|
132
132
|
exports.CustomImage = image.CustomImage;
|
|
133
|
+
exports.ImagePreviewModal = previewModal.ImagePreviewModal;
|
|
134
|
+
exports.getImagePreviewModal = previewModal.getImagePreviewModal;
|
|
133
135
|
exports.BlotSpec = blotSpec.BlotSpec;
|
|
134
136
|
exports.CustomImageSpec = customImageSpec.CustomImageSpec;
|
|
135
137
|
exports.ImageSpec = imageSpec.ImageSpec;
|
|
136
|
-
exports.ImagePreviewModal = previewModal.ImagePreviewModal;
|
|
137
|
-
exports.getImagePreviewModal = previewModal.getImagePreviewModal;
|
|
138
138
|
exports.FileUploader = customUploader.FileUploader;
|
|
139
139
|
exports.DividerBlot = divider.DividerBlot;
|
|
140
140
|
exports.EmojiModule = emoji$1.EmojiModule;
|
|
@@ -142,7 +142,6 @@ exports.File = file.File;
|
|
|
142
142
|
exports.FileBar = fileBar.FileBar;
|
|
143
143
|
exports.FileModule = fileModule.FileModule;
|
|
144
144
|
exports.FlowChartModule = index$1.FlowChartModule;
|
|
145
|
-
exports.I18N = i18n.I18N;
|
|
146
145
|
exports.LinkBlot = link.LinkBlot;
|
|
147
146
|
exports.LinkTooltip = tooltip.LinkTooltip;
|
|
148
147
|
exports.MathliveBlot = formats.MathliveBlot;
|
|
@@ -158,4 +157,16 @@ exports.ColorPicker = betterPicker.ColorPicker;
|
|
|
158
157
|
exports.Picker = betterPicker.Picker;
|
|
159
158
|
exports.BetterToolbar = betterToolbar.BetterToolbar;
|
|
160
159
|
exports.generateToolbarTip = toolbarTip.generateToolbarTip;
|
|
160
|
+
Object.keys(QuillShortcutKey).forEach((k) => {
|
|
161
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
162
|
+
enumerable: true,
|
|
163
|
+
get: () => QuillShortcutKey[k]
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
Object.keys(I18n).forEach((k) => {
|
|
167
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
168
|
+
enumerable: true,
|
|
169
|
+
get: () => I18n[k]
|
|
170
|
+
});
|
|
171
|
+
});
|
|
161
172
|
//# sourceMappingURL=index.cjs.js.map
|
package/lib/index.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -4,8 +4,7 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
|
|
|
4
4
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
5
|
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
6
6
|
const Quill = require("quill");
|
|
7
|
-
require("
|
|
8
|
-
const editor_config = require("../config/editor.config.cjs.js");
|
|
7
|
+
const I18n = require("quill-i18n");
|
|
9
8
|
class Counter {
|
|
10
9
|
constructor(quill, options) {
|
|
11
10
|
__publicField(this, "container");
|
|
@@ -37,7 +36,7 @@ class Counter {
|
|
|
37
36
|
this.options = this.resolveOptions(options);
|
|
38
37
|
this.container = quill.addContainer("ql-counter");
|
|
39
38
|
quill.on(Quill.events.TEXT_CHANGE, this.renderCount);
|
|
40
|
-
this.quill.
|
|
39
|
+
this.quill.on(I18n.I18N_LOCALE_CHANGE, () => {
|
|
41
40
|
this.options = this.resolveOptions(options);
|
|
42
41
|
this.renderCount();
|
|
43
42
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"counter.cjs.js","sources":["../../../src/modules/counter.ts"],"sourcesContent":["import type { AnyFunction } from '../config'\nimport type FluentEditor from '../fluent-editor'\nimport Quill from 'quill'\nimport {
|
|
1
|
+
{"version":3,"file":"counter.cjs.js","sources":["../../../src/modules/counter.ts"],"sourcesContent":["import type { AnyFunction } from '../config'\nimport type FluentEditor from '../fluent-editor'\nimport Quill from 'quill'\nimport { I18N_LOCALE_CHANGE } from 'quill-i18n'\n\nexport interface ICounterOption {\n format?: 'text' | 'html'\n unit?: 'word' | 'char'\n count?: number\n template?: string | AnyFunction\n errorTemplate?: string | AnyFunction\n}\n\nexport default class Counter {\n container: HTMLDivElement\n options: ICounterOption\n\n constructor(public quill: FluentEditor, options: ICounterOption) {\n this.options = this.resolveOptions(options)\n this.container = quill.addContainer('ql-counter')\n quill.on(Quill.events.TEXT_CHANGE, this.renderCount)\n this.quill.on(I18N_LOCALE_CHANGE, () => {\n this.options = this.resolveOptions(options)\n this.renderCount()\n })\n this.renderCount()\n }\n\n resolveOptions(options: ICounterOption) {\n return Object.assign({\n format: 'text',\n unit: 'char',\n template: this.quill.getLangText('counter-template'),\n count: 500,\n }, options)\n }\n\n renderCount = () => {\n setTimeout(() => {\n // @ts-ignore\n const { format, count: totalCount, unit, template: counterTemplate, errorTemplate } = this.options\n const count = this.getContentLength(format)\n const restCount = totalCount - count\n const countUnit = unit === 'char' ? this.quill.getLangText('char') : this.quill.getLangText('word')\n let template: any = counterTemplate\n if (typeof template === 'function') {\n template = template(count, restCount)\n }\n const desc = template.replace('{{count}}', count)\n .replace('{{totalCount}}', String(totalCount))\n .replace('{{restCount}}', String(restCount))\n .replace(/{{countUnit}}/g, countUnit)\n\n let limitTemplate: any = errorTemplate || this.quill.getLangText('counter-limit-tips')\n if (typeof limitTemplate === 'function') {\n limitTemplate = limitTemplate(count, restCount)\n }\n const limitTips = limitTemplate.replace('{{countUnit}}', countUnit)\n if (restCount < 0) {\n this.container.innerHTML = errorTemplate ? limitTips : `<span style=\"color:red\">${limitTips}</span>`\n }\n else {\n this.container.innerHTML = desc\n }\n })\n }\n\n getContentLength(format) {\n let content = this.quill.getText()\n if (format === 'html') {\n let html = this.quill.root.innerHTML\n // 编辑器初始时\n if (html === '<p><br></p>' || html === '<div><br><div>') {\n html = ''\n }\n content = html\n }\n const text = content.replace(/\\s/g, '').trim()\n if (this.options.unit === 'word') {\n return !content.trim() ? 0 : content.trim().split(/\\s+/).length\n }\n return text.length\n }\n}\n"],"names":["I18N_LOCALE_CHANGE"],"mappings":";;;;;;;AAaA,MAAqB,QAAQ;AAAA,EAI3B,YAAmB,OAAqB,SAAyB;AAHjE;AACA;AAsBA,uCAAc,MAAM;AAClB,iBAAW,MAAM;AAEf,cAAM,EAAE,QAAQ,OAAO,YAAY,MAAM,UAAU,iBAAiB,kBAAkB,KAAK;AAC3F,cAAM,QAAQ,KAAK,iBAAiB,MAAM;AAC1C,cAAM,YAAY,aAAa;AAC/B,cAAM,YAAY,SAAS,SAAS,KAAK,MAAM,YAAY,MAAM,IAAI,KAAK,MAAM,YAAY,MAAM;AAClG,YAAI,WAAgB;AACpB,YAAI,OAAO,aAAa,YAAY;AAClC,qBAAW,SAAS,OAAO,SAAS;AAAA,QACtC;AACA,cAAM,OAAO,SAAS,QAAQ,aAAa,KAAK,EAC7C,QAAQ,kBAAkB,OAAO,UAAU,CAAC,EAC5C,QAAQ,iBAAiB,OAAO,SAAS,CAAC,EAC1C,QAAQ,kBAAkB,SAAS;AAEtC,YAAI,gBAAqB,iBAAiB,KAAK,MAAM,YAAY,oBAAoB;AACrF,YAAI,OAAO,kBAAkB,YAAY;AACvC,0BAAgB,cAAc,OAAO,SAAS;AAAA,QAChD;AACA,cAAM,YAAY,cAAc,QAAQ,iBAAiB,SAAS;AAClE,YAAI,YAAY,GAAG;AACjB,eAAK,UAAU,YAAY,gBAAgB,YAAY,2BAA2B,SAAS;AAAA,QAC7F,OACK;AACH,eAAK,UAAU,YAAY;AAAA,QAC7B;AAAA,MACF,CAAC;AAAA,IACH;AAhDmB,SAAA,QAAA;AACjB,SAAK,UAAU,KAAK,eAAe,OAAO;AAC1C,SAAK,YAAY,MAAM,aAAa,YAAY;AAChD,UAAM,GAAG,MAAM,OAAO,aAAa,KAAK,WAAW;AACnD,SAAK,MAAM,GAAGA,KAAAA,oBAAoB,MAAM;AACtC,WAAK,UAAU,KAAK,eAAe,OAAO;AAC1C,WAAK,YAAA;AAAA,IACP,CAAC;AACD,SAAK,YAAA;AAAA,EACP;AAAA,EAEA,eAAe,SAAyB;AACtC,WAAO,OAAO,OAAO;AAAA,MACnB,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,UAAU,KAAK,MAAM,YAAY,kBAAkB;AAAA,MACnD,OAAO;AAAA,IAAA,GACN,OAAO;AAAA,EACZ;AAAA,EAgCA,iBAAiB,QAAQ;AACvB,QAAI,UAAU,KAAK,MAAM,QAAA;AACzB,QAAI,WAAW,QAAQ;AACrB,UAAI,OAAO,KAAK,MAAM,KAAK;AAE3B,UAAI,SAAS,iBAAiB,SAAS,kBAAkB;AACvD,eAAO;AAAA,MACT;AACA,gBAAU;AAAA,IACZ;AACA,UAAM,OAAO,QAAQ,QAAQ,OAAO,EAAE,EAAE,KAAA;AACxC,QAAI,KAAK,QAAQ,SAAS,QAAQ;AAChC,aAAO,CAAC,QAAQ,KAAA,IAAS,IAAI,QAAQ,OAAO,MAAM,KAAK,EAAE;AAAA,IAC3D;AACA,WAAO,KAAK;AAAA,EACd;AACF;;"}
|
|
@@ -8,6 +8,17 @@ const is = require("../utils/is.cjs.js");
|
|
|
8
8
|
const Clipboard = Quill.import("modules/clipboard");
|
|
9
9
|
const Delta = Quill.import("delta");
|
|
10
10
|
class CustomClipboard extends Clipboard {
|
|
11
|
+
constructor(quill) {
|
|
12
|
+
super(quill);
|
|
13
|
+
this.quill = quill;
|
|
14
|
+
this.quill.root.addEventListener("input", () => {
|
|
15
|
+
if (this.quill.root.innerText !== "\\n" && this.quill.root.classList.contains("ql-blank")) {
|
|
16
|
+
this.quill.root.classList.toggle("ql-blank", false);
|
|
17
|
+
} else {
|
|
18
|
+
this.quill.options.placeholder = this.quill.getLangText("editor-placeholder");
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
11
22
|
prepareMatching(container, nodeMatches) {
|
|
12
23
|
const elementMatchers = [];
|
|
13
24
|
const textMatchers = [];
|
|
@@ -191,7 +202,8 @@ class CustomClipboard extends Clipboard {
|
|
|
191
202
|
});
|
|
192
203
|
} else {
|
|
193
204
|
const range = this.getImgSelection(pastedDelta, imageIndexs[index]);
|
|
194
|
-
this.quill.uploader.
|
|
205
|
+
const urls = await this.quill.uploader.getFileUrls([imageFile], range);
|
|
206
|
+
return urls[0] || void 0;
|
|
195
207
|
}
|
|
196
208
|
})
|
|
197
209
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"custom-clipboard.cjs.js","sources":["../../../src/modules/custom-clipboard.ts"],"sourcesContent":["import type TypeClipboard from 'quill/modules/clipboard'\nimport type FluentEditor from '../fluent-editor'\nimport Quill from 'quill'\nimport {\n ERROR_IMAGE_PLACEHOLDER_CN,\n ERROR_IMAGE_PLACEHOLDER_EN,\n} from '../config/base64-image'\nimport { BIG_DELTA_LIMIT } from '../config/editor.config'\nimport {\n hexToRgbA,\n imageUrlToFile,\n isNullOrUndefined,\n omit,\n replaceDeltaImage,\n splitWithBreak,\n} from '../config/editor.utils'\nimport { isString } from '../utils/is'\n\nconst Clipboard = Quill.import('modules/clipboard') as typeof TypeClipboard\nconst Delta = Quill.import('delta')\n\nexport class CustomClipboard extends Clipboard {\n declare quill: FluentEditor\n\n prepareMatching(container: HTMLElement, nodeMatches) {\n const elementMatchers = []\n const textMatchers = []\n this.matchers.forEach((pair) => {\n const [selector, matcher] = pair\n if (selector === Node.TEXT_NODE) {\n textMatchers.push(matcher)\n }\n else if (selector === Node.ELEMENT_NODE) {\n elementMatchers.push(matcher)\n }\n else if (isString(selector)) {\n // word 的 v:shape 系列标签只能通过 getElementsByTagName 获取\n const vRegex = /v:(.+)/\n const nodeList = Array.from(\n vRegex.test(selector)\n ? container.getElementsByTagName(selector)\n : container.querySelectorAll(selector),\n )\n nodeList.forEach((node) => {\n if (nodeMatches.has(node)) {\n const matches = nodeMatches.get(node)\n matches.push(matcher)\n }\n else {\n nodeMatches.set(node, [matcher])\n }\n })\n }\n })\n return [elementMatchers, textMatchers]\n }\n\n onCaptureCopy(e, isCut = false) {\n if (e.defaultPrevented) {\n return\n }\n e.preventDefault()\n const [range] = this.quill.selection.getRange()\n if (isNullOrUndefined(range)) {\n return\n }\n const { html, text } = this.onCopy(range, isCut)\n\n // 兼容IE11浏览器`\n if (!e.clipboardData) {\n e.clipboardData = {\n types: 'text/plain',\n setData: (_type, value) => {\n // @ts-ignore\n return window.clipboardData.setData('Text', value)\n },\n }\n }\n\n // 复制代码时移除utf8中产生的不间断空格\\u00A0\n let plainText = text\n if (html.startsWith('<pre>')) {\n plainText = text.replace(/\\u00A0/g, ' ')\n }\n\n e.clipboardData.setData('text/html', html)\n e.clipboardData.setData('text/plain', plainText)\n if (isCut) {\n this.quill.deleteText(range, Quill.sources.USER)\n }\n }\n\n onCapturePaste(e: ClipboardEvent) {\n if (e.defaultPrevented || !this.quill.isEnabled()) {\n return\n }\n e.preventDefault()\n const range = this.quill.getSelection(true)\n if (isNullOrUndefined(range)) {\n return\n }\n\n // 兼容IE11浏览器\n if (!e.clipboardData) {\n // @ts-ignore\n e.clipboardData = {\n types: 'text/plain',\n getData: () => {\n // @ts-ignore\n return window.clipboardData.getData('Text')\n },\n }\n }\n\n const html = e.clipboardData.getData('text/html')\n const text = e.clipboardData.getData('text/plain')\n const files = Array.from(e.clipboardData.files || [])\n const msExcelCheck = /<meta.*?Microsoft Excel\\s[\\d].*?>/\n\n if (html.search(msExcelCheck) === -1 && files.length > 0) {\n this.quill.uploader.upload(range, files)\n }\n else {\n const msWordCheck1\n = /<meta\\s*name=\"?generator\"?\\s*content=\"?microsoft\\s*word\\s*\\d+\"?\\/?>/i\n const msWordCheck2 = /xmlns:o=\"urn:schemas-microsoft-com/i\n const result = { html, text, files, rtf: null }\n if (html.search(msExcelCheck) !== -1) {\n result.html = renderStyles(html)\n }\n if (msWordCheck1.test(html) || msWordCheck2.test(html)) {\n // TODO: 当word文档包含heading时text/rtf读取为空,无法获取hex图片,待修复。可参考ckeditor5/issues/2493\n result.rtf = e.clipboardData.getData('text/rtf')\n }\n this.onPaste(range, result)\n }\n }\n\n onPaste(range, { html, text, files: clipboardFiles, rtf }) {\n const hexImages = this.extractImageDataFromRtf(rtf)\n const rootBgColor = getComputedStyle(this.quill.root).backgroundColor\n const formats = this.quill.getFormat(range.index)\n let pastedDelta = this.convert({ text, html }, formats)\n pastedDelta = replaceDeltaWhiteSpace(pastedDelta, rootBgColor)\n const deltaLength = pastedDelta.ops.length\n\n let loadingTipsContainer\n if (deltaLength > BIG_DELTA_LIMIT) {\n loadingTipsContainer = this.quill.addContainer('ql-loading-tips')\n loadingTipsContainer.innerHTML = this.quill.getLangText('pasting')\n }\n\n const linePos = { index: range.index, length: range.length, fix: 0 }\n const [line, offset] = this.quill.getLine(range.index)\n\n const handlePasteContent = (content: any) => {\n const pastedContent = content\n\n const oldDelta = new Delta().retain(linePos.index).delete(linePos.length)\n const delta = oldDelta.concat(pastedContent)\n\n setTimeout(() => {\n this.quill.updateContents(delta, Quill.sources.USER)\n // 光标位置应该在粘贴内容之后:原光标位置 + 粘贴内容长度\n const newSelectionIndex = linePos.index + (pastedContent.length ? pastedContent.length() : 0)\n this.quill.setSelection(\n newSelectionIndex,\n Quill.sources.SILENT,\n )\n this.quill.scrollSelectionIntoView()\n if (loadingTipsContainer) {\n loadingTipsContainer.remove()\n }\n })\n }\n\n ;(async () => {\n try {\n const [files, placeholders, originalUrls, imageIndexs] = this.flipFilesArray(\n await this.extractFilesFromDelta(\n pastedDelta,\n clipboardFiles,\n hexImages,\n ),\n )\n\n if (files.length === 0) {\n handlePasteContent(pastedDelta)\n }\n else {\n if (this.quill.options.editorPaste && this.quill.options.editorPaste.observers.length !== 0) {\n // 设置editorPaste回调的情况\n this.quill.options.editorPaste.emit({\n files,\n callback: ({ code, message, data }) => {\n if (code === 0) {\n const { imageUrls } = data\n pastedDelta = replaceDeltaImage(\n pastedDelta,\n imageUrls,\n placeholders,\n )\n handlePasteContent(pastedDelta)\n }\n else {\n console.error('error message:', message)\n }\n },\n })\n }\n else {\n // 没有originalUrls 也没有文件粘贴\n if (files[0] !== undefined || originalUrls.length === 0) {\n // 没有设置editorPaste回调的情况下,File格式的占位图需要手动转换成url格式,插入到编辑器中\n const imageUrls = await this.files2urls(\n files,\n placeholders,\n originalUrls,\n pastedDelta,\n imageIndexs,\n )\n pastedDelta = replaceDeltaImage(\n pastedDelta,\n imageUrls,\n placeholders,\n )\n }\n handlePasteContent(pastedDelta)\n }\n }\n }\n catch (_e) {\n throw new Error('Paste failed.')\n }\n })()\n }\n\n files2urls(files: File[], placeholders, originalUrls, pastedDelta, imageIndexs) {\n return Promise.all(\n files.map(async (imageFile, index) => {\n const netImgExp = /^((http|https)\\:)?\\/\\/([\\s\\S]+)$/\n if (\n !placeholders[index]\n && originalUrls[index]\n && netImgExp.test(originalUrls[index])\n ) {\n // 不是占位图的普通url图片直接返回url\n return new Promise((resolve) => {\n resolve(originalUrls[index])\n })\n }\n else {\n const range = this.getImgSelection(pastedDelta, imageIndexs[index])\n this.quill.uploader.upload(range, [imageFile])\n }\n }),\n )\n }\n\n flipFilesArray(filesArr) {\n const files = []\n const placeholders = []\n const originalUrls = []\n const imageIndexs = []\n filesArr.forEach((item: any) => {\n if (item) {\n const [file, placeholder, originalUrl, imageIndex] = item\n files.push(file)\n placeholders.push(placeholder)\n originalUrls.push(originalUrl)\n if (imageIndex === 0 || imageIndex) {\n imageIndexs.push(imageIndex)\n }\n }\n })\n return [files, placeholders, originalUrls, imageIndexs]\n }\n\n // 将图片从hex转为base64\n convertHexToBase64(hexString) {\n return btoa(\n hexString\n .match(/\\w{2}/g)\n .map((char) => {\n return String.fromCharCode(Number.parseInt(char, 16))\n })\n .join(''),\n )\n }\n\n // 匹配rtf中的图片,存储为{hex, type}对象数组\n extractImageDataFromRtf(rtfData) {\n if (!rtfData) {\n return []\n }\n\n const regexPictureHeader\n = /{\\\\pict[\\s\\S]+?\\\\bliptag-?\\d+(\\\\blipupi-?\\d+)?({\\\\\\*\\\\blipuid\\s?[\\da-fA-F]+)?[\\s}]*?/\n const regexPicture = new RegExp(\n `(?:(${regexPictureHeader.source}))([\\\\da-fA-F\\\\s]+)\\\\}`,\n 'g',\n )\n const images = rtfData.match(regexPicture)\n const result = []\n\n if (images) {\n for (const image of images) {\n let imageType = ''\n\n if (image.includes('\\\\pngblip')) {\n imageType = 'image/png'\n }\n else if (image.includes('\\\\jpegblip')) {\n imageType = 'image/jpeg'\n }\n\n if (imageType) {\n result.push({\n hex: image\n .replace(regexPictureHeader, '')\n .replace(/[^\\da-fA-F]/g, ''),\n type: imageType,\n })\n }\n }\n }\n\n return result\n }\n\n extractFilesFromDelta(delta, clipboardFiles, hexImages?) {\n let index = -1\n return Promise.all(\n delta.map(async (op) => {\n index++\n const image = op.insert.image\n if (!image || image.hasExisted) {\n return\n }\n\n let file\n let isPlaceholderImage = false\n let imageIndex\n try {\n // hex 图片存在则为 file:/// 协议本地图片,使用 hex 图片转为 base64 读取\n const hexImage = hexImages.length && hexImages.shift()\n const newImage\n = hexImage\n && `data:${hexImage.type};base64,${this.convertHexToBase64(\n hexImage.hex,\n )}`\n imageIndex = index\n file = await imageUrlToFile(newImage || image.src || image)\n }\n catch (_err) {\n if (clipboardFiles.length !== 0) {\n // 跨域获取图片失败时从剪切板获取图片\n const clipboardFile = clipboardFiles[0]\n const imageType\n = clipboardFile.type?.indexOf('image') === -1\n ? 'image/png'\n : clipboardFile.type\n const blob = clipboardFile.slice(0, clipboardFile.size, imageType)\n file = new File([blob], `image-CORS-${new Date().getTime()}.png`, {\n type: imageType,\n })\n }\n else if (image.src.startsWith('http')) {\n // 什么都不做\n }\n else {\n // 剪切板中无图片,用失败占位图替换\n const errorImagePlaceholderJpg\n = this.quill.getLangText('img-error') === 'Image Copy Error'\n ? ERROR_IMAGE_PLACEHOLDER_EN\n : ERROR_IMAGE_PLACEHOLDER_CN\n file = await imageUrlToFile(errorImagePlaceholderJpg, true)\n isPlaceholderImage = true\n }\n }\n\n return [file, isPlaceholderImage, image, imageIndex]\n }),\n )\n }\n\n getImgSelection(delta, imageIndex) {\n let length = 0\n delta.ops.every((op, index) => {\n if (index === imageIndex) {\n return false\n }\n if (typeof op.insert === 'string') {\n length += op.insert.length\n }\n else if (typeof op.insert === 'object') {\n // 对于图片、提及等对象类型的 insert,长度为 1\n length += 1\n }\n return true\n })\n const range = {\n index: length,\n length: 0,\n }\n return range\n }\n}\n\nfunction rebuildDelta(delta, cellLine) {\n const { cell: cellId, colspan, row: rowId, rowspan } = cellLine\n const buildedDelta = delta.reduce((newDelta, op) => {\n if (op.insert && typeof op.insert === 'string') {\n const lines = splitWithBreak(op.insert)\n\n lines.forEach((text) => {\n if (text === '\\n') {\n // 对换行增加 table-cell-line 格式,以避免表格断开\n newDelta.insert('\\n', {\n ...op.attributes,\n 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan },\n })\n }\n else {\n text = text.endsWith('\\r') ? text.slice(0, -1) : text\n newDelta.insert(\n text,\n omit(op.attributes, ['table', 'table-cell-line']),\n )\n }\n })\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n\n return newDelta\n }, new Delta())\n\n return buildedDelta\n}\n\nfunction replaceStrWhiteSpace(str) {\n const isWhiteSpace = value => /^(\\u3000|\\u0020){1}$/.test(value) // 空白字符\n let textWithWhiteSpace = ''\n let beginHasChar = false\n for (const char of str) {\n if (isWhiteSpace(char) && !beginHasChar) {\n textWithWhiteSpace += '\\u00A0'\n }\n else {\n textWithWhiteSpace += char\n beginHasChar = true\n }\n }\n return textWithWhiteSpace\n}\n\nfunction replaceDeltaWhiteSpace(delta, rootBgColor?) {\n return delta.reduce((newDelta, op) => {\n // fix: 当粘贴文字颜色和编辑器背景色一致且自身无背景色的情况下移除文字颜色样式,避免误导用户粘贴无效\n if (\n rootBgColor\n && op.attributes\n && op.attributes.color\n && !op.attributes.background\n ) {\n const originColor = op.attributes.color\n const fontColor\n = originColor.indexOf('#') === 0 ? hexToRgbA(originColor) : originColor\n if (\n fontColor === rootBgColor\n || (fontColor === 'rgba(255,255,255,1)'\n && rootBgColor === 'rgba(0, 0, 0, 0)')\n ) {\n delete op.attributes.color\n }\n }\n if (op.insert && typeof op.insert === 'string') {\n const lines = splitWithBreak(op.insert)\n let insertWithWhiteSpace = ''\n lines.forEach((text) => {\n insertWithWhiteSpace += replaceStrWhiteSpace(text)\n })\n newDelta.insert(insertWithWhiteSpace, op.attributes)\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n return newDelta\n }, new Delta())\n}\n\nfunction renderStyles(html) {\n let htmlString = html\n // Trim unnecessary parts.\n htmlString = htmlString.substring(\n htmlString.indexOf('<html '),\n htmlString.length,\n )\n htmlString = htmlString.substring(\n 0,\n htmlString.lastIndexOf('</html>') + '</html>'.length,\n )\n\n // Add temporary iframe.\n const iframe = document.createElement('iframe')\n iframe.style.display = 'none'\n document.body.appendChild(iframe)\n\n const iframeDoc = iframe.contentDocument || iframe.contentWindow.document\n iframeDoc.open()\n iframeDoc.write(htmlString)\n iframeDoc.close()\n\n let collection\n let pointer\n const rules\n = iframeDoc.styleSheets[iframeDoc.styleSheets.length - 1].cssRules\n\n // Convert internal styles to inline style of respective node.\n for (let idx = 0; idx < rules.length; idx++) {\n if ((rules[idx] as CSSStyleRule).selectorText === '') {\n continue\n }\n collection = iframeDoc.body.querySelectorAll(\n (rules[idx] as CSSStyleRule).selectorText,\n )\n\n for (pointer = 0; pointer < collection.length; pointer++) {\n collection[pointer].style.cssText += (\n rules[idx] as CSSStyleRule\n ).style.cssText\n }\n }\n\n // @ts-ignore\n const convertedString = iframeDoc.firstChild.outerHTML\n // Remove temporary iframe.\n iframe.parentNode.removeChild(iframe)\n\n return convertedString\n}\n"],"names":["isString","isNullOrUndefined","BIG_DELTA_LIMIT","replaceDeltaImage","imageUrlToFile","ERROR_IMAGE_PLACEHOLDER_EN","ERROR_IMAGE_PLACEHOLDER_CN","splitWithBreak","omit","hexToRgbA"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"custom-clipboard.cjs.js","sources":["../../../src/modules/custom-clipboard.ts"],"sourcesContent":["import type TypeClipboard from 'quill/modules/clipboard'\nimport type FluentEditor from '../fluent-editor'\nimport Quill from 'quill'\nimport {\n ERROR_IMAGE_PLACEHOLDER_CN,\n ERROR_IMAGE_PLACEHOLDER_EN,\n} from '../config/base64-image'\nimport { BIG_DELTA_LIMIT } from '../config/editor.config'\nimport {\n hexToRgbA,\n imageUrlToFile,\n isNullOrUndefined,\n omit,\n replaceDeltaImage,\n splitWithBreak,\n} from '../config/editor.utils'\nimport { isString } from '../utils/is'\n\nconst Clipboard = Quill.import('modules/clipboard') as typeof TypeClipboard\nconst Delta = Quill.import('delta')\n\nexport class CustomClipboard extends Clipboard {\n declare quill: FluentEditor\n\n constructor(public quill: FluentEditor) {\n super(quill)\n // 解决 quill 组件在中文输入法的情景下开始输入placeholder不消失的问题\n this.quill.root.addEventListener('input', () => {\n if (this.quill.root.innerText !== '\\\\n' && this.quill.root.classList.contains('ql-blank')) {\n this.quill.root.classList.toggle('ql-blank', false)\n }\n else {\n this.quill.options.placeholder = this.quill.getLangText('editor-placeholder')\n }\n })\n }\n\n prepareMatching(container: HTMLElement, nodeMatches) {\n const elementMatchers = []\n const textMatchers = []\n this.matchers.forEach((pair) => {\n const [selector, matcher] = pair\n if (selector === Node.TEXT_NODE) {\n textMatchers.push(matcher)\n }\n else if (selector === Node.ELEMENT_NODE) {\n elementMatchers.push(matcher)\n }\n else if (isString(selector)) {\n // word 的 v:shape 系列标签只能通过 getElementsByTagName 获取\n const vRegex = /v:(.+)/\n const nodeList = Array.from(\n vRegex.test(selector)\n ? container.getElementsByTagName(selector)\n : container.querySelectorAll(selector),\n )\n nodeList.forEach((node) => {\n if (nodeMatches.has(node)) {\n const matches = nodeMatches.get(node)\n matches.push(matcher)\n }\n else {\n nodeMatches.set(node, [matcher])\n }\n })\n }\n })\n return [elementMatchers, textMatchers]\n }\n\n onCaptureCopy(e, isCut = false) {\n if (e.defaultPrevented) {\n return\n }\n e.preventDefault()\n const [range] = this.quill.selection.getRange()\n if (isNullOrUndefined(range)) {\n return\n }\n const { html, text } = this.onCopy(range, isCut)\n\n // 兼容IE11浏览器`\n if (!e.clipboardData) {\n e.clipboardData = {\n types: 'text/plain',\n setData: (_type, value) => {\n // @ts-ignore\n return window.clipboardData.setData('Text', value)\n },\n }\n }\n\n // 复制代码时移除utf8中产生的不间断空格\\u00A0\n let plainText = text\n if (html.startsWith('<pre>')) {\n plainText = text.replace(/\\u00A0/g, ' ')\n }\n\n e.clipboardData.setData('text/html', html)\n e.clipboardData.setData('text/plain', plainText)\n if (isCut) {\n this.quill.deleteText(range, Quill.sources.USER)\n }\n }\n\n onCapturePaste(e: ClipboardEvent) {\n if (e.defaultPrevented || !this.quill.isEnabled()) {\n return\n }\n e.preventDefault()\n const range = this.quill.getSelection(true)\n if (isNullOrUndefined(range)) {\n return\n }\n\n // 兼容IE11浏览器\n if (!e.clipboardData) {\n // @ts-ignore\n e.clipboardData = {\n types: 'text/plain',\n getData: () => {\n // @ts-ignore\n return window.clipboardData.getData('Text')\n },\n }\n }\n\n const html = e.clipboardData.getData('text/html')\n const text = e.clipboardData.getData('text/plain')\n const files = Array.from(e.clipboardData.files || [])\n const msExcelCheck = /<meta.*?Microsoft Excel\\s[\\d].*?>/\n\n if (html.search(msExcelCheck) === -1 && files.length > 0) {\n this.quill.uploader.upload(range, files)\n }\n else {\n const msWordCheck1\n = /<meta\\s*name=\"?generator\"?\\s*content=\"?microsoft\\s*word\\s*\\d+\"?\\/?>/i\n const msWordCheck2 = /xmlns:o=\"urn:schemas-microsoft-com/i\n const result = { html, text, files, rtf: null }\n if (html.search(msExcelCheck) !== -1) {\n result.html = renderStyles(html)\n }\n if (msWordCheck1.test(html) || msWordCheck2.test(html)) {\n // TODO: 当word文档包含heading时text/rtf读取为空,无法获取hex图片,待修复。可参考ckeditor5/issues/2493\n result.rtf = e.clipboardData.getData('text/rtf')\n }\n this.onPaste(range, result)\n }\n }\n\n onPaste(range, { html, text, files: clipboardFiles, rtf }) {\n const hexImages = this.extractImageDataFromRtf(rtf)\n const rootBgColor = getComputedStyle(this.quill.root).backgroundColor\n const formats = this.quill.getFormat(range.index)\n let pastedDelta = this.convert({ text, html }, formats)\n pastedDelta = replaceDeltaWhiteSpace(pastedDelta, rootBgColor)\n const deltaLength = pastedDelta.ops.length\n\n let loadingTipsContainer\n if (deltaLength > BIG_DELTA_LIMIT) {\n loadingTipsContainer = this.quill.addContainer('ql-loading-tips')\n loadingTipsContainer.innerHTML = this.quill.getLangText('pasting')\n }\n\n const linePos = { index: range.index, length: range.length, fix: 0 }\n const [line, offset] = this.quill.getLine(range.index)\n\n const handlePasteContent = (content: any) => {\n const pastedContent = content\n\n const oldDelta = new Delta().retain(linePos.index).delete(linePos.length)\n const delta = oldDelta.concat(pastedContent)\n\n setTimeout(() => {\n this.quill.updateContents(delta, Quill.sources.USER)\n // 光标位置应该在粘贴内容之后:原光标位置 + 粘贴内容长度\n const newSelectionIndex = linePos.index + (pastedContent.length ? pastedContent.length() : 0)\n this.quill.setSelection(\n newSelectionIndex,\n Quill.sources.SILENT,\n )\n this.quill.scrollSelectionIntoView()\n if (loadingTipsContainer) {\n loadingTipsContainer.remove()\n }\n })\n }\n\n ;(async () => {\n try {\n const [files, placeholders, originalUrls, imageIndexs] = this.flipFilesArray(\n await this.extractFilesFromDelta(\n pastedDelta,\n clipboardFiles,\n hexImages,\n ),\n )\n\n if (files.length === 0) {\n handlePasteContent(pastedDelta)\n }\n else {\n if (this.quill.options.editorPaste && this.quill.options.editorPaste.observers.length !== 0) {\n // 设置editorPaste回调的情况\n this.quill.options.editorPaste.emit({\n files,\n callback: ({ code, message, data }) => {\n if (code === 0) {\n const { imageUrls } = data\n pastedDelta = replaceDeltaImage(\n pastedDelta,\n imageUrls,\n placeholders,\n )\n handlePasteContent(pastedDelta)\n }\n else {\n console.error('error message:', message)\n }\n },\n })\n }\n else {\n // 没有originalUrls 也没有文件粘贴\n if (files[0] !== undefined || originalUrls.length === 0) {\n // 没有设置editorPaste回调的情况下,File格式的占位图需要手动转换成url格式,插入到编辑器中\n const imageUrls = await this.files2urls(\n files,\n placeholders,\n originalUrls,\n pastedDelta,\n imageIndexs,\n )\n pastedDelta = replaceDeltaImage(\n pastedDelta,\n imageUrls,\n placeholders,\n )\n }\n handlePasteContent(pastedDelta)\n }\n }\n }\n catch (_e) {\n throw new Error('Paste failed.')\n }\n })()\n }\n\n files2urls(files: File[], placeholders, originalUrls, pastedDelta, imageIndexs) {\n return Promise.all(\n files.map(async (imageFile, index) => {\n const netImgExp = /^((http|https)\\:)?\\/\\/([\\s\\S]+)$/\n if (\n !placeholders[index]\n && originalUrls[index]\n && netImgExp.test(originalUrls[index])\n ) {\n // 不是占位图的普通url图片直接返回url\n return new Promise((resolve) => {\n resolve(originalUrls[index])\n })\n }\n else {\n const range = this.getImgSelection(pastedDelta, imageIndexs[index])\n const urls = await this.quill.uploader.getFileUrls([imageFile], range)\n return urls[0] || undefined\n }\n }),\n )\n }\n\n flipFilesArray(filesArr) {\n const files = []\n const placeholders = []\n const originalUrls = []\n const imageIndexs = []\n filesArr.forEach((item: any) => {\n if (item) {\n const [file, placeholder, originalUrl, imageIndex] = item\n files.push(file)\n placeholders.push(placeholder)\n originalUrls.push(originalUrl)\n if (imageIndex === 0 || imageIndex) {\n imageIndexs.push(imageIndex)\n }\n }\n })\n return [files, placeholders, originalUrls, imageIndexs]\n }\n\n // 将图片从hex转为base64\n convertHexToBase64(hexString) {\n return btoa(\n hexString\n .match(/\\w{2}/g)\n .map((char) => {\n return String.fromCharCode(Number.parseInt(char, 16))\n })\n .join(''),\n )\n }\n\n // 匹配rtf中的图片,存储为{hex, type}对象数组\n extractImageDataFromRtf(rtfData) {\n if (!rtfData) {\n return []\n }\n\n const regexPictureHeader\n = /{\\\\pict[\\s\\S]+?\\\\bliptag-?\\d+(\\\\blipupi-?\\d+)?({\\\\\\*\\\\blipuid\\s?[\\da-fA-F]+)?[\\s}]*?/\n const regexPicture = new RegExp(\n `(?:(${regexPictureHeader.source}))([\\\\da-fA-F\\\\s]+)\\\\}`,\n 'g',\n )\n const images = rtfData.match(regexPicture)\n const result = []\n\n if (images) {\n for (const image of images) {\n let imageType = ''\n\n if (image.includes('\\\\pngblip')) {\n imageType = 'image/png'\n }\n else if (image.includes('\\\\jpegblip')) {\n imageType = 'image/jpeg'\n }\n\n if (imageType) {\n result.push({\n hex: image\n .replace(regexPictureHeader, '')\n .replace(/[^\\da-fA-F]/g, ''),\n type: imageType,\n })\n }\n }\n }\n\n return result\n }\n\n extractFilesFromDelta(delta, clipboardFiles, hexImages?) {\n let index = -1\n return Promise.all(\n delta.map(async (op) => {\n index++\n const image = op.insert.image\n if (!image || image.hasExisted) {\n return\n }\n\n let file\n let isPlaceholderImage = false\n let imageIndex\n try {\n // hex 图片存在则为 file:/// 协议本地图片,使用 hex 图片转为 base64 读取\n const hexImage = hexImages.length && hexImages.shift()\n const newImage\n = hexImage\n && `data:${hexImage.type};base64,${this.convertHexToBase64(\n hexImage.hex,\n )}`\n imageIndex = index\n file = await imageUrlToFile(newImage || image.src || image)\n }\n catch (_err) {\n if (clipboardFiles.length !== 0) {\n // 跨域获取图片失败时从剪切板获取图片\n const clipboardFile = clipboardFiles[0]\n const imageType\n = clipboardFile.type?.indexOf('image') === -1\n ? 'image/png'\n : clipboardFile.type\n const blob = clipboardFile.slice(0, clipboardFile.size, imageType)\n file = new File([blob], `image-CORS-${new Date().getTime()}.png`, {\n type: imageType,\n })\n }\n else if (image.src.startsWith('http')) {\n // 什么都不做\n }\n else {\n // 剪切板中无图片,用失败占位图替换\n const errorImagePlaceholderJpg\n = this.quill.getLangText('img-error') === 'Image Copy Error'\n ? ERROR_IMAGE_PLACEHOLDER_EN\n : ERROR_IMAGE_PLACEHOLDER_CN\n file = await imageUrlToFile(errorImagePlaceholderJpg, true)\n isPlaceholderImage = true\n }\n }\n\n return [file, isPlaceholderImage, image, imageIndex]\n }),\n )\n }\n\n getImgSelection(delta, imageIndex) {\n let length = 0\n delta.ops.every((op, index) => {\n if (index === imageIndex) {\n return false\n }\n if (typeof op.insert === 'string') {\n length += op.insert.length\n }\n else if (typeof op.insert === 'object') {\n // 对于图片、提及等对象类型的 insert,长度为 1\n length += 1\n }\n return true\n })\n const range = {\n index: length,\n length: 0,\n }\n return range\n }\n}\n\nfunction rebuildDelta(delta, cellLine) {\n const { cell: cellId, colspan, row: rowId, rowspan } = cellLine\n const buildedDelta = delta.reduce((newDelta, op) => {\n if (op.insert && typeof op.insert === 'string') {\n const lines = splitWithBreak(op.insert)\n\n lines.forEach((text) => {\n if (text === '\\n') {\n // 对换行增加 table-cell-line 格式,以避免表格断开\n newDelta.insert('\\n', {\n ...op.attributes,\n 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan },\n })\n }\n else {\n text = text.endsWith('\\r') ? text.slice(0, -1) : text\n newDelta.insert(\n text,\n omit(op.attributes, ['table', 'table-cell-line']),\n )\n }\n })\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n\n return newDelta\n }, new Delta())\n\n return buildedDelta\n}\n\nfunction replaceStrWhiteSpace(str) {\n const isWhiteSpace = value => /^(\\u3000|\\u0020){1}$/.test(value) // 空白字符\n let textWithWhiteSpace = ''\n let beginHasChar = false\n for (const char of str) {\n if (isWhiteSpace(char) && !beginHasChar) {\n textWithWhiteSpace += '\\u00A0'\n }\n else {\n textWithWhiteSpace += char\n beginHasChar = true\n }\n }\n return textWithWhiteSpace\n}\n\nfunction replaceDeltaWhiteSpace(delta, rootBgColor?) {\n return delta.reduce((newDelta, op) => {\n // fix: 当粘贴文字颜色和编辑器背景色一致且自身无背景色的情况下移除文字颜色样式,避免误导用户粘贴无效\n if (\n rootBgColor\n && op.attributes\n && op.attributes.color\n && !op.attributes.background\n ) {\n const originColor = op.attributes.color\n const fontColor\n = originColor.indexOf('#') === 0 ? hexToRgbA(originColor) : originColor\n if (\n fontColor === rootBgColor\n || (fontColor === 'rgba(255,255,255,1)'\n && rootBgColor === 'rgba(0, 0, 0, 0)')\n ) {\n delete op.attributes.color\n }\n }\n if (op.insert && typeof op.insert === 'string') {\n const lines = splitWithBreak(op.insert)\n let insertWithWhiteSpace = ''\n lines.forEach((text) => {\n insertWithWhiteSpace += replaceStrWhiteSpace(text)\n })\n newDelta.insert(insertWithWhiteSpace, op.attributes)\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n return newDelta\n }, new Delta())\n}\n\nfunction renderStyles(html) {\n let htmlString = html\n // Trim unnecessary parts.\n htmlString = htmlString.substring(\n htmlString.indexOf('<html '),\n htmlString.length,\n )\n htmlString = htmlString.substring(\n 0,\n htmlString.lastIndexOf('</html>') + '</html>'.length,\n )\n\n // Add temporary iframe.\n const iframe = document.createElement('iframe')\n iframe.style.display = 'none'\n document.body.appendChild(iframe)\n\n const iframeDoc = iframe.contentDocument || iframe.contentWindow.document\n iframeDoc.open()\n iframeDoc.write(htmlString)\n iframeDoc.close()\n\n let collection\n let pointer\n const rules\n = iframeDoc.styleSheets[iframeDoc.styleSheets.length - 1].cssRules\n\n // Convert internal styles to inline style of respective node.\n for (let idx = 0; idx < rules.length; idx++) {\n if ((rules[idx] as CSSStyleRule).selectorText === '') {\n continue\n }\n collection = iframeDoc.body.querySelectorAll(\n (rules[idx] as CSSStyleRule).selectorText,\n )\n\n for (pointer = 0; pointer < collection.length; pointer++) {\n collection[pointer].style.cssText += (\n rules[idx] as CSSStyleRule\n ).style.cssText\n }\n }\n\n // @ts-ignore\n const convertedString = iframeDoc.firstChild.outerHTML\n // Remove temporary iframe.\n iframe.parentNode.removeChild(iframe)\n\n return convertedString\n}\n"],"names":["isString","isNullOrUndefined","BIG_DELTA_LIMIT","replaceDeltaImage","imageUrlToFile","ERROR_IMAGE_PLACEHOLDER_EN","ERROR_IMAGE_PLACEHOLDER_CN","splitWithBreak","omit","hexToRgbA"],"mappings":"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"}
|
|
@@ -117,8 +117,8 @@ class BlotFormatter {
|
|
|
117
117
|
display: "block",
|
|
118
118
|
left: `${specRect.left - parentRect.left - 1 + parent.scrollLeft}px`,
|
|
119
119
|
top: `${specRect.top - parentRect.top + parent.scrollTop}px`,
|
|
120
|
-
width: `${specRect.width}px`,
|
|
121
|
-
height: `${specRect.height}px`
|
|
120
|
+
width: `${Math.min(specRect.width, parentRect.width)}px`,
|
|
121
|
+
height: `${Math.min(specRect.height, parentRect.height)}px`
|
|
122
122
|
});
|
|
123
123
|
}
|
|
124
124
|
setUserSelect(value) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blot-formatter.cjs.js","sources":["../../../../src/modules/custom-image/blot-formatter.ts"],"sourcesContent":["import type FluentEditor from '../../core/fluent-editor'\nimport type { Action } from './actions'\nimport type { BlotFormatterOptions } from './options'\nimport type { BlotSpec } from './specs'\nimport Quill from 'quill'\nimport { merge as deepmerge } from '../../utils/merge'\nimport { CustomImage } from './image'\nimport DefaultOptions from './options'\nimport { CustomImageSpec } from './specs'\n\nconst dontMerge = (_destination: Array<any>, source: Array<any>) => source\n\nexport class BlotFormatter {\n options: BlotFormatterOptions\n currentSpec: BlotSpec\n specs: BlotSpec[]\n overlay: HTMLElement\n actions: Action[]\n observer: MutationObserver\n\n static register() {\n Quill.register({\n 'formats/image': CustomImage,\n 'modules/image-spec': CustomImageSpec,\n }, true)\n }\n\n constructor(public quill: FluentEditor, options: Partial<BlotFormatterOptions> = {}) {\n this.options = deepmerge({}, DefaultOptions, options, { arrayMerge: dontMerge })\n if (options.allowInvalidUrl !== undefined) {\n this.options.allowInvalidUrl = options.allowInvalidUrl\n }\n CustomImage.setOptions(this.options.allowInvalidUrl)\n this.currentSpec = null\n this.actions = []\n this.overlay = document.createElement('div')\n this.overlay.classList.add(this.options.overlay.className)\n if (this.options.overlay.style) {\n Object.assign(this.overlay.style, this.options.overlay.style)\n }\n\n // disable native image resizing on firefox\n document.execCommand('enableObjectResizing', false, 'false') // eslint-disable-next-line-line no-undef\n this.quill.root.addEventListener('click', this.onClick)\n this.specs = this.options.specs.map((SpecClass: any) => new SpecClass(this))\n this.specs.forEach(spec => spec.init())\n }\n\n show(spec: BlotSpec) {\n this.currentSpec = spec\n this.currentSpec.setSelection()\n this.setUserSelect('none')\n this.quill.root.parentNode.appendChild(this.overlay)\n this.repositionOverlay()\n this.createActions(spec)\n\n // fix: 图片对齐之后,虚线外框应该跟随移动\n const imageDom = spec.getTargetElement()\n const win: any = window\n const MutationObserver: typeof window.MutationObserver = win.MutationObserver || win.WebKitMutationObserver || win.MozMutationObserver\n const element = imageDom.parentNode\n this.observer = new MutationObserver((mutationList) => {\n for (const mutation of mutationList) {\n const target = mutation.target as HTMLElement\n const image = target.querySelector('img')\n if (image) {\n this.repositionOverlay()\n }\n }\n })\n this.observer.observe(element, {\n attributes: true,\n attributeFilter: ['class'],\n attributeOldValue: true,\n subtree: true,\n })\n }\n\n hide() {\n if (!this.currentSpec) {\n return\n }\n\n const imgDom = this.currentSpec.getTargetElement()\n if (imgDom) {\n imgDom.classList.remove('current-select-img')\n }\n\n this.currentSpec.onHide()\n this.currentSpec = null\n this.quill.root.parentNode.removeChild(this.overlay)\n this.overlay.style.setProperty('display', 'none')\n this.setUserSelect('')\n this.destroyActions()\n }\n\n update() {\n this.repositionOverlay()\n this.actions.forEach(action => action.onUpdate())\n }\n\n createActions(spec: BlotSpec) {\n this.actions = spec.getActions().map((ActionClass: any) => {\n const action: Action = new ActionClass(this)\n action.onCreate()\n return action\n })\n }\n\n destroyActions() {\n this.actions.forEach((action: Action) => action.onDestroy())\n this.actions = []\n }\n\n repositionOverlay() {\n if (!this.currentSpec) {\n return\n }\n\n const overlayTarget = this.currentSpec.getOverlayElement()\n if (!overlayTarget) {\n return\n }\n\n const parent = this.quill.root.parentElement\n const specRect = overlayTarget.getBoundingClientRect()\n const parentRect = parent.getBoundingClientRect()\n\n Object.assign(this.overlay.style, {\n display: 'block',\n left: `${specRect.left - parentRect.left - 1 + parent.scrollLeft}px`,\n top: `${specRect.top - parentRect.top + parent.scrollTop}px`,\n width: `${specRect.width}px`,\n height: `${specRect.height}px`,\n })\n }\n\n setUserSelect(value: string) {\n const props: string[] = [\n 'userSelect',\n 'mozUserSelect',\n 'webkitUserSelect',\n 'msUserSelect',\n ]\n\n props.forEach((prop: string) => {\n // set on contenteditable element and <html>\n this.quill.root.style.setProperty(prop, value)\n if (document.documentElement) {\n document.documentElement.style.setProperty(prop, value)\n }\n })\n }\n\n onClick = () => {\n this.hide()\n }\n}\n"],"names":["options","deepmerge","DefaultOptions","CustomImage","CustomImageSpec","image"],"mappings":";;;;;;;;;;;AAUA,MAAM,YAAY,CAAC,cAA0B,WAAuB;AAE7D,MAAM,cAAc;AAAA,EAezB,YAAmB,OAAqBA,YAAyC,IAAI;AAdrF;AACA;AACA;AACA;AACA;AACA;AAwIA,mCAAU,MAAM;AACd,WAAK,KAAA;AAAA,IACP;AAjImB,SAAA,QAAA;AACjB,SAAK,UAAUC,MAAAA,MAAU,CAAA,GAAIC,QAAAA,SAAgBF,WAAS,EAAE,YAAY,WAAW;AAC/E,QAAIA,UAAQ,oBAAoB,QAAW;AACzC,WAAK,QAAQ,kBAAkBA,UAAQ;AAAA,IACzC;AACAG,UAAAA,YAAY,WAAW,KAAK,QAAQ,eAAe;AACnD,SAAK,cAAc;AACnB,SAAK,UAAU,CAAA;AACf,SAAK,UAAU,SAAS,cAAc,KAAK;AAC3C,SAAK,QAAQ,UAAU,IAAI,KAAK,QAAQ,QAAQ,SAAS;AACzD,QAAI,KAAK,QAAQ,QAAQ,OAAO;AAC9B,aAAO,OAAO,KAAK,QAAQ,OAAO,KAAK,QAAQ,QAAQ,KAAK;AAAA,IAC9D;AAGA,aAAS,YAAY,wBAAwB,OAAO,OAAO;AAC3D,SAAK,MAAM,KAAK,iBAAiB,SAAS,KAAK,OAAO;AACtD,SAAK,QAAQ,KAAK,QAAQ,MAAM,IAAI,CAAC,cAAmB,IAAI,UAAU,IAAI,CAAC;AAC3E,SAAK,MAAM,QAAQ,CAAA,SAAQ,KAAK,MAAM;AAAA,EACxC;AAAA,EA1BA,OAAO,WAAW;AAChB,UAAM,SAAS;AAAA,MACb,iBAAiBA,MAAAA;AAAAA,MACjB,sBAAsBC,gBAAAA;AAAAA,IAAA,GACrB,IAAI;AAAA,EACT;AAAA,EAuBA,KAAK,MAAgB;AACnB,SAAK,cAAc;AACnB,SAAK,YAAY,aAAA;AACjB,SAAK,cAAc,MAAM;AACzB,SAAK,MAAM,KAAK,WAAW,YAAY,KAAK,OAAO;AACnD,SAAK,kBAAA;AACL,SAAK,cAAc,IAAI;AAGvB,UAAM,WAAW,KAAK,iBAAA;AACtB,UAAM,MAAW;AACjB,UAAM,mBAAmD,IAAI,oBAAoB,IAAI,0BAA0B,IAAI;AACnH,UAAM,UAAU,SAAS;AACzB,SAAK,WAAW,IAAI,iBAAiB,CAAC,iBAAiB;AACrD,iBAAW,YAAY,cAAc;AACnC,cAAM,SAAS,SAAS;AACxB,cAAMC,SAAQ,OAAO,cAAc,KAAK;AACxC,YAAIA,QAAO;AACT,eAAK,kBAAA;AAAA,QACP;AAAA,MACF;AAAA,IACF,CAAC;AACD,SAAK,SAAS,QAAQ,SAAS;AAAA,MAC7B,YAAY;AAAA,MACZ,iBAAiB,CAAC,OAAO;AAAA,MACzB,mBAAmB;AAAA,MACnB,SAAS;AAAA,IAAA,CACV;AAAA,EACH;AAAA,EAEA,OAAO;AACL,QAAI,CAAC,KAAK,aAAa;AACrB;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,YAAY,iBAAA;AAChC,QAAI,QAAQ;AACV,aAAO,UAAU,OAAO,oBAAoB;AAAA,IAC9C;AAEA,SAAK,YAAY,OAAA;AACjB,SAAK,cAAc;AACnB,SAAK,MAAM,KAAK,WAAW,YAAY,KAAK,OAAO;AACnD,SAAK,QAAQ,MAAM,YAAY,WAAW,MAAM;AAChD,SAAK,cAAc,EAAE;AACrB,SAAK,eAAA;AAAA,EACP;AAAA,EAEA,SAAS;AACP,SAAK,kBAAA;AACL,SAAK,QAAQ,QAAQ,CAAA,WAAU,OAAO,UAAU;AAAA,EAClD;AAAA,EAEA,cAAc,MAAgB;AAC5B,SAAK,UAAU,KAAK,WAAA,EAAa,IAAI,CAAC,gBAAqB;AACzD,YAAM,SAAiB,IAAI,YAAY,IAAI;AAC3C,aAAO,SAAA;AACP,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA,EAEA,iBAAiB;AACf,SAAK,QAAQ,QAAQ,CAAC,WAAmB,OAAO,WAAW;AAC3D,SAAK,UAAU,CAAA;AAAA,EACjB;AAAA,EAEA,oBAAoB;AAClB,QAAI,CAAC,KAAK,aAAa;AACrB;AAAA,IACF;AAEA,UAAM,gBAAgB,KAAK,YAAY,kBAAA;AACvC,QAAI,CAAC,eAAe;AAClB;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,UAAM,WAAW,cAAc,sBAAA;AAC/B,UAAM,aAAa,OAAO,sBAAA;AAE1B,WAAO,OAAO,KAAK,QAAQ,OAAO;AAAA,MAChC,SAAS;AAAA,MACT,MAAM,GAAG,SAAS,OAAO,WAAW,OAAO,IAAI,OAAO,UAAU;AAAA,MAChE,KAAK,GAAG,SAAS,MAAM,WAAW,MAAM,OAAO,SAAS;AAAA,MACxD,OAAO,GAAG,SAAS,KAAK;AAAA,
|
|
1
|
+
{"version":3,"file":"blot-formatter.cjs.js","sources":["../../../../src/modules/custom-image/blot-formatter.ts"],"sourcesContent":["import type FluentEditor from '../../core/fluent-editor'\nimport type { Action } from './actions'\nimport type { BlotFormatterOptions } from './options'\nimport type { BlotSpec } from './specs'\nimport Quill from 'quill'\nimport { merge as deepmerge } from '../../utils/merge'\nimport { CustomImage } from './image'\nimport DefaultOptions from './options'\nimport { CustomImageSpec } from './specs'\n\nconst dontMerge = (_destination: Array<any>, source: Array<any>) => source\n\nexport class BlotFormatter {\n options: BlotFormatterOptions\n currentSpec: BlotSpec\n specs: BlotSpec[]\n overlay: HTMLElement\n actions: Action[]\n observer: MutationObserver\n\n static register() {\n Quill.register({\n 'formats/image': CustomImage,\n 'modules/image-spec': CustomImageSpec,\n }, true)\n }\n\n constructor(public quill: FluentEditor, options: Partial<BlotFormatterOptions> = {}) {\n this.options = deepmerge({}, DefaultOptions, options, { arrayMerge: dontMerge })\n if (options.allowInvalidUrl !== undefined) {\n this.options.allowInvalidUrl = options.allowInvalidUrl\n }\n CustomImage.setOptions(this.options.allowInvalidUrl)\n this.currentSpec = null\n this.actions = []\n this.overlay = document.createElement('div')\n this.overlay.classList.add(this.options.overlay.className)\n if (this.options.overlay.style) {\n Object.assign(this.overlay.style, this.options.overlay.style)\n }\n\n // disable native image resizing on firefox\n document.execCommand('enableObjectResizing', false, 'false') // eslint-disable-next-line-line no-undef\n this.quill.root.addEventListener('click', this.onClick)\n this.specs = this.options.specs.map((SpecClass: any) => new SpecClass(this))\n this.specs.forEach(spec => spec.init())\n }\n\n show(spec: BlotSpec) {\n this.currentSpec = spec\n this.currentSpec.setSelection()\n this.setUserSelect('none')\n this.quill.root.parentNode.appendChild(this.overlay)\n this.repositionOverlay()\n this.createActions(spec)\n\n // fix: 图片对齐之后,虚线外框应该跟随移动\n const imageDom = spec.getTargetElement()\n const win: any = window\n const MutationObserver: typeof window.MutationObserver = win.MutationObserver || win.WebKitMutationObserver || win.MozMutationObserver\n const element = imageDom.parentNode\n this.observer = new MutationObserver((mutationList) => {\n for (const mutation of mutationList) {\n const target = mutation.target as HTMLElement\n const image = target.querySelector('img')\n if (image) {\n this.repositionOverlay()\n }\n }\n })\n this.observer.observe(element, {\n attributes: true,\n attributeFilter: ['class'],\n attributeOldValue: true,\n subtree: true,\n })\n }\n\n hide() {\n if (!this.currentSpec) {\n return\n }\n\n const imgDom = this.currentSpec.getTargetElement()\n if (imgDom) {\n imgDom.classList.remove('current-select-img')\n }\n\n this.currentSpec.onHide()\n this.currentSpec = null\n this.quill.root.parentNode.removeChild(this.overlay)\n this.overlay.style.setProperty('display', 'none')\n this.setUserSelect('')\n this.destroyActions()\n }\n\n update() {\n this.repositionOverlay()\n this.actions.forEach(action => action.onUpdate())\n }\n\n createActions(spec: BlotSpec) {\n this.actions = spec.getActions().map((ActionClass: any) => {\n const action: Action = new ActionClass(this)\n action.onCreate()\n return action\n })\n }\n\n destroyActions() {\n this.actions.forEach((action: Action) => action.onDestroy())\n this.actions = []\n }\n\n repositionOverlay() {\n if (!this.currentSpec) {\n return\n }\n\n const overlayTarget = this.currentSpec.getOverlayElement()\n if (!overlayTarget) {\n return\n }\n\n const parent = this.quill.root.parentElement\n const specRect = overlayTarget.getBoundingClientRect()\n const parentRect = parent.getBoundingClientRect()\n\n Object.assign(this.overlay.style, {\n display: 'block',\n left: `${specRect.left - parentRect.left - 1 + parent.scrollLeft}px`,\n top: `${specRect.top - parentRect.top + parent.scrollTop}px`,\n width: `${Math.min(specRect.width, parentRect.width)}px`,\n height: `${Math.min(specRect.height, parentRect.height)}px`,\n })\n }\n\n setUserSelect(value: string) {\n const props: string[] = [\n 'userSelect',\n 'mozUserSelect',\n 'webkitUserSelect',\n 'msUserSelect',\n ]\n\n props.forEach((prop: string) => {\n // set on contenteditable element and <html>\n this.quill.root.style.setProperty(prop, value)\n if (document.documentElement) {\n document.documentElement.style.setProperty(prop, value)\n }\n })\n }\n\n onClick = () => {\n this.hide()\n }\n}\n"],"names":["options","deepmerge","DefaultOptions","CustomImage","CustomImageSpec","image"],"mappings":"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"}
|
|
@@ -3,8 +3,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
3
3
|
require("./actions/index.cjs.js");
|
|
4
4
|
const blotFormatter = require("./blot-formatter.cjs.js");
|
|
5
5
|
const image = require("./image.cjs.js");
|
|
6
|
-
require("./specs/index.cjs.js");
|
|
7
6
|
require("./preview/index.cjs.js");
|
|
7
|
+
require("./specs/index.cjs.js");
|
|
8
8
|
exports.BlotFormatter = blotFormatter.BlotFormatter;
|
|
9
9
|
exports.CustomImage = image.CustomImage;
|
|
10
10
|
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -9,6 +9,7 @@ class ImagePreviewModal {
|
|
|
9
9
|
__publicField(this, "overlay", null);
|
|
10
10
|
__publicField(this, "previewImage", null);
|
|
11
11
|
__publicField(this, "scaleTooltip", null);
|
|
12
|
+
__publicField(this, "closeBtn", null);
|
|
12
13
|
__publicField(this, "currentScale", 1);
|
|
13
14
|
__publicField(this, "minScale", 0.5);
|
|
14
15
|
__publicField(this, "maxScale", 3);
|
|
@@ -67,10 +68,10 @@ class ImagePreviewModal {
|
|
|
67
68
|
transition: transform 0.2s ease-out;
|
|
68
69
|
cursor: grab;
|
|
69
70
|
`;
|
|
70
|
-
|
|
71
|
-
closeBtn.className = "tiny-editor-image-preview-close";
|
|
72
|
-
closeBtn.innerHTML = "×";
|
|
73
|
-
closeBtn.style.cssText = `
|
|
71
|
+
this.closeBtn = document.createElement("button");
|
|
72
|
+
this.closeBtn.className = "tiny-editor-image-preview-close";
|
|
73
|
+
this.closeBtn.innerHTML = "×";
|
|
74
|
+
this.closeBtn.style.cssText = `
|
|
74
75
|
position: fixed;
|
|
75
76
|
top: 20px;
|
|
76
77
|
right: 20px;
|
|
@@ -85,9 +86,9 @@ class ImagePreviewModal {
|
|
|
85
86
|
line-height: 1;
|
|
86
87
|
padding: 0;
|
|
87
88
|
`;
|
|
88
|
-
closeBtn.addEventListener("click", () => this.hide());
|
|
89
|
+
this.closeBtn.addEventListener("click", () => this.hide());
|
|
89
90
|
this.modal.appendChild(this.previewImage);
|
|
90
|
-
document.body.appendChild(closeBtn);
|
|
91
|
+
document.body.appendChild(this.closeBtn);
|
|
91
92
|
this.scaleTooltip = document.createElement("div");
|
|
92
93
|
this.scaleTooltip.className = "image-preview-scale-tooltip";
|
|
93
94
|
this.scaleTooltip.style.cssText = `
|
|
@@ -185,6 +186,9 @@ class ImagePreviewModal {
|
|
|
185
186
|
this.modal.style.alignItems = "center";
|
|
186
187
|
this.modal.style.justifyContent = "center";
|
|
187
188
|
this.overlay.style.display = "block";
|
|
189
|
+
if (this.closeBtn) {
|
|
190
|
+
this.closeBtn.style.display = "block";
|
|
191
|
+
}
|
|
188
192
|
document.body.style.overflow = "hidden";
|
|
189
193
|
}
|
|
190
194
|
/**
|
|
@@ -196,6 +200,9 @@ class ImagePreviewModal {
|
|
|
196
200
|
this.overlay.style.display = "none";
|
|
197
201
|
document.body.style.overflow = "";
|
|
198
202
|
this.resetScale();
|
|
203
|
+
if (this.closeBtn) {
|
|
204
|
+
this.closeBtn.style.display = "none";
|
|
205
|
+
}
|
|
199
206
|
}
|
|
200
207
|
}
|
|
201
208
|
/**
|
|
@@ -209,12 +216,16 @@ class ImagePreviewModal {
|
|
|
209
216
|
if (this.modal && this.modal.parentNode) {
|
|
210
217
|
this.modal.parentNode.removeChild(this.modal);
|
|
211
218
|
}
|
|
219
|
+
if (this.closeBtn && this.closeBtn.parentNode) {
|
|
220
|
+
this.closeBtn.parentNode.removeChild(this.closeBtn);
|
|
221
|
+
}
|
|
212
222
|
if (this.scaleTooltip && this.scaleTooltip.parentNode) {
|
|
213
223
|
this.scaleTooltip.parentNode.removeChild(this.scaleTooltip);
|
|
214
224
|
}
|
|
215
225
|
this.modal = null;
|
|
216
226
|
this.overlay = null;
|
|
217
227
|
this.previewImage = null;
|
|
228
|
+
this.closeBtn = null;
|
|
218
229
|
this.scaleTooltip = null;
|
|
219
230
|
}
|
|
220
231
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preview-modal.cjs.js","sources":["../../../../../src/modules/custom-image/preview/preview-modal.ts"],"sourcesContent":["/**\n * 图片预览模态框\n * 提供图片双击时的预览功能,包括遮罩层和全屏预览\n */\n\nexport class ImagePreviewModal {\n private modal: HTMLElement | null = null\n private overlay: HTMLElement | null = null\n private previewImage: HTMLImageElement | null = null\n private scaleTooltip: HTMLElement | null = null\n private currentScale: number = 1\n private minScale: number = 0.5\n private maxScale: number = 3\n private scaleStep: number = 0.1\n private tooltipHideTimer: number | null = null\n\n constructor() {\n this.initModal()\n }\n\n private initModal() {\n // 创建遮罩层\n this.overlay = document.createElement('div')\n this.overlay.className = 'image-preview-overlay'\n this.overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0, 0, 0, 0.8);\n display: none;\n z-index: 9999;\n cursor: pointer;\n `\n\n // 创建预览容器\n this.modal = document.createElement('div')\n this.modal.className = 'image-preview-modal'\n this.modal.style.cssText = `\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: transparent;\n display: none;\n z-index: 10000;\n max-width: 90vw;\n max-height: 90vh;\n cursor: auto;\n `\n\n // 创建预览图片\n this.previewImage = document.createElement('img')\n this.previewImage.className = 'image-preview-img'\n this.previewImage.style.cssText = `\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n border-radius: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n transition: transform 0.2s ease-out;\n cursor: grab;\n `\n\n // 创建关闭按钮\n const closeBtn = document.createElement('button')\n closeBtn.className = 'tiny-editor-image-preview-close'\n closeBtn.innerHTML = '×'\n closeBtn.style.cssText = `\n position: fixed;\n top: 20px;\n right: 20px;\n width: 40px;\n height: 40px;\n border: none;\n background-color: transparent;\n color: white;\n font-size: 32px;\n cursor: pointer;\n z-index: 10001;\n line-height: 1;\n padding: 0;\n `\n closeBtn.addEventListener('click', () => this.hide())\n\n this.modal.appendChild(this.previewImage)\n document.body.appendChild(closeBtn)\n\n // 创建缩放提示窗口\n this.scaleTooltip = document.createElement('div')\n this.scaleTooltip.className = 'image-preview-scale-tooltip'\n this.scaleTooltip.style.cssText = `\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: rgba(0, 0, 0, 0.7);\n color: white;\n padding: 12px 20px;\n border-radius: 6px;\n font-size: 14px;\n z-index: 10002;\n display: none;\n pointer-events: none;\n white-space: nowrap;\n font-weight: 500;\n `\n document.body.appendChild(this.scaleTooltip)\n\n // 绑定事件\n this.overlay.addEventListener('click', () => this.hide())\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') {\n this.hide()\n }\n })\n\n // 绑定滚轮缩放事件\n document.addEventListener('wheel', (e) => this.onMouseWheel(e), { passive: false })\n\n // 阻止模态框内的点击事件冒泡到遮罩层\n this.modal.addEventListener('click', (e) => {\n e.stopPropagation()\n })\n\n document.body.appendChild(this.overlay)\n document.body.appendChild(this.modal)\n }\n\n /**\n * 处理鼠标滚轮事件 - 缩放图片\n */\n private onMouseWheel = (event: WheelEvent) => {\n // 只在预览打开时处理\n if (!this.modal || this.modal.style.display === 'none') {\n return\n }\n\n event.preventDefault()\n\n // 根据滚轮方向调整缩放比例\n const delta = event.deltaY > 0 ? -this.scaleStep : this.scaleStep\n this.setScale(this.currentScale + delta)\n\n // 显示缩放提示\n this.showScaleTooltip()\n }\n\n /**\n * 设置缩放比例\n */\n private setScale(scale: number) {\n // 限制缩放范围\n this.currentScale = Math.max(this.minScale, Math.min(scale, this.maxScale))\n\n if (this.previewImage) {\n this.previewImage.style.transform = `scale(${this.currentScale})`\n }\n }\n\n /**\n * 显示缩放百分比提示\n */\n private showScaleTooltip() {\n if (!this.scaleTooltip) {\n return\n }\n\n // 清除之前的隐藏计时器\n if (this.tooltipHideTimer !== null) {\n clearTimeout(this.tooltipHideTimer)\n }\n\n // 更新提示文本\n const percentage = Math.round(this.currentScale * 100)\n this.scaleTooltip.textContent = `${percentage}%`\n this.scaleTooltip.style.display = 'block'\n\n // 1.5秒后隐藏提示\n this.tooltipHideTimer = window.setTimeout(() => {\n if (this.scaleTooltip) {\n this.scaleTooltip.style.display = 'none'\n }\n this.tooltipHideTimer = null\n }, 1500)\n }\n\n /**\n * 隐藏缩放提示\n */\n private hideScaleTooltip() {\n if (this.tooltipHideTimer !== null) {\n clearTimeout(this.tooltipHideTimer)\n this.tooltipHideTimer = null\n }\n if (this.scaleTooltip) {\n this.scaleTooltip.style.display = 'none'\n }\n }\n\n /**\n * 重置缩放比例\n */\n private resetScale() {\n this.currentScale = 1\n if (this.previewImage) {\n this.previewImage.style.transform = 'scale(1)'\n }\n this.hideScaleTooltip()\n }\n\n /**\n * 显示预览\n * @param imageUrl 图片URL\n */\n show(imageUrl: string) {\n if (!this.previewImage || !this.modal || !this.overlay) {\n return\n }\n\n this.resetScale()\n this.previewImage.src = imageUrl\n this.modal.style.display = 'flex'\n this.modal.style.alignItems = 'center'\n this.modal.style.justifyContent = 'center'\n this.overlay.style.display = 'block'\n\n // 防止页面滚动\n document.body.style.overflow = 'hidden'\n }\n\n /**\n * 隐藏预览\n */\n hide() {\n if (this.modal && this.overlay) {\n this.modal.style.display = 'none'\n this.overlay.style.display = 'none'\n document.body.style.overflow = ''\n this.resetScale()\n }\n }\n\n /**\n * 销毁预览模态框\n */\n destroy() {\n this.hideScaleTooltip()\n if (this.overlay && this.overlay.parentNode) {\n this.overlay.parentNode.removeChild(this.overlay)\n }\n if (this.modal && this.modal.parentNode) {\n this.modal.parentNode.removeChild(this.modal)\n }\n if (this.scaleTooltip && this.scaleTooltip.parentNode) {\n this.scaleTooltip.parentNode.removeChild(this.scaleTooltip)\n }\n this.modal = null\n this.overlay = null\n this.previewImage = null\n this.scaleTooltip = null\n }\n}\n\n// 全局单例实例\nlet globalPreviewModal: ImagePreviewModal | null = null\n\n/**\n * 获取或创建全局预览模态框实例\n */\nexport function getImagePreviewModal(): ImagePreviewModal {\n if (!globalPreviewModal) {\n globalPreviewModal = new ImagePreviewModal()\n }\n return globalPreviewModal\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"preview-modal.cjs.js","sources":["../../../../../src/modules/custom-image/preview/preview-modal.ts"],"sourcesContent":["/**\n * 图片预览模态框\n * 提供图片双击时的预览功能,包括遮罩层和全屏预览\n */\n\nexport class ImagePreviewModal {\n private modal: HTMLElement | null = null\n private overlay: HTMLElement | null = null\n private previewImage: HTMLImageElement | null = null\n private scaleTooltip: HTMLElement | null = null\n private closeBtn: HTMLButtonElement | null = null\n private currentScale: number = 1\n private minScale: number = 0.5\n private maxScale: number = 3\n private scaleStep: number = 0.1\n private tooltipHideTimer: number | null = null\n\n constructor() {\n this.initModal()\n }\n\n private initModal() {\n // 创建遮罩层\n this.overlay = document.createElement('div')\n this.overlay.className = 'image-preview-overlay'\n this.overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0, 0, 0, 0.8);\n display: none;\n z-index: 9999;\n cursor: pointer;\n `\n\n // 创建预览容器\n this.modal = document.createElement('div')\n this.modal.className = 'image-preview-modal'\n this.modal.style.cssText = `\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: transparent;\n display: none;\n z-index: 10000;\n max-width: 90vw;\n max-height: 90vh;\n cursor: auto;\n `\n\n // 创建预览图片\n this.previewImage = document.createElement('img')\n this.previewImage.className = 'image-preview-img'\n this.previewImage.style.cssText = `\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n border-radius: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n transition: transform 0.2s ease-out;\n cursor: grab;\n `\n\n // 创建关闭按钮\n this.closeBtn = document.createElement('button')\n this.closeBtn.className = 'tiny-editor-image-preview-close'\n this.closeBtn.innerHTML = '×'\n this.closeBtn.style.cssText = `\n position: fixed;\n top: 20px;\n right: 20px;\n width: 40px;\n height: 40px;\n border: none;\n background-color: transparent;\n color: white;\n font-size: 32px;\n cursor: pointer;\n z-index: 10001;\n line-height: 1;\n padding: 0;\n `\n this.closeBtn.addEventListener('click', () => this.hide())\n\n this.modal.appendChild(this.previewImage)\n document.body.appendChild(this.closeBtn)\n\n // 创建缩放提示窗口\n this.scaleTooltip = document.createElement('div')\n this.scaleTooltip.className = 'image-preview-scale-tooltip'\n this.scaleTooltip.style.cssText = `\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: rgba(0, 0, 0, 0.7);\n color: white;\n padding: 12px 20px;\n border-radius: 6px;\n font-size: 14px;\n z-index: 10002;\n display: none;\n pointer-events: none;\n white-space: nowrap;\n font-weight: 500;\n `\n document.body.appendChild(this.scaleTooltip)\n\n // 绑定事件\n this.overlay.addEventListener('click', () => this.hide())\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') {\n this.hide()\n }\n })\n\n // 绑定滚轮缩放事件\n document.addEventListener('wheel', e => this.onMouseWheel(e), { passive: false })\n\n // 阻止模态框内的点击事件冒泡到遮罩层\n this.modal.addEventListener('click', (e) => {\n e.stopPropagation()\n })\n\n document.body.appendChild(this.overlay)\n document.body.appendChild(this.modal)\n }\n\n /**\n * 处理鼠标滚轮事件 - 缩放图片\n */\n private onMouseWheel = (event: WheelEvent) => {\n // 只在预览打开时处理\n if (!this.modal || this.modal.style.display === 'none') {\n return\n }\n\n event.preventDefault()\n\n // 根据滚轮方向调整缩放比例\n const delta = event.deltaY > 0 ? -this.scaleStep : this.scaleStep\n this.setScale(this.currentScale + delta)\n\n // 显示缩放提示\n this.showScaleTooltip()\n }\n\n /**\n * 设置缩放比例\n */\n private setScale(scale: number) {\n // 限制缩放范围\n this.currentScale = Math.max(this.minScale, Math.min(scale, this.maxScale))\n\n if (this.previewImage) {\n this.previewImage.style.transform = `scale(${this.currentScale})`\n }\n }\n\n /**\n * 显示缩放百分比提示\n */\n private showScaleTooltip() {\n if (!this.scaleTooltip) {\n return\n }\n\n // 清除之前的隐藏计时器\n if (this.tooltipHideTimer !== null) {\n clearTimeout(this.tooltipHideTimer)\n }\n\n // 更新提示文本\n const percentage = Math.round(this.currentScale * 100)\n this.scaleTooltip.textContent = `${percentage}%`\n this.scaleTooltip.style.display = 'block'\n\n // 1.5秒后隐藏提示\n this.tooltipHideTimer = window.setTimeout(() => {\n if (this.scaleTooltip) {\n this.scaleTooltip.style.display = 'none'\n }\n this.tooltipHideTimer = null\n }, 1500)\n }\n\n /**\n * 隐藏缩放提示\n */\n private hideScaleTooltip() {\n if (this.tooltipHideTimer !== null) {\n clearTimeout(this.tooltipHideTimer)\n this.tooltipHideTimer = null\n }\n if (this.scaleTooltip) {\n this.scaleTooltip.style.display = 'none'\n }\n }\n\n /**\n * 重置缩放比例\n */\n private resetScale() {\n this.currentScale = 1\n if (this.previewImage) {\n this.previewImage.style.transform = 'scale(1)'\n }\n this.hideScaleTooltip()\n }\n\n /**\n * 显示预览\n * @param imageUrl 图片URL\n */\n show(imageUrl: string) {\n if (!this.previewImage || !this.modal || !this.overlay) {\n return\n }\n\n this.resetScale()\n this.previewImage.src = imageUrl\n this.modal.style.display = 'flex'\n this.modal.style.alignItems = 'center'\n this.modal.style.justifyContent = 'center'\n this.overlay.style.display = 'block'\n\n if (this.closeBtn) {\n this.closeBtn.style.display = 'block'\n }\n\n // 防止页面滚动\n document.body.style.overflow = 'hidden'\n }\n\n /**\n * 隐藏预览\n */\n hide() {\n if (this.modal && this.overlay) {\n this.modal.style.display = 'none'\n this.overlay.style.display = 'none'\n document.body.style.overflow = ''\n this.resetScale()\n if (this.closeBtn) {\n this.closeBtn.style.display = 'none'\n }\n }\n }\n\n /**\n * 销毁预览模态框\n */\n destroy() {\n this.hideScaleTooltip()\n if (this.overlay && this.overlay.parentNode) {\n this.overlay.parentNode.removeChild(this.overlay)\n }\n if (this.modal && this.modal.parentNode) {\n this.modal.parentNode.removeChild(this.modal)\n }\n if (this.closeBtn && this.closeBtn.parentNode) {\n this.closeBtn.parentNode.removeChild(this.closeBtn)\n }\n if (this.scaleTooltip && this.scaleTooltip.parentNode) {\n this.scaleTooltip.parentNode.removeChild(this.scaleTooltip)\n }\n this.modal = null\n this.overlay = null\n this.previewImage = null\n this.closeBtn = null\n this.scaleTooltip = null\n }\n}\n\n// 全局单例实例\nlet globalPreviewModal: ImagePreviewModal | null = null\n\n/**\n * 获取或创建全局预览模态框实例\n */\nexport function getImagePreviewModal(): ImagePreviewModal {\n if (!globalPreviewModal) {\n globalPreviewModal = new ImagePreviewModal()\n }\n return globalPreviewModal\n}\n"],"names":[],"mappings":"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"}
|