@limetech/lime-elements 38.13.0 → 38.13.2

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.
Files changed (46) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/cjs/limel-markdown.cjs.entry.js +1 -1
  3. package/dist/cjs/limel-prosemirror-adapter.cjs.entry.js +228 -71
  4. package/dist/cjs/limel-prosemirror-adapter.cjs.entry.js.map +1 -1
  5. package/dist/cjs/{markdown-parser-564adb69.js → markdown-parser-563c73db.js} +144 -386
  6. package/dist/cjs/{markdown-parser-564adb69.js.map → markdown-parser-563c73db.js.map} +1 -1
  7. package/dist/collection/components/markdown/link-markdown-plugin.js +30 -0
  8. package/dist/collection/components/markdown/link-markdown-plugin.js.map +1 -0
  9. package/dist/collection/components/markdown/markdown-parser.js +4 -4
  10. package/dist/collection/components/markdown/markdown-parser.js.map +1 -1
  11. package/dist/collection/components/text-editor/prosemirror-adapter/menu/menu-commands.js +3 -42
  12. package/dist/collection/components/text-editor/prosemirror-adapter/menu/menu-commands.js.map +1 -1
  13. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/inserter.js +59 -9
  14. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/inserter.js.map +1 -1
  15. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/link/link-mark-spec.js +33 -0
  16. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/link/link-mark-spec.js.map +1 -0
  17. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/{link-plugin.js → link/link-plugin.js} +135 -22
  18. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/link/link-plugin.js.map +1 -0
  19. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/link/utils.js +39 -0
  20. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/link/utils.js.map +1 -0
  21. package/dist/collection/components/text-editor/prosemirror-adapter/prosemirror-adapter.js +3 -1
  22. package/dist/collection/components/text-editor/prosemirror-adapter/prosemirror-adapter.js.map +1 -1
  23. package/dist/esm/limel-markdown.entry.js +1 -1
  24. package/dist/esm/limel-prosemirror-adapter.entry.js +228 -71
  25. package/dist/esm/limel-prosemirror-adapter.entry.js.map +1 -1
  26. package/dist/esm/{markdown-parser-1c1fdedc.js → markdown-parser-41d15994.js} +144 -387
  27. package/dist/esm/markdown-parser-41d15994.js.map +1 -0
  28. package/dist/lime-elements/lime-elements.esm.js +1 -1
  29. package/dist/lime-elements/p-6b5d588e.entry.js +2 -0
  30. package/dist/lime-elements/p-6b5d588e.entry.js.map +1 -0
  31. package/dist/lime-elements/{p-ce152b39.entry.js → p-895ae176.entry.js} +2 -2
  32. package/dist/lime-elements/p-95a71e89.js +8 -0
  33. package/dist/lime-elements/p-95a71e89.js.map +1 -0
  34. package/dist/types/components/markdown/link-markdown-plugin.d.ts +9 -0
  35. package/dist/types/components/text-editor/prosemirror-adapter/menu/menu-commands.d.ts +0 -2
  36. package/dist/types/components/text-editor/prosemirror-adapter/plugins/link/link-mark-spec.d.ts +10 -0
  37. package/dist/types/components/text-editor/prosemirror-adapter/plugins/link/utils.d.ts +3 -0
  38. package/package.json +1 -2
  39. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/link-plugin.js.map +0 -1
  40. package/dist/esm/markdown-parser-1c1fdedc.js.map +0 -1
  41. package/dist/lime-elements/p-587f6b6d.entry.js +0 -2
  42. package/dist/lime-elements/p-587f6b6d.entry.js.map +0 -1
  43. package/dist/lime-elements/p-cf87519f.js +0 -8
  44. package/dist/lime-elements/p-cf87519f.js.map +0 -1
  45. /package/dist/lime-elements/{p-ce152b39.entry.js.map → p-895ae176.entry.js.map} +0 -0
  46. /package/dist/types/components/text-editor/prosemirror-adapter/plugins/{link-plugin.d.ts → link/link-plugin.d.ts} +0 -0
@@ -0,0 +1,30 @@
1
+ import { visit } from 'unist-util-visit';
2
+ import { getLinkAttributes } from '../text-editor/prosemirror-adapter/plugins/link/utils';
3
+ /**
4
+ * Creates a unified.js plugin that transforms link elements
5
+ * to add target, rel, and referrerpolicy attributes.
6
+ *
7
+ * @returns A unified.js plugin function
8
+ */
9
+ export function createLinksPlugin() {
10
+ return () => {
11
+ return (tree) => {
12
+ visit(tree, 'element', (node) => {
13
+ var _a, _b;
14
+ if (node.tagName === 'a') {
15
+ const href = (_a = node.properties) === null || _a === void 0 ? void 0 : _a.href;
16
+ const title = (_b = node.properties) === null || _b === void 0 ? void 0 : _b.title;
17
+ if (!href) {
18
+ return;
19
+ }
20
+ const attributes = getLinkAttributes(href, title);
21
+ node.properties.target = attributes.target;
22
+ node.properties.rel = attributes.rel;
23
+ node.properties.referrerpolicy = attributes.referrerpolicy;
24
+ }
25
+ });
26
+ return tree;
27
+ };
28
+ };
29
+ }
30
+ //# sourceMappingURL=link-markdown-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link-markdown-plugin.js","sourceRoot":"","sources":["../../../src/components/markdown/link-markdown-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAGzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,uDAAuD,CAAC;AAE1F;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB;EAC7B,OAAO,GAAgB,EAAE;IACrB,OAAO,CAAC,IAAU,EAAE,EAAE;MAClB,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,IAAS,EAAE,EAAE;;QACjC,IAAI,IAAI,CAAC,OAAO,KAAK,GAAG,EAAE;UACtB,MAAM,IAAI,GAAG,MAAA,IAAI,CAAC,UAAU,0CAAE,IAAI,CAAC;UACnC,MAAM,KAAK,GAAG,MAAA,IAAI,CAAC,UAAU,0CAAE,KAAK,CAAC;UAErC,IAAI,CAAC,IAAI,EAAE;YACP,OAAO;WACV;UAED,MAAM,UAAU,GAAG,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;UAElD,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;UAC3C,IAAI,CAAC,UAAU,CAAC,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC;UACrC,IAAI,CAAC,UAAU,CAAC,cAAc,GAAG,UAAU,CAAC,cAAc,CAAC;SAC9D;MACL,CAAC,CAAC,CAAC;MAEH,OAAO,IAAI,CAAC;IAChB,CAAC,CAAC;EACN,CAAC,CAAC;AACN,CAAC","sourcesContent":["import { visit } from 'unist-util-visit';\nimport { Node } from 'unist';\nimport { Plugin, Transformer } from 'unified';\nimport { getLinkAttributes } from '../text-editor/prosemirror-adapter/plugins/link/utils';\n\n/**\n * Creates a unified.js plugin that transforms link elements\n * to add target, rel, and referrerpolicy attributes.\n *\n * @returns A unified.js plugin function\n */\nexport function createLinksPlugin(): Plugin {\n return (): Transformer => {\n return (tree: Node) => {\n visit(tree, 'element', (node: any) => {\n if (node.tagName === 'a') {\n const href = node.properties?.href;\n const title = node.properties?.title;\n\n if (!href) {\n return;\n }\n\n const attributes = getLinkAttributes(href, title);\n\n node.properties.target = attributes.target;\n node.properties.rel = attributes.rel;\n node.properties.referrerpolicy = attributes.referrerpolicy;\n }\n });\n\n return tree;\n };\n };\n}\n"]}
@@ -3,13 +3,13 @@ import remarkParse from 'remark-parse';
3
3
  import remarkRehype from 'remark-rehype';
4
4
  import remarkGfm from 'remark-gfm';
5
5
  import rehypeParse from 'rehype-parse';
6
- import rehypeExternalLinks from 'rehype-external-links';
7
6
  import rehypeSanitize, { defaultSchema } from 'rehype-sanitize';
8
7
  import rehypeStringify from 'rehype-stringify';
9
8
  import rehypeRaw from 'rehype-raw';
10
9
  import { visit } from 'unist-util-visit';
11
10
  import { sanitizeStyle } from './sanitize-style';
12
11
  import { createLazyLoadImagesPlugin } from './image-markdown-plugin';
12
+ import { createLinksPlugin } from './link-markdown-plugin';
13
13
  /**
14
14
  * Takes a string as input and returns a new string
15
15
  * where the text has been converted to HTML.
@@ -33,8 +33,8 @@ export async function markdownToHTML(text, options) {
33
33
  .use(remarkParse)
34
34
  .use(remarkGfm)
35
35
  .use(remarkRehype, { allowDangerousHtml: true })
36
- .use(rehypeExternalLinks, { target: '_blank' })
37
36
  .use(rehypeRaw)
37
+ .use(createLinksPlugin())
38
38
  .use(rehypeSanitize, Object.assign({}, getWhiteList((_a = options === null || options === void 0 ? void 0 : options.whitelist) !== null && _a !== void 0 ? _a : [])))
39
39
  .use(() => {
40
40
  return (tree) => {
@@ -71,7 +71,7 @@ export async function sanitizeHTML(html, whitelist) {
71
71
  return file.toString();
72
72
  }
73
73
  function getWhiteList(allowedComponents) {
74
- var _a, _b;
74
+ var _a, _b, _c;
75
75
  const defaultSchemaClone = [...((_a = defaultSchema.attributes['*']) !== null && _a !== void 0 ? _a : [])];
76
76
  const asteriskAttributeWhitelist = defaultSchemaClone.filter((attr) => {
77
77
  return attr !== 'height';
@@ -83,7 +83,7 @@ function getWhiteList(allowedComponents) {
83
83
  ], attributes: Object.assign(Object.assign({}, defaultSchema.attributes), { p: [
84
84
  ...((_b = defaultSchema.attributes.p) !== null && _b !== void 0 ? _b : []),
85
85
  ['className', 'MsoNormal'],
86
- ], '*': asteriskAttributeWhitelist }) });
86
+ ], a: [...((_c = defaultSchema.attributes.a) !== null && _c !== void 0 ? _c : []), 'referrerpolicy'], '*': asteriskAttributeWhitelist }) });
87
87
  for (const component of allowedComponents) {
88
88
  whitelist.attributes[component.tagName] = component.attributes;
89
89
  }
@@ -1 +1 @@
1
- {"version":3,"file":"markdown-parser.js","sourceRoot":"","sources":["../../../src/components/markdown/markdown-parser.ts"],"names":[],"mappings":"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","sourcesContent":["import { unified } from 'unified';\nimport remarkParse from 'remark-parse';\nimport remarkRehype from 'remark-rehype';\nimport remarkGfm from 'remark-gfm';\nimport rehypeParse from 'rehype-parse';\nimport rehypeExternalLinks from 'rehype-external-links';\nimport rehypeSanitize, { defaultSchema } from 'rehype-sanitize';\nimport rehypeStringify from 'rehype-stringify';\nimport rehypeRaw from 'rehype-raw';\nimport { visit } from 'unist-util-visit';\nimport { sanitizeStyle } from './sanitize-style';\nimport { Node } from 'unist';\nimport { Schema } from 'rehype-sanitize/lib';\nimport { createLazyLoadImagesPlugin } from './image-markdown-plugin';\nimport { CustomElementDefinition } from '../../global/shared-types/custom-element.types';\n\n/**\n * Takes a string as input and returns a new string\n * where the text has been converted to HTML.\n *\n * If the text is formatted with .md markdown, it will\n * be transformed to HTML.\n *\n * If the text already is in HTML it will be sanitized and\n * \"dangerous\" tags such as <script> will be removed.\n *\n * @param text - The string to convert.\n * @param options - Options for the conversions.\n * @returns The resulting HTML.\n */\nexport async function markdownToHTML(\n text: string,\n options?: MarkdownToHTMLOptions,\n): Promise<string> {\n if (options?.forceHardLineBreaks) {\n text = text.replace(/(?<!\\\\)([\\n\\r])/g, ' $1');\n }\n\n const file = await unified()\n .use(remarkParse)\n .use(remarkGfm)\n .use(remarkRehype, { allowDangerousHtml: true })\n .use(rehypeExternalLinks, { target: '_blank' })\n .use(rehypeRaw)\n .use(rehypeSanitize, {\n ...getWhiteList(options?.whitelist ?? []),\n })\n .use(() => {\n return (tree: Node) => {\n // Run the sanitizeStyle function on all elements, to sanitize\n // the value of the `style` attribute, if there is one.\n visit(tree, 'element', sanitizeStyle);\n };\n })\n .use(createLazyLoadImagesPlugin(options?.lazyLoadImages))\n .use(rehypeStringify)\n .process(text);\n\n return file.toString();\n}\n\n/**\n * Sanitizes a given HTML string by removing dangerous tags and attributes.\n *\n * @param html - The string containing HTML to sanitize.\n * @param whitelist - Optional whitelist of custom components.\n * @returns The sanitized HTML string.\n */\nexport async function sanitizeHTML(\n html: string,\n whitelist?: CustomElementDefinition[],\n): Promise<string> {\n const file = await unified()\n .use(rehypeParse)\n .use(rehypeSanitize, {\n ...getWhiteList(whitelist ?? []),\n })\n .use(() => {\n return (tree: Node) => {\n // Run the sanitizeStyle function on all elements, to sanitize\n // the value of the `style` attribute, if there is one.\n visit(tree, 'element', sanitizeStyle);\n };\n })\n .use(rehypeStringify)\n .process(html);\n\n return file.toString();\n}\n\nfunction getWhiteList(allowedComponents: CustomElementDefinition[]): Schema {\n const defaultSchemaClone = [...(defaultSchema.attributes['*'] ?? [])];\n const asteriskAttributeWhitelist = defaultSchemaClone.filter((attr) => {\n return attr !== 'height';\n });\n asteriskAttributeWhitelist.push('style');\n\n const whitelist: Schema = {\n ...defaultSchema,\n tagNames: [\n ...(defaultSchema.tagNames || []),\n ...allowedComponents.map((component) => component.tagName),\n ],\n attributes: {\n ...defaultSchema.attributes,\n p: [\n ...(defaultSchema.attributes.p ?? []),\n ['className', 'MsoNormal'],\n ], // Allow the class 'MsoNormal' on <p> elements\n '*': asteriskAttributeWhitelist,\n },\n };\n\n for (const component of allowedComponents) {\n whitelist.attributes[component.tagName] = component.attributes;\n }\n\n return whitelist;\n}\n\n/**\n * Options for markdownToHTML.\n */\nexport interface MarkdownToHTMLOptions {\n /**\n * Set to `true` to convert all soft line breaks to hard line breaks.\n */\n forceHardLineBreaks?: boolean;\n whitelist?: CustomElementDefinition[];\n lazyLoadImages?: boolean;\n}\n"]}
1
+ {"version":3,"file":"markdown-parser.js","sourceRoot":"","sources":["../../../src/components/markdown/markdown-parser.ts"],"names":[],"mappings":"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","sourcesContent":["import { unified } from 'unified';\nimport remarkParse from 'remark-parse';\nimport remarkRehype from 'remark-rehype';\nimport remarkGfm from 'remark-gfm';\nimport rehypeParse from 'rehype-parse';\nimport rehypeSanitize, { defaultSchema } from 'rehype-sanitize';\nimport rehypeStringify from 'rehype-stringify';\nimport rehypeRaw from 'rehype-raw';\nimport { visit } from 'unist-util-visit';\nimport { sanitizeStyle } from './sanitize-style';\nimport { Node } from 'unist';\nimport { Schema } from 'rehype-sanitize/lib';\nimport { createLazyLoadImagesPlugin } from './image-markdown-plugin';\nimport { CustomElementDefinition } from '../../global/shared-types/custom-element.types';\nimport { createLinksPlugin } from './link-markdown-plugin';\n\n/**\n * Takes a string as input and returns a new string\n * where the text has been converted to HTML.\n *\n * If the text is formatted with .md markdown, it will\n * be transformed to HTML.\n *\n * If the text already is in HTML it will be sanitized and\n * \"dangerous\" tags such as <script> will be removed.\n *\n * @param text - The string to convert.\n * @param options - Options for the conversions.\n * @returns The resulting HTML.\n */\nexport async function markdownToHTML(\n text: string,\n options?: MarkdownToHTMLOptions,\n): Promise<string> {\n if (options?.forceHardLineBreaks) {\n text = text.replace(/(?<!\\\\)([\\n\\r])/g, ' $1');\n }\n\n const file = await unified()\n .use(remarkParse)\n .use(remarkGfm)\n .use(remarkRehype, { allowDangerousHtml: true })\n .use(rehypeRaw)\n .use(createLinksPlugin())\n .use(rehypeSanitize, {\n ...getWhiteList(options?.whitelist ?? []),\n })\n .use(() => {\n return (tree: Node) => {\n // Run the sanitizeStyle function on all elements, to sanitize\n // the value of the `style` attribute, if there is one.\n visit(tree, 'element', sanitizeStyle);\n };\n })\n .use(createLazyLoadImagesPlugin(options?.lazyLoadImages))\n .use(rehypeStringify)\n .process(text);\n\n return file.toString();\n}\n\n/**\n * Sanitizes a given HTML string by removing dangerous tags and attributes.\n *\n * @param html - The string containing HTML to sanitize.\n * @param whitelist - Optional whitelist of custom components.\n * @returns The sanitized HTML string.\n */\nexport async function sanitizeHTML(\n html: string,\n whitelist?: CustomElementDefinition[],\n): Promise<string> {\n const file = await unified()\n .use(rehypeParse)\n .use(rehypeSanitize, {\n ...getWhiteList(whitelist ?? []),\n })\n .use(() => {\n return (tree: Node) => {\n // Run the sanitizeStyle function on all elements, to sanitize\n // the value of the `style` attribute, if there is one.\n visit(tree, 'element', sanitizeStyle);\n };\n })\n .use(rehypeStringify)\n .process(html);\n\n return file.toString();\n}\n\nfunction getWhiteList(allowedComponents: CustomElementDefinition[]): Schema {\n const defaultSchemaClone = [...(defaultSchema.attributes['*'] ?? [])];\n const asteriskAttributeWhitelist = defaultSchemaClone.filter((attr) => {\n return attr !== 'height';\n });\n asteriskAttributeWhitelist.push('style');\n\n const whitelist: Schema = {\n ...defaultSchema,\n tagNames: [\n ...(defaultSchema.tagNames || []),\n ...allowedComponents.map((component) => component.tagName),\n ],\n attributes: {\n ...defaultSchema.attributes,\n p: [\n ...(defaultSchema.attributes.p ?? []),\n ['className', 'MsoNormal'],\n ], // Allow the class 'MsoNormal' on <p> elements\n a: [...(defaultSchema.attributes.a ?? []), 'referrerpolicy'], // Allow referrerpolicy on <a> elements\n '*': asteriskAttributeWhitelist,\n },\n };\n\n for (const component of allowedComponents) {\n whitelist.attributes[component.tagName] = component.attributes;\n }\n\n return whitelist;\n}\n\n/**\n * Options for markdownToHTML.\n */\nexport interface MarkdownToHTMLOptions {\n /**\n * Set to `true` to convert all soft line breaks to hard line breaks.\n */\n forceHardLineBreaks?: boolean;\n whitelist?: CustomElementDefinition[];\n lazyLoadImages?: boolean;\n}\n"]}
@@ -1,7 +1,8 @@
1
1
  import { toggleMark, setBlockType, wrapIn, lift } from 'prosemirror-commands';
2
2
  import { findWrapping, liftTarget } from 'prosemirror-transform';
3
- import { TextSelection, } from 'prosemirror-state';
3
+ import { TextSelection } from 'prosemirror-state';
4
4
  import { EditorMenuTypes, LevelMapping } from './types';
5
+ import { getLinkAttributes } from '../plugins/link/utils';
5
6
  const setActiveMethodForMark = (command, markType) => {
6
7
  command.active = (state) => {
7
8
  const { from, $from, to, empty } = state.selection;
@@ -44,24 +45,15 @@ const setActiveMethodForWrap = (command, nodeType) => {
44
45
  const createInsertLinkCommand = (schema, _, link) => {
45
46
  const command = (state, dispatch) => {
46
47
  const { from, to } = state.selection;
48
+ const linkMark = schema.marks.link.create(getLinkAttributes(link.href, link.href));
47
49
  if (from === to) {
48
50
  // If no text is selected, insert new text with link
49
- const linkMark = schema.marks.link.create({
50
- href: link.href,
51
- title: link.href,
52
- target: isExternalLink(link.href) ? '_blank' : null,
53
- });
54
51
  const linkText = link.text || link.href;
55
52
  const newLink = schema.text(linkText, [linkMark]);
56
53
  dispatch(state.tr.insert(from, newLink));
57
54
  }
58
55
  else {
59
56
  // If text is selected, replace selected text with link text
60
- const linkMark = schema.marks.link.create({
61
- href: link.href,
62
- title: link.href,
63
- target: isExternalLink(link.href) ? '_blank' : null,
64
- });
65
57
  const selectedText = state.doc.textBetween(from, to, ' ');
66
58
  const newLink = schema.text(link.text || selectedText, [linkMark]);
67
59
  dispatch(state.tr.replaceWith(from, to, newLink));
@@ -135,15 +127,6 @@ const toggleNodeType = (schema, type, attrs = {}, shouldWrap = false) => {
135
127
  return false;
136
128
  };
137
129
  };
138
- export const isValidUrl = (text) => {
139
- try {
140
- new URL(text);
141
- }
142
- catch (_a) {
143
- return false;
144
- }
145
- return true;
146
- };
147
130
  const createSetNodeTypeCommand = (schema, nodeType, level) => {
148
131
  const type = schema.nodes[nodeType];
149
132
  if (!type) {
@@ -216,27 +199,6 @@ const createListCommand = (schema, listType) => {
216
199
  setActiveMethodForWrap(command, type);
217
200
  return command;
218
201
  };
219
- const copyPasteLinkCommand = (state, dispatch) => {
220
- const { from, to } = state.selection;
221
- if (from === to) {
222
- return false;
223
- }
224
- const clipboardData = window.clipboardData;
225
- if (!clipboardData) {
226
- return false;
227
- }
228
- const copyPastedText = clipboardData.getData('text');
229
- if (!isValidUrl(copyPastedText)) {
230
- return false;
231
- }
232
- const linkMark = state.schema.marks.link.create({
233
- href: copyPastedText,
234
- target: isExternalLink(copyPastedText) ? '_blank' : null,
235
- });
236
- const selectedText = state.doc.textBetween(from, to, ' ');
237
- const newLink = state.schema.text(selectedText, [linkMark]);
238
- dispatch(state.tr.replaceWith(from, to, newLink));
239
- };
240
202
  const commandMapping = {
241
203
  strong: createToggleMarkCommand,
242
204
  em: createToggleMarkCommand,
@@ -275,7 +237,6 @@ export class MenuCommandFactory {
275
237
  'Mod-Shift-X': this.getCommand(EditorMenuTypes.Strikethrough),
276
238
  'Mod-`': this.getCommand(EditorMenuTypes.Code),
277
239
  'Mod-Shift-C': this.getCommand(EditorMenuTypes.CodeBlock),
278
- 'Mod-v': copyPasteLinkCommand,
279
240
  };
280
241
  }
281
242
  }
@@ -1 +1 @@
1
- {"version":3,"file":"menu-commands.js","sourceRoot":"","sources":["../../../../../src/components/text-editor/prosemirror-adapter/menu/menu-commands.ts"],"names":[],"mappings":"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","sourcesContent":["import { toggleMark, setBlockType, wrapIn, lift } from 'prosemirror-commands';\nimport { Schema, MarkType, NodeType, Attrs } from 'prosemirror-model';\nimport { findWrapping, liftTarget } from 'prosemirror-transform';\nimport {\n Command,\n EditorState,\n Transaction,\n TextSelection,\n} from 'prosemirror-state';\nimport { EditorMenuTypes, EditorTextLink, LevelMapping } from './types';\n\ntype CommandFunction = (\n schema: Schema,\n mark: EditorMenuTypes,\n link?: EditorTextLink,\n) => CommandWithActive;\n\ninterface CommandMapping {\n [key: string]: CommandFunction;\n}\n\nexport interface CommandWithActive extends Command {\n active?: (state: EditorState) => boolean;\n allowed?: (state: EditorState) => boolean;\n}\n\nconst setActiveMethodForMark = (\n command: CommandWithActive,\n markType: MarkType,\n) => {\n command.active = (state) => {\n const { from, $from, to, empty } = state.selection;\n if (empty) {\n return !!markType.isInSet(state.storedMarks || $from.marks());\n } else {\n return state.doc.rangeHasMark(from, to, markType);\n }\n };\n};\n\nconst setActiveMethodForNode = (\n command: CommandWithActive,\n nodeType: NodeType,\n level?: number,\n) => {\n command.active = (state) => {\n const { $from } = state.selection;\n const node = $from.node($from.depth);\n\n if (node && node.type.name === nodeType.name) {\n if (nodeType.name === LevelMapping.Heading && level) {\n return node.attrs.level === level;\n }\n\n return true;\n }\n\n return false;\n };\n};\n\nconst setActiveMethodForWrap = (\n command: CommandWithActive,\n nodeType: NodeType,\n) => {\n command.active = (state) => {\n const { from, to } = state.selection;\n\n for (let pos = from; pos <= to; pos++) {\n const resolvedPos = state.doc.resolve(pos);\n for (let i = resolvedPos.depth; i > 0; i--) {\n const node = resolvedPos.node(i);\n if (node && node.type.name === nodeType.name) {\n return true;\n }\n }\n }\n\n return false;\n };\n};\n\nconst createInsertLinkCommand: CommandFunction = (\n schema: Schema,\n _: EditorMenuTypes,\n link?: EditorTextLink,\n): CommandWithActive => {\n const command: Command = (state, dispatch) => {\n const { from, to } = state.selection;\n if (from === to) {\n // If no text is selected, insert new text with link\n const linkMark = schema.marks.link.create({\n href: link.href,\n title: link.href,\n target: isExternalLink(link.href) ? '_blank' : null,\n });\n const linkText = link.text || link.href;\n const newLink = schema.text(linkText, [linkMark]);\n dispatch(state.tr.insert(from, newLink));\n } else {\n // If text is selected, replace selected text with link text\n const linkMark = schema.marks.link.create({\n href: link.href,\n title: link.href,\n target: isExternalLink(link.href) ? '_blank' : null,\n });\n const selectedText = state.doc.textBetween(from, to, ' ');\n const newLink = schema.text(link.text || selectedText, [linkMark]);\n dispatch(state.tr.replaceWith(from, to, newLink));\n }\n\n return true;\n };\n\n setActiveMethodForMark(command, schema.marks.link);\n\n return command;\n};\n\nconst createToggleMarkCommand = (\n schema: Schema,\n markName: string,\n link?: EditorTextLink,\n): CommandWithActive => {\n const markType: MarkType | undefined = schema.marks[markName];\n if (!markType) {\n throw new Error(`Mark \"${markName}\" not found in schema`);\n }\n\n const attrs = getAttributes(markName, link);\n\n const command: CommandWithActive = toggleMark(markType, attrs);\n setActiveMethodForMark(command, markType);\n\n return command;\n};\n\nconst getAttributes = (\n markName: string,\n link: EditorTextLink,\n): Attrs | null => {\n if (markName === EditorMenuTypes.Link && link.href) {\n return {\n href: link.href,\n target: isExternalLink(link.href) ? '_blank' : null,\n };\n }\n\n return undefined;\n};\n\nexport const isExternalLink = (url: string): boolean => {\n return !url.startsWith(window.location.origin);\n};\n\n/**\n * Toggles or wraps a node type based on the selection and parameters.\n * - Toggles to paragraph if the selection is of the specified type.\n * - Lifts content out if already wrapped in the specified type.\n * - Wraps or sets the selection to the specified type based on `shouldWrap`.\n * @param schema - ProseMirror schema.\n * @param type - Block type name to toggle.\n * @param attrs - Attributes for the block type.\n * @param shouldWrap - Wrap selection if true, otherwise directly set the block type for the selection.\n * @returns A command based on selection and action needed.\n */\nconst toggleNodeType = (\n schema: Schema,\n type: string,\n attrs: Attrs = {},\n shouldWrap: boolean = false,\n): Command => {\n const nodeType = schema.nodes[type];\n const paragraphType = schema.nodes.paragraph;\n\n return (state, dispatch) => {\n const { $from, $to } = state.selection;\n\n const hasActiveWrap = $from.node($from.depth - 1).type === nodeType;\n\n if (\n state.selection instanceof TextSelection &&\n // Ensure selection is within the same parent block\n // We don't want toggling block types across multiple blocks\n $from.sameParent($from.doc.resolve($to.pos))\n ) {\n if ($from.parent.type === nodeType) {\n if (dispatch) {\n dispatch(\n state.tr.setBlockType(\n $from.pos,\n $to.pos,\n paragraphType,\n ),\n );\n }\n\n return true;\n } else {\n if (hasActiveWrap) {\n return lift(state, dispatch);\n }\n\n if (shouldWrap) {\n return wrapIn(nodeType, attrs)(state, dispatch);\n } else {\n return setBlockType(nodeType, attrs)(state, dispatch);\n }\n }\n }\n\n return false;\n };\n};\n\nexport const isValidUrl = (text: string): boolean => {\n try {\n new URL(text);\n } catch {\n return false;\n }\n\n return true;\n};\n\nconst createSetNodeTypeCommand = (\n schema: Schema,\n nodeType: string,\n level?: number,\n): CommandWithActive => {\n const type: NodeType | undefined = schema.nodes[nodeType];\n if (!type) {\n throw new Error(`Node type \"${nodeType}\" not found in schema`);\n }\n\n let command: CommandWithActive;\n if (nodeType === LevelMapping.Heading && level) {\n command = toggleNodeType(schema, LevelMapping.Heading, {\n level: level,\n });\n } else if (nodeType === EditorMenuTypes.CodeBlock) {\n command = toggleNodeType(schema, EditorMenuTypes.CodeBlock);\n } else {\n command = setBlockType(type);\n }\n\n setActiveMethodForNode(command, type, level);\n\n return command;\n};\n\nconst createWrapInCommand = (\n schema: Schema,\n nodeType: string,\n): CommandWithActive => {\n const type: NodeType | undefined = schema.nodes[nodeType];\n if (!type) {\n throw new Error(`Node type \"${nodeType}\" not found in schema`);\n }\n\n let command: CommandWithActive;\n if (nodeType === EditorMenuTypes.Blockquote) {\n command = toggleNodeType(schema, EditorMenuTypes.Blockquote, {}, true);\n } else {\n command = wrapIn(type);\n }\n\n setActiveMethodForWrap(command, type);\n\n return command;\n};\n\nconst toggleList = (listType) => {\n return (state, dispatch) => {\n const { $from, $to } = state.selection;\n const range = $from.blockRange($to);\n\n if (!range) {\n return false;\n }\n\n const wrapping = range && findWrapping(range, listType);\n\n if (wrapping) {\n // Wrap the selection in a list\n if (dispatch) {\n dispatch(state.tr.wrap(range, wrapping).scrollIntoView());\n }\n\n return true;\n } else {\n // Check if we are in a list item and lift out of the list\n const liftRange = range && liftTarget(range);\n if (liftRange !== null) {\n if (dispatch) {\n dispatch(state.tr.lift(range, liftRange).scrollIntoView());\n }\n\n return true;\n }\n\n return false;\n }\n };\n};\n\nconst createListCommand = (\n schema: Schema,\n listType: string,\n): CommandWithActive => {\n const type: NodeType | undefined = schema.nodes[listType];\n if (!type) {\n throw new Error(`List type \"${listType}\" not found in schema`);\n }\n\n const command: CommandWithActive = toggleList(type);\n setActiveMethodForWrap(command, type);\n\n return command;\n};\n\nconst copyPasteLinkCommand: Command = (\n state: EditorState,\n dispatch: (tr: Transaction) => void,\n) => {\n const { from, to } = state.selection;\n if (from === to) {\n return false;\n }\n\n const clipboardData = (window as any).clipboardData;\n if (!clipboardData) {\n return false;\n }\n\n const copyPastedText = clipboardData.getData('text');\n if (!isValidUrl(copyPastedText)) {\n return false;\n }\n\n const linkMark = state.schema.marks.link.create({\n href: copyPastedText,\n target: isExternalLink(copyPastedText) ? '_blank' : null,\n });\n\n const selectedText = state.doc.textBetween(from, to, ' ');\n const newLink = state.schema.text(selectedText, [linkMark]);\n dispatch(state.tr.replaceWith(from, to, newLink));\n};\n\nconst commandMapping: CommandMapping = {\n strong: createToggleMarkCommand,\n em: createToggleMarkCommand,\n underline: createToggleMarkCommand,\n strikethrough: createToggleMarkCommand,\n code: createToggleMarkCommand,\n link: createInsertLinkCommand,\n headerlevel1: (schema) =>\n createSetNodeTypeCommand(\n schema,\n LevelMapping.Heading,\n LevelMapping.one,\n ),\n headerlevel2: (schema) =>\n createSetNodeTypeCommand(\n schema,\n LevelMapping.Heading,\n LevelMapping.two,\n ),\n headerlevel3: (schema) =>\n createSetNodeTypeCommand(\n schema,\n LevelMapping.Heading,\n LevelMapping.three,\n ),\n blockquote: (schema) =>\n createWrapInCommand(schema, EditorMenuTypes.Blockquote),\n /* eslint-disable camelcase */\n code_block: (schema) =>\n createSetNodeTypeCommand(schema, EditorMenuTypes.CodeBlock),\n ordered_list: (schema) =>\n createListCommand(schema, EditorMenuTypes.OrderedList),\n bullet_list: (schema) =>\n createListCommand(schema, EditorMenuTypes.BulletList),\n /* eslint-enable camelcase */\n};\n\nexport class MenuCommandFactory {\n private schema: Schema;\n\n constructor(schema: Schema) {\n this.schema = schema;\n }\n\n public getCommand(mark: EditorMenuTypes, link?: EditorTextLink) {\n const commandFunc = commandMapping[mark];\n if (!commandFunc) {\n throw new Error(`The Mark \"${mark}\" is not supported`);\n }\n\n return commandFunc(this.schema, mark, link);\n }\n\n buildKeymap() {\n return {\n 'Mod-B': this.getCommand(EditorMenuTypes.Bold),\n 'Mod-I': this.getCommand(EditorMenuTypes.Italic),\n 'Mod-Shift-1': this.getCommand(EditorMenuTypes.HeaderLevel1),\n 'Mod-Shift-2': this.getCommand(EditorMenuTypes.HeaderLevel2),\n 'Mod-Shift-3': this.getCommand(EditorMenuTypes.HeaderLevel3),\n 'Mod-Shift-X': this.getCommand(EditorMenuTypes.Strikethrough),\n 'Mod-`': this.getCommand(EditorMenuTypes.Code),\n 'Mod-Shift-C': this.getCommand(EditorMenuTypes.CodeBlock),\n 'Mod-v': copyPasteLinkCommand,\n };\n }\n}\n"]}
1
+ {"version":3,"file":"menu-commands.js","sourceRoot":"","sources":["../../../../../src/components/text-editor/prosemirror-adapter/menu/menu-commands.ts"],"names":[],"mappings":"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","sourcesContent":["import { toggleMark, setBlockType, wrapIn, lift } from 'prosemirror-commands';\nimport { Schema, MarkType, NodeType, Attrs } from 'prosemirror-model';\nimport { findWrapping, liftTarget } from 'prosemirror-transform';\nimport { Command, EditorState, TextSelection } from 'prosemirror-state';\nimport { EditorMenuTypes, EditorTextLink, LevelMapping } from './types';\nimport { getLinkAttributes } from '../plugins/link/utils';\n\ntype CommandFunction = (\n schema: Schema,\n mark: EditorMenuTypes,\n link?: EditorTextLink,\n) => CommandWithActive;\n\ninterface CommandMapping {\n [key: string]: CommandFunction;\n}\n\nexport interface CommandWithActive extends Command {\n active?: (state: EditorState) => boolean;\n allowed?: (state: EditorState) => boolean;\n}\n\nconst setActiveMethodForMark = (\n command: CommandWithActive,\n markType: MarkType,\n) => {\n command.active = (state) => {\n const { from, $from, to, empty } = state.selection;\n if (empty) {\n return !!markType.isInSet(state.storedMarks || $from.marks());\n } else {\n return state.doc.rangeHasMark(from, to, markType);\n }\n };\n};\n\nconst setActiveMethodForNode = (\n command: CommandWithActive,\n nodeType: NodeType,\n level?: number,\n) => {\n command.active = (state) => {\n const { $from } = state.selection;\n const node = $from.node($from.depth);\n\n if (node && node.type.name === nodeType.name) {\n if (nodeType.name === LevelMapping.Heading && level) {\n return node.attrs.level === level;\n }\n\n return true;\n }\n\n return false;\n };\n};\n\nconst setActiveMethodForWrap = (\n command: CommandWithActive,\n nodeType: NodeType,\n) => {\n command.active = (state) => {\n const { from, to } = state.selection;\n\n for (let pos = from; pos <= to; pos++) {\n const resolvedPos = state.doc.resolve(pos);\n for (let i = resolvedPos.depth; i > 0; i--) {\n const node = resolvedPos.node(i);\n if (node && node.type.name === nodeType.name) {\n return true;\n }\n }\n }\n\n return false;\n };\n};\n\nconst createInsertLinkCommand: CommandFunction = (\n schema: Schema,\n _: EditorMenuTypes,\n link?: EditorTextLink,\n): CommandWithActive => {\n const command: Command = (state, dispatch) => {\n const { from, to } = state.selection;\n const linkMark = schema.marks.link.create(\n getLinkAttributes(link.href, link.href),\n );\n\n if (from === to) {\n // If no text is selected, insert new text with link\n const linkText = link.text || link.href;\n const newLink = schema.text(linkText, [linkMark]);\n dispatch(state.tr.insert(from, newLink));\n } else {\n // If text is selected, replace selected text with link text\n const selectedText = state.doc.textBetween(from, to, ' ');\n const newLink = schema.text(link.text || selectedText, [linkMark]);\n dispatch(state.tr.replaceWith(from, to, newLink));\n }\n\n return true;\n };\n\n setActiveMethodForMark(command, schema.marks.link);\n\n return command;\n};\n\nconst createToggleMarkCommand = (\n schema: Schema,\n markName: string,\n link?: EditorTextLink,\n): CommandWithActive => {\n const markType: MarkType | undefined = schema.marks[markName];\n if (!markType) {\n throw new Error(`Mark \"${markName}\" not found in schema`);\n }\n\n const attrs = getAttributes(markName, link);\n\n const command: CommandWithActive = toggleMark(markType, attrs);\n setActiveMethodForMark(command, markType);\n\n return command;\n};\n\nconst getAttributes = (\n markName: string,\n link: EditorTextLink,\n): Attrs | null => {\n if (markName === EditorMenuTypes.Link && link.href) {\n return {\n href: link.href,\n target: isExternalLink(link.href) ? '_blank' : null,\n };\n }\n\n return undefined;\n};\n\nexport const isExternalLink = (url: string): boolean => {\n return !url.startsWith(window.location.origin);\n};\n\n/**\n * Toggles or wraps a node type based on the selection and parameters.\n * - Toggles to paragraph if the selection is of the specified type.\n * - Lifts content out if already wrapped in the specified type.\n * - Wraps or sets the selection to the specified type based on `shouldWrap`.\n * @param schema - ProseMirror schema.\n * @param type - Block type name to toggle.\n * @param attrs - Attributes for the block type.\n * @param shouldWrap - Wrap selection if true, otherwise directly set the block type for the selection.\n * @returns A command based on selection and action needed.\n */\nconst toggleNodeType = (\n schema: Schema,\n type: string,\n attrs: Attrs = {},\n shouldWrap: boolean = false,\n): Command => {\n const nodeType = schema.nodes[type];\n const paragraphType = schema.nodes.paragraph;\n\n return (state, dispatch) => {\n const { $from, $to } = state.selection;\n\n const hasActiveWrap = $from.node($from.depth - 1).type === nodeType;\n\n if (\n state.selection instanceof TextSelection &&\n // Ensure selection is within the same parent block\n // We don't want toggling block types across multiple blocks\n $from.sameParent($from.doc.resolve($to.pos))\n ) {\n if ($from.parent.type === nodeType) {\n if (dispatch) {\n dispatch(\n state.tr.setBlockType(\n $from.pos,\n $to.pos,\n paragraphType,\n ),\n );\n }\n\n return true;\n } else {\n if (hasActiveWrap) {\n return lift(state, dispatch);\n }\n\n if (shouldWrap) {\n return wrapIn(nodeType, attrs)(state, dispatch);\n } else {\n return setBlockType(nodeType, attrs)(state, dispatch);\n }\n }\n }\n\n return false;\n };\n};\n\nconst createSetNodeTypeCommand = (\n schema: Schema,\n nodeType: string,\n level?: number,\n): CommandWithActive => {\n const type: NodeType | undefined = schema.nodes[nodeType];\n if (!type) {\n throw new Error(`Node type \"${nodeType}\" not found in schema`);\n }\n\n let command: CommandWithActive;\n if (nodeType === LevelMapping.Heading && level) {\n command = toggleNodeType(schema, LevelMapping.Heading, {\n level: level,\n });\n } else if (nodeType === EditorMenuTypes.CodeBlock) {\n command = toggleNodeType(schema, EditorMenuTypes.CodeBlock);\n } else {\n command = setBlockType(type);\n }\n\n setActiveMethodForNode(command, type, level);\n\n return command;\n};\n\nconst createWrapInCommand = (\n schema: Schema,\n nodeType: string,\n): CommandWithActive => {\n const type: NodeType | undefined = schema.nodes[nodeType];\n if (!type) {\n throw new Error(`Node type \"${nodeType}\" not found in schema`);\n }\n\n let command: CommandWithActive;\n if (nodeType === EditorMenuTypes.Blockquote) {\n command = toggleNodeType(schema, EditorMenuTypes.Blockquote, {}, true);\n } else {\n command = wrapIn(type);\n }\n\n setActiveMethodForWrap(command, type);\n\n return command;\n};\n\nconst toggleList = (listType) => {\n return (state, dispatch) => {\n const { $from, $to } = state.selection;\n const range = $from.blockRange($to);\n\n if (!range) {\n return false;\n }\n\n const wrapping = range && findWrapping(range, listType);\n\n if (wrapping) {\n // Wrap the selection in a list\n if (dispatch) {\n dispatch(state.tr.wrap(range, wrapping).scrollIntoView());\n }\n\n return true;\n } else {\n // Check if we are in a list item and lift out of the list\n const liftRange = range && liftTarget(range);\n if (liftRange !== null) {\n if (dispatch) {\n dispatch(state.tr.lift(range, liftRange).scrollIntoView());\n }\n\n return true;\n }\n\n return false;\n }\n };\n};\n\nconst createListCommand = (\n schema: Schema,\n listType: string,\n): CommandWithActive => {\n const type: NodeType | undefined = schema.nodes[listType];\n if (!type) {\n throw new Error(`List type \"${listType}\" not found in schema`);\n }\n\n const command: CommandWithActive = toggleList(type);\n setActiveMethodForWrap(command, type);\n\n return command;\n};\n\nconst commandMapping: CommandMapping = {\n strong: createToggleMarkCommand,\n em: createToggleMarkCommand,\n underline: createToggleMarkCommand,\n strikethrough: createToggleMarkCommand,\n code: createToggleMarkCommand,\n link: createInsertLinkCommand,\n headerlevel1: (schema) =>\n createSetNodeTypeCommand(\n schema,\n LevelMapping.Heading,\n LevelMapping.one,\n ),\n headerlevel2: (schema) =>\n createSetNodeTypeCommand(\n schema,\n LevelMapping.Heading,\n LevelMapping.two,\n ),\n headerlevel3: (schema) =>\n createSetNodeTypeCommand(\n schema,\n LevelMapping.Heading,\n LevelMapping.three,\n ),\n blockquote: (schema) =>\n createWrapInCommand(schema, EditorMenuTypes.Blockquote),\n /* eslint-disable camelcase */\n code_block: (schema) =>\n createSetNodeTypeCommand(schema, EditorMenuTypes.CodeBlock),\n ordered_list: (schema) =>\n createListCommand(schema, EditorMenuTypes.OrderedList),\n bullet_list: (schema) =>\n createListCommand(schema, EditorMenuTypes.BulletList),\n /* eslint-enable camelcase */\n};\n\nexport class MenuCommandFactory {\n private schema: Schema;\n\n constructor(schema: Schema) {\n this.schema = schema;\n }\n\n public getCommand(mark: EditorMenuTypes, link?: EditorTextLink) {\n const commandFunc = commandMapping[mark];\n if (!commandFunc) {\n throw new Error(`The Mark \"${mark}\" is not supported`);\n }\n\n return commandFunc(this.schema, mark, link);\n }\n\n buildKeymap() {\n return {\n 'Mod-B': this.getCommand(EditorMenuTypes.Bold),\n 'Mod-I': this.getCommand(EditorMenuTypes.Italic),\n 'Mod-Shift-1': this.getCommand(EditorMenuTypes.HeaderLevel1),\n 'Mod-Shift-2': this.getCommand(EditorMenuTypes.HeaderLevel2),\n 'Mod-Shift-3': this.getCommand(EditorMenuTypes.HeaderLevel3),\n 'Mod-Shift-X': this.getCommand(EditorMenuTypes.Strikethrough),\n 'Mod-`': this.getCommand(EditorMenuTypes.Code),\n 'Mod-Shift-C': this.getCommand(EditorMenuTypes.CodeBlock),\n };\n }\n}\n"]}
@@ -132,9 +132,29 @@ const processPasteEvent = (view, event, slice) => {
132
132
  if (!clipboardData) {
133
133
  return false;
134
134
  }
135
+ const isImageFilePasted = handlePastedImages(view, clipboardData);
136
+ const filteredSlice = new Slice(filterImageNodes(slice.content), slice.openStart, slice.openEnd);
137
+ if (filteredSlice.content.childCount < slice.content.childCount) {
138
+ const { state, dispatch } = view;
139
+ const tr = state.tr.replaceSelection(filteredSlice);
140
+ dispatch(tr);
141
+ return true;
142
+ }
143
+ return isImageFilePasted;
144
+ };
145
+ /**
146
+ * Processes any image files found in the clipboard data and dispatches an imagePasted event.
147
+ *
148
+ * @param view - The ProseMirror editor view
149
+ * @param clipboardData - The clipboard data transfer object containing potential image files
150
+ * @returns True if at least one valid image file was found and processed, false otherwise
151
+ */
152
+ function handlePastedImages(view, clipboardData) {
153
+ let isImageFilePasted = false;
135
154
  const files = Array.from(clipboardData.files || []);
136
155
  for (const file of files) {
137
- if (file.type.startsWith('image/')) {
156
+ if (isImageFile(file, clipboardData)) {
157
+ isImageFilePasted = true;
138
158
  const reader = new FileReader();
139
159
  reader.onloadend = () => {
140
160
  view.dom.dispatchEvent(new CustomEvent('imagePasted', {
@@ -144,13 +164,43 @@ const processPasteEvent = (view, event, slice) => {
144
164
  reader.readAsDataURL(file);
145
165
  }
146
166
  }
147
- const filteredSlice = new Slice(filterImageNodes(slice.content), slice.openStart, slice.openEnd);
148
- if (filteredSlice.content.childCount < slice.content.childCount) {
149
- const { state, dispatch } = view;
150
- const tr = state.tr.replaceSelection(filteredSlice);
151
- dispatch(tr);
152
- return true;
167
+ return isImageFilePasted;
168
+ }
169
+ /**
170
+ * Determines if a file is an image that should be processed by the image handler.
171
+ *
172
+ * This function checks both the file's MIME type and the clipboard HTML content.
173
+ * It filters out HTML content from Excel and HTML tables, as they are not relevant for image processing.
174
+ *
175
+ * @param file - The file object to check
176
+ * @param clipboardData - The full clipboard data transfer object to examine for context
177
+ * @returns True if the file is an image that should be processed, false otherwise
178
+ */
179
+ function isImageFile(file, clipboardData) {
180
+ var _a, _b;
181
+ if (!isContentTypeImage(file)) {
182
+ return false;
153
183
  }
154
- return files.length > 0;
155
- };
184
+ const html = (_b = (_a = clipboardData === null || clipboardData === void 0 ? void 0 : clipboardData.getData('text/html')) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== null && _b !== void 0 ? _b : '';
185
+ return !isHtmlFromExcel(html) && !isHtmlTable(html);
186
+ }
187
+ function isContentTypeImage(file) {
188
+ if (!(file === null || file === void 0 ? void 0 : file.type)) {
189
+ return false;
190
+ }
191
+ return file.type.startsWith('image/');
192
+ }
193
+ function isHtmlFromExcel(html) {
194
+ if (!html) {
195
+ return false;
196
+ }
197
+ return (html.includes('name=generator content="microsoft excel"') ||
198
+ html.includes('xmlns:x="urn:schemas-microsoft-com:office:excel"'));
199
+ }
200
+ function isHtmlTable(html) {
201
+ if (!html) {
202
+ return false;
203
+ }
204
+ return html.includes('<table');
205
+ }
156
206
  //# sourceMappingURL=inserter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"inserter.js","sourceRoot":"","sources":["../../../../../../src/components/text-editor/prosemirror-adapter/plugins/image/inserter.ts"],"names":[],"mappings":"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","sourcesContent":["import { Plugin, PluginKey } from 'prosemirror-state';\nimport { EditorView } from 'prosemirror-view';\nimport { createFileInfo } from '../../../../../util/files';\nimport { FileInfo } from '../../../../../global/shared-types/file.types';\nimport { ImageInserter, EditorImageState } from '../../../text-editor.types';\nimport { Node, Slice, Fragment } from 'prosemirror-model';\nimport { ImageNodeAttrs } from './node';\n\nexport const pluginKey = new PluginKey('imageInserterPlugin');\n\ntype ImagePastedCallback = (data: ImageInserter) => CustomEvent<ImageInserter>;\n\nexport const createImageInserterPlugin = (\n imagePastedCallback: ImagePastedCallback,\n) => {\n return new Plugin({\n key: pluginKey,\n props: {\n handlePaste: (view, event, slice) => {\n return processPasteEvent(view, event, slice);\n },\n handleDOMEvents: {\n imagePasted: (_, event) => {\n imagePastedCallback(event.detail);\n },\n },\n },\n });\n};\n\nexport const imageInserterFactory = (\n view: EditorView,\n base64Data: string,\n fileInfo: FileInfo,\n): ImageInserter => {\n return {\n fileInfo: fileInfo,\n insertThumbnail: createThumbnailInserter(view, base64Data, fileInfo),\n insertImage: createImageInserter(view, fileInfo),\n insertFailedThumbnail: createFailedThumbnailInserter(view, fileInfo),\n };\n};\n\nconst createThumbnailInserter =\n (view: EditorView, base64Data: string, fileInfo: FileInfo) => () => {\n const { state, dispatch } = view;\n const { schema } = state;\n\n const imageNodeAttrs = createImageNodeAttrs(\n base64Data,\n fileInfo,\n 'loading',\n );\n const placeholderNode = schema.nodes.image.create(imageNodeAttrs);\n\n const transaction = state.tr.replaceSelectionWith(placeholderNode);\n\n dispatch(transaction);\n };\n\nconst createImageInserter =\n (view: EditorView, fileInfo: FileInfo) => (src?: string) => {\n const { state, dispatch } = view;\n const { schema } = state;\n\n const tr = state.tr;\n state.doc.descendants((node, pos) => {\n if (node.attrs.fileInfoId === fileInfo.id) {\n const imageNodeAttrs = createImageNodeAttrs(\n src ? src : node.attrs.src,\n fileInfo,\n 'success',\n );\n const imageNode = schema.nodes.image.create(imageNodeAttrs);\n\n tr.replaceWith(pos, pos + node.nodeSize, imageNode);\n\n return false;\n }\n });\n\n dispatch(tr);\n };\n\nconst createFailedThumbnailInserter =\n (view: EditorView, fileInfo: FileInfo) => () => {\n const { state, dispatch } = view;\n const { schema } = state;\n\n const tr = state.tr;\n state.doc.descendants((node, pos) => {\n if (node.attrs.fileInfoId === fileInfo.id) {\n const imageNodeAttrs = createImageNodeAttrs(\n node.attrs.src,\n fileInfo,\n 'failed',\n );\n const errorPlaceholderNode =\n schema.nodes.image.create(imageNodeAttrs);\n\n tr.replaceWith(pos, pos + node.nodeSize, errorPlaceholderNode);\n\n return false;\n }\n });\n\n dispatch(tr);\n };\n\nfunction createImageNodeAttrs(\n src: string,\n fileInfo: FileInfo,\n state: EditorImageState,\n): ImageNodeAttrs {\n return {\n src: src,\n alt: fileInfo.filename,\n fileInfoId: fileInfo.id,\n state: state,\n };\n}\n\n/**\n * Check if a given ProseMirror node or fragment contains any image nodes.\n * @param node - The ProseMirror node or fragment to check.\n * @returns A boolean indicating whether the node contains any image nodes.\n */\nconst isImageNode = (node: Node | Fragment): boolean => {\n if (node instanceof Node) {\n if (node.type.name === 'image') {\n return true;\n }\n\n let found = false;\n node.content.forEach((child) => {\n if (isImageNode(child)) {\n found = true;\n }\n });\n\n return found;\n } else if (node instanceof Fragment) {\n let found = false;\n node.forEach((child) => {\n if (isImageNode(child)) {\n found = true;\n }\n });\n\n return found;\n }\n\n return false;\n};\n\n/**\n * Filter out image nodes from a ProseMirror fragment.\n * @param fragment - The ProseMirror fragment to filter.\n * @returns A new fragment with image nodes removed.\n */\nconst filterImageNodes = (fragment: Fragment): Fragment => {\n const filteredChildren: Node[] = [];\n\n fragment.forEach((child) => {\n if (!isImageNode(child)) {\n if (child.content.size > 0) {\n const filteredContent = filterImageNodes(child.content);\n const newNode = child.copy(filteredContent);\n filteredChildren.push(newNode);\n } else {\n filteredChildren.push(child);\n }\n }\n });\n\n return Fragment.fromArray(filteredChildren);\n};\n\n/**\n * Process a paste event and trigger an imagePasted event if an image file is pasted.\n * If an HTML image element is pasted, this image is filtered out from the slice content.\n *\n * @param view - The ProseMirror editor view.\n * @param event - The paste event.\n * @returns A boolean; True if an image file was pasted to prevent default paste behavior, otherwise false.\n */\nconst processPasteEvent = (\n view: EditorView,\n event: ClipboardEvent,\n slice: Slice,\n): boolean => {\n const clipboardData = event.clipboardData;\n if (!clipboardData) {\n return false;\n }\n\n const files = Array.from(clipboardData.files || []);\n for (const file of files) {\n if (file.type.startsWith('image/')) {\n const reader = new FileReader();\n reader.onloadend = () => {\n view.dom.dispatchEvent(\n new CustomEvent('imagePasted', {\n detail: imageInserterFactory(\n view,\n reader.result as string,\n createFileInfo(file),\n ),\n }),\n );\n };\n\n reader.readAsDataURL(file);\n }\n }\n\n const filteredSlice = new Slice(\n filterImageNodes(slice.content),\n slice.openStart,\n slice.openEnd,\n );\n\n if (filteredSlice.content.childCount < slice.content.childCount) {\n const { state, dispatch } = view;\n const tr = state.tr.replaceSelection(filteredSlice);\n dispatch(tr);\n\n return true;\n }\n\n return files.length > 0;\n};\n"]}
1
+ {"version":3,"file":"inserter.js","sourceRoot":"","sources":["../../../../../../src/components/text-editor/prosemirror-adapter/plugins/image/inserter.ts"],"names":[],"mappings":"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","sourcesContent":["import { Plugin, PluginKey } from 'prosemirror-state';\nimport { EditorView } from 'prosemirror-view';\nimport { createFileInfo } from '../../../../../util/files';\nimport { FileInfo } from '../../../../../global/shared-types/file.types';\nimport { ImageInserter, EditorImageState } from '../../../text-editor.types';\nimport { Node, Slice, Fragment } from 'prosemirror-model';\nimport { ImageNodeAttrs } from './node';\n\nexport const pluginKey = new PluginKey('imageInserterPlugin');\n\ntype ImagePastedCallback = (data: ImageInserter) => CustomEvent<ImageInserter>;\n\nexport const createImageInserterPlugin = (\n imagePastedCallback: ImagePastedCallback,\n) => {\n return new Plugin({\n key: pluginKey,\n props: {\n handlePaste: (view, event, slice) => {\n return processPasteEvent(view, event, slice);\n },\n handleDOMEvents: {\n imagePasted: (_, event) => {\n imagePastedCallback(event.detail);\n },\n },\n },\n });\n};\n\nexport const imageInserterFactory = (\n view: EditorView,\n base64Data: string,\n fileInfo: FileInfo,\n): ImageInserter => {\n return {\n fileInfo: fileInfo,\n insertThumbnail: createThumbnailInserter(view, base64Data, fileInfo),\n insertImage: createImageInserter(view, fileInfo),\n insertFailedThumbnail: createFailedThumbnailInserter(view, fileInfo),\n };\n};\n\nconst createThumbnailInserter =\n (view: EditorView, base64Data: string, fileInfo: FileInfo) => () => {\n const { state, dispatch } = view;\n const { schema } = state;\n\n const imageNodeAttrs = createImageNodeAttrs(\n base64Data,\n fileInfo,\n 'loading',\n );\n const placeholderNode = schema.nodes.image.create(imageNodeAttrs);\n\n const transaction = state.tr.replaceSelectionWith(placeholderNode);\n\n dispatch(transaction);\n };\n\nconst createImageInserter =\n (view: EditorView, fileInfo: FileInfo) => (src?: string) => {\n const { state, dispatch } = view;\n const { schema } = state;\n\n const tr = state.tr;\n state.doc.descendants((node, pos) => {\n if (node.attrs.fileInfoId === fileInfo.id) {\n const imageNodeAttrs = createImageNodeAttrs(\n src ? src : node.attrs.src,\n fileInfo,\n 'success',\n );\n const imageNode = schema.nodes.image.create(imageNodeAttrs);\n\n tr.replaceWith(pos, pos + node.nodeSize, imageNode);\n\n return false;\n }\n });\n\n dispatch(tr);\n };\n\nconst createFailedThumbnailInserter =\n (view: EditorView, fileInfo: FileInfo) => () => {\n const { state, dispatch } = view;\n const { schema } = state;\n\n const tr = state.tr;\n state.doc.descendants((node, pos) => {\n if (node.attrs.fileInfoId === fileInfo.id) {\n const imageNodeAttrs = createImageNodeAttrs(\n node.attrs.src,\n fileInfo,\n 'failed',\n );\n const errorPlaceholderNode =\n schema.nodes.image.create(imageNodeAttrs);\n\n tr.replaceWith(pos, pos + node.nodeSize, errorPlaceholderNode);\n\n return false;\n }\n });\n\n dispatch(tr);\n };\n\nfunction createImageNodeAttrs(\n src: string,\n fileInfo: FileInfo,\n state: EditorImageState,\n): ImageNodeAttrs {\n return {\n src: src,\n alt: fileInfo.filename,\n fileInfoId: fileInfo.id,\n state: state,\n };\n}\n\n/**\n * Check if a given ProseMirror node or fragment contains any image nodes.\n * @param node - The ProseMirror node or fragment to check.\n * @returns A boolean indicating whether the node contains any image nodes.\n */\nconst isImageNode = (node: Node | Fragment): boolean => {\n if (node instanceof Node) {\n if (node.type.name === 'image') {\n return true;\n }\n\n let found = false;\n node.content.forEach((child) => {\n if (isImageNode(child)) {\n found = true;\n }\n });\n\n return found;\n } else if (node instanceof Fragment) {\n let found = false;\n node.forEach((child) => {\n if (isImageNode(child)) {\n found = true;\n }\n });\n\n return found;\n }\n\n return false;\n};\n\n/**\n * Filter out image nodes from a ProseMirror fragment.\n * @param fragment - The ProseMirror fragment to filter.\n * @returns A new fragment with image nodes removed.\n */\nconst filterImageNodes = (fragment: Fragment): Fragment => {\n const filteredChildren: Node[] = [];\n\n fragment.forEach((child) => {\n if (!isImageNode(child)) {\n if (child.content.size > 0) {\n const filteredContent = filterImageNodes(child.content);\n const newNode = child.copy(filteredContent);\n filteredChildren.push(newNode);\n } else {\n filteredChildren.push(child);\n }\n }\n });\n\n return Fragment.fromArray(filteredChildren);\n};\n\n/**\n * Process a paste event and trigger an imagePasted event if an image file is pasted.\n * If an HTML image element is pasted, this image is filtered out from the slice content.\n *\n * @param view - The ProseMirror editor view.\n * @param event - The paste event.\n * @returns A boolean; True if an image file was pasted to prevent default paste behavior, otherwise false.\n */\nconst processPasteEvent = (\n view: EditorView,\n event: ClipboardEvent,\n slice: Slice,\n): boolean => {\n const clipboardData = event.clipboardData;\n if (!clipboardData) {\n return false;\n }\n\n const isImageFilePasted = handlePastedImages(view, clipboardData);\n\n const filteredSlice = new Slice(\n filterImageNodes(slice.content),\n slice.openStart,\n slice.openEnd,\n );\n\n if (filteredSlice.content.childCount < slice.content.childCount) {\n const { state, dispatch } = view;\n const tr = state.tr.replaceSelection(filteredSlice);\n dispatch(tr);\n\n return true;\n }\n\n return isImageFilePasted;\n};\n\n/**\n * Processes any image files found in the clipboard data and dispatches an imagePasted event.\n *\n * @param view - The ProseMirror editor view\n * @param clipboardData - The clipboard data transfer object containing potential image files\n * @returns True if at least one valid image file was found and processed, false otherwise\n */\nfunction handlePastedImages(\n view: EditorView,\n clipboardData: DataTransfer,\n): boolean {\n let isImageFilePasted = false;\n const files = Array.from(clipboardData.files || []);\n\n for (const file of files) {\n if (isImageFile(file, clipboardData)) {\n isImageFilePasted = true;\n\n const reader = new FileReader();\n reader.onloadend = () => {\n view.dom.dispatchEvent(\n new CustomEvent('imagePasted', {\n detail: imageInserterFactory(\n view,\n reader.result as string,\n createFileInfo(file),\n ),\n }),\n );\n };\n\n reader.readAsDataURL(file);\n }\n }\n\n return isImageFilePasted;\n}\n\n/**\n * Determines if a file is an image that should be processed by the image handler.\n *\n * This function checks both the file's MIME type and the clipboard HTML content.\n * It filters out HTML content from Excel and HTML tables, as they are not relevant for image processing.\n *\n * @param file - The file object to check\n * @param clipboardData - The full clipboard data transfer object to examine for context\n * @returns True if the file is an image that should be processed, false otherwise\n */\nfunction isImageFile(file: File, clipboardData: DataTransfer): boolean {\n if (!isContentTypeImage(file)) {\n return false;\n }\n\n const html = clipboardData?.getData('text/html')?.toLowerCase() ?? '';\n\n return !isHtmlFromExcel(html) && !isHtmlTable(html);\n}\n\nfunction isContentTypeImage(file: File): boolean {\n if (!file?.type) {\n return false;\n }\n\n return file.type.startsWith('image/');\n}\n\nfunction isHtmlFromExcel(html: string): boolean {\n if (!html) {\n return false;\n }\n\n return (\n html.includes('name=generator content=\"microsoft excel\"') ||\n html.includes('xmlns:x=\"urn:schemas-microsoft-com:office:excel\"')\n );\n}\n\nfunction isHtmlTable(html: string): boolean {\n if (!html) {\n return false;\n }\n\n return html.includes('<table');\n}\n"]}
@@ -0,0 +1,33 @@
1
+ export const linkMarkSpec = {
2
+ attrs: {
3
+ href: { default: '' },
4
+ title: { default: null },
5
+ target: { default: null },
6
+ rel: { default: null },
7
+ referrerpolicy: { default: null },
8
+ },
9
+ inclusive: false,
10
+ parseDOM: [
11
+ {
12
+ tag: 'a[href]',
13
+ getAttrs: (dom) => {
14
+ return {
15
+ href: dom.getAttribute('href') || '',
16
+ title: dom.getAttribute('title'),
17
+ target: dom.getAttribute('target'),
18
+ rel: dom.getAttribute('rel'),
19
+ referrerpolicy: dom.getAttribute('referrerpolicy'),
20
+ };
21
+ },
22
+ },
23
+ ],
24
+ toDOM: (mark) => {
25
+ const target = mark.attrs.target || null;
26
+ const securityAttrs = {
27
+ rel: target === '_blank' ? 'noopener noreferrer' : null,
28
+ referrerpolicy: target === '_blank' ? 'noreferrer' : null,
29
+ };
30
+ return ['a', Object.assign(Object.assign({}, mark.attrs), securityAttrs), 0];
31
+ },
32
+ };
33
+ //# sourceMappingURL=link-mark-spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link-mark-spec.js","sourceRoot":"","sources":["../../../../../../src/components/text-editor/prosemirror-adapter/plugins/link/link-mark-spec.ts"],"names":[],"mappings":"AAUA,MAAM,CAAC,MAAM,YAAY,GAAa;EAClC,KAAK,EAAE;IACH,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;IACrB,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;IACxB,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;IACzB,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;IACtB,cAAc,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;GACpC;EACD,SAAS,EAAE,KAAK;EAChB,QAAQ,EAAE;IACN;MACI,GAAG,EAAE,SAAS;MACd,QAAQ,EAAE,CAAC,GAAgB,EAAiB,EAAE;QAC1C,OAAO;UACH,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE;UACpC,KAAK,EAAE,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC;UAChC,MAAM,EAAE,GAAG,CAAC,YAAY,CAAC,QAAQ,CAAC;UAClC,GAAG,EAAE,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC;UAC5B,cAAc,EAAE,GAAG,CAAC,YAAY,CAAC,gBAAgB,CAAC;SACrD,CAAC;MACN,CAAC;KACJ;GACJ;EACD,KAAK,EAAE,CAAC,IAAI,EAAiB,EAAE;IAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC;IAEzC,MAAM,aAAa,GAAG;MAClB,GAAG,EAAE,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,IAAI;MACvD,cAAc,EAAE,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI;KAC5D,CAAC;IAEF,OAAO,CAAC,GAAG,kCAAO,IAAI,CAAC,KAAK,GAAK,aAAa,GAAI,CAAC,CAAC,CAAC;EACzD,CAAC;CACJ,CAAC","sourcesContent":["import { MarkSpec, DOMOutputSpec } from 'prosemirror-model';\n\nexport interface LinkMarkAttrs {\n href: string;\n title: string | null;\n target: string | null;\n rel: string | null;\n referrerpolicy: string | null;\n}\n\nexport const linkMarkSpec: MarkSpec = {\n attrs: {\n href: { default: '' },\n title: { default: null },\n target: { default: null },\n rel: { default: null },\n referrerpolicy: { default: null },\n },\n inclusive: false,\n parseDOM: [\n {\n tag: 'a[href]',\n getAttrs: (dom: HTMLElement): LinkMarkAttrs => {\n return {\n href: dom.getAttribute('href') || '',\n title: dom.getAttribute('title'),\n target: dom.getAttribute('target'),\n rel: dom.getAttribute('rel'),\n referrerpolicy: dom.getAttribute('referrerpolicy'),\n };\n },\n },\n ],\n toDOM: (mark): DOMOutputSpec => {\n const target = mark.attrs.target || null;\n\n const securityAttrs = {\n rel: target === '_blank' ? 'noopener noreferrer' : null,\n referrerpolicy: target === '_blank' ? 'noreferrer' : null,\n };\n\n return ['a', { ...mark.attrs, ...securityAttrs }, 0];\n },\n};\n"]}