@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.
- package/CHANGELOG.md +17 -0
- package/dist/cjs/limel-markdown.cjs.entry.js +1 -1
- package/dist/cjs/limel-prosemirror-adapter.cjs.entry.js +228 -71
- package/dist/cjs/limel-prosemirror-adapter.cjs.entry.js.map +1 -1
- package/dist/cjs/{markdown-parser-564adb69.js → markdown-parser-563c73db.js} +144 -386
- package/dist/cjs/{markdown-parser-564adb69.js.map → markdown-parser-563c73db.js.map} +1 -1
- package/dist/collection/components/markdown/link-markdown-plugin.js +30 -0
- package/dist/collection/components/markdown/link-markdown-plugin.js.map +1 -0
- package/dist/collection/components/markdown/markdown-parser.js +4 -4
- package/dist/collection/components/markdown/markdown-parser.js.map +1 -1
- package/dist/collection/components/text-editor/prosemirror-adapter/menu/menu-commands.js +3 -42
- package/dist/collection/components/text-editor/prosemirror-adapter/menu/menu-commands.js.map +1 -1
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/inserter.js +59 -9
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/inserter.js.map +1 -1
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/link/link-mark-spec.js +33 -0
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/link/link-mark-spec.js.map +1 -0
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/{link-plugin.js → link/link-plugin.js} +135 -22
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/link/link-plugin.js.map +1 -0
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/link/utils.js +39 -0
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/link/utils.js.map +1 -0
- package/dist/collection/components/text-editor/prosemirror-adapter/prosemirror-adapter.js +3 -1
- package/dist/collection/components/text-editor/prosemirror-adapter/prosemirror-adapter.js.map +1 -1
- package/dist/esm/limel-markdown.entry.js +1 -1
- package/dist/esm/limel-prosemirror-adapter.entry.js +228 -71
- package/dist/esm/limel-prosemirror-adapter.entry.js.map +1 -1
- package/dist/esm/{markdown-parser-1c1fdedc.js → markdown-parser-41d15994.js} +144 -387
- package/dist/esm/markdown-parser-41d15994.js.map +1 -0
- package/dist/lime-elements/lime-elements.esm.js +1 -1
- package/dist/lime-elements/p-6b5d588e.entry.js +2 -0
- package/dist/lime-elements/p-6b5d588e.entry.js.map +1 -0
- package/dist/lime-elements/{p-ce152b39.entry.js → p-895ae176.entry.js} +2 -2
- package/dist/lime-elements/p-95a71e89.js +8 -0
- package/dist/lime-elements/p-95a71e89.js.map +1 -0
- package/dist/types/components/markdown/link-markdown-plugin.d.ts +9 -0
- package/dist/types/components/text-editor/prosemirror-adapter/menu/menu-commands.d.ts +0 -2
- package/dist/types/components/text-editor/prosemirror-adapter/plugins/link/link-mark-spec.d.ts +10 -0
- package/dist/types/components/text-editor/prosemirror-adapter/plugins/link/utils.d.ts +3 -0
- package/package.json +1 -2
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/link-plugin.js.map +0 -1
- package/dist/esm/markdown-parser-1c1fdedc.js.map +0 -1
- package/dist/lime-elements/p-587f6b6d.entry.js +0 -2
- package/dist/lime-elements/p-587f6b6d.entry.js.map +0 -1
- package/dist/lime-elements/p-cf87519f.js +0 -8
- package/dist/lime-elements/p-cf87519f.js.map +0 -1
- /package/dist/lime-elements/{p-ce152b39.entry.js.map → p-895ae176.entry.js.map} +0 -0
- /package/dist/types/components/text-editor/prosemirror-adapter/plugins/{link-plugin.d.ts → link/link-plugin.d.ts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
## [38.13.2](https://github.com/Lundalogik/lime-elements/compare/v38.13.1...v38.13.2) (2025-05-23)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
* **markdown/text-editor:** properly handle internal vs external link targets ([e42123b](https://github.com/Lundalogik/lime-elements/commit/e42123b41fe2f3025c910325e37b2ac12c907cfb))
|
|
8
|
+
* **text-editor:** don't interpret `:` as links when pasting ([9509540](https://github.com/Lundalogik/lime-elements/commit/9509540f3591ab7401a53a5de48ca774a63ef2b2))
|
|
9
|
+
|
|
10
|
+
## [38.13.1](https://github.com/Lundalogik/lime-elements/compare/v38.13.0...v38.13.1) (2025-05-21)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
* **text-editor:** prevent Excel tables from being processed as images when pasted ([8ec93fb](https://github.com/Lundalogik/lime-elements/commit/8ec93fbeb751ba3c984d572a117a71de40f5c94a))
|
|
17
|
+
|
|
1
18
|
## [38.13.0](https://github.com/Lundalogik/lime-elements/compare/v38.12.5...v38.13.0) (2025-05-20)
|
|
2
19
|
|
|
3
20
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
const index = require('./index-174a078a.js');
|
|
6
|
-
const markdownParser = require('./markdown-parser-
|
|
6
|
+
const markdownParser = require('./markdown-parser-563c73db.js');
|
|
7
7
|
const config = require('./config-e7e1a299.js');
|
|
8
8
|
require('./_commonjsHelpers-a5111d61.js');
|
|
9
9
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
const index = require('./index-174a078a.js');
|
|
6
|
+
const markdownParser = require('./markdown-parser-563c73db.js');
|
|
6
7
|
const _baseIsEqual = require('./_baseIsEqual-244a20fe.js');
|
|
7
8
|
const _assignValue = require('./_assignValue-7a5440a6.js');
|
|
8
9
|
const _baseAssignValue = require('./_baseAssignValue-e84dd769.js');
|
|
@@ -12,19 +13,18 @@ const _getTag = require('./_getTag-92cb60fe.js');
|
|
|
12
13
|
const _getPrototype = require('./_getPrototype-18d2118e.js');
|
|
13
14
|
const isArray = require('./isArray-d188a04f.js');
|
|
14
15
|
const isObjectLike = require('./isObjectLike-3e3f0cba.js');
|
|
15
|
-
const markdownParser = require('./markdown-parser-564adb69.js');
|
|
16
16
|
const translations = require('./translations-1d376e48.js');
|
|
17
17
|
const randomString = require('./random-string-e8ad4419.js');
|
|
18
18
|
const isItem = require('./isItem-3f8ad629.js');
|
|
19
19
|
const files = require('./files-c08d24d4.js');
|
|
20
20
|
const isEqual = require('./isEqual-a4bccf32.js');
|
|
21
21
|
const debounce = require('./debounce-2e5f4b7e.js');
|
|
22
|
+
require('./_commonjsHelpers-a5111d61.js');
|
|
22
23
|
require('./eq-9a943b00.js');
|
|
23
24
|
require('./_getNative-60328036.js');
|
|
24
25
|
require('./_isIndex-b40f4fc5.js');
|
|
25
26
|
require('./isArrayLike-e840b044.js');
|
|
26
27
|
require('./_defineProperty-8f56146d.js');
|
|
27
|
-
require('./_commonjsHelpers-a5111d61.js');
|
|
28
28
|
require('./file-metadata-e309a7a4.js');
|
|
29
29
|
require('./get-icon-props-65f39e40.js');
|
|
30
30
|
require('./toNumber-062ea29c.js');
|
|
@@ -16902,24 +16902,15 @@ const setActiveMethodForWrap = (command, nodeType) => {
|
|
|
16902
16902
|
const createInsertLinkCommand = (schema, _, link) => {
|
|
16903
16903
|
const command = (state, dispatch) => {
|
|
16904
16904
|
const { from, to } = state.selection;
|
|
16905
|
+
const linkMark = schema.marks.link.create(markdownParser.getLinkAttributes(link.href, link.href));
|
|
16905
16906
|
if (from === to) {
|
|
16906
16907
|
// If no text is selected, insert new text with link
|
|
16907
|
-
const linkMark = schema.marks.link.create({
|
|
16908
|
-
href: link.href,
|
|
16909
|
-
title: link.href,
|
|
16910
|
-
target: isExternalLink(link.href) ? '_blank' : null,
|
|
16911
|
-
});
|
|
16912
16908
|
const linkText = link.text || link.href;
|
|
16913
16909
|
const newLink = schema.text(linkText, [linkMark]);
|
|
16914
16910
|
dispatch(state.tr.insert(from, newLink));
|
|
16915
16911
|
}
|
|
16916
16912
|
else {
|
|
16917
16913
|
// If text is selected, replace selected text with link text
|
|
16918
|
-
const linkMark = schema.marks.link.create({
|
|
16919
|
-
href: link.href,
|
|
16920
|
-
title: link.href,
|
|
16921
|
-
target: isExternalLink(link.href) ? '_blank' : null,
|
|
16922
|
-
});
|
|
16923
16914
|
const selectedText = state.doc.textBetween(from, to, ' ');
|
|
16924
16915
|
const newLink = schema.text(link.text || selectedText, [linkMark]);
|
|
16925
16916
|
dispatch(state.tr.replaceWith(from, to, newLink));
|
|
@@ -16993,15 +16984,6 @@ const toggleNodeType = (schema, type, attrs = {}, shouldWrap = false) => {
|
|
|
16993
16984
|
return false;
|
|
16994
16985
|
};
|
|
16995
16986
|
};
|
|
16996
|
-
const isValidUrl = (text) => {
|
|
16997
|
-
try {
|
|
16998
|
-
new URL(text);
|
|
16999
|
-
}
|
|
17000
|
-
catch (_a) {
|
|
17001
|
-
return false;
|
|
17002
|
-
}
|
|
17003
|
-
return true;
|
|
17004
|
-
};
|
|
17005
16987
|
const createSetNodeTypeCommand = (schema, nodeType, level) => {
|
|
17006
16988
|
const type = schema.nodes[nodeType];
|
|
17007
16989
|
if (!type) {
|
|
@@ -17074,27 +17056,6 @@ const createListCommand = (schema, listType) => {
|
|
|
17074
17056
|
setActiveMethodForWrap(command, type);
|
|
17075
17057
|
return command;
|
|
17076
17058
|
};
|
|
17077
|
-
const copyPasteLinkCommand = (state, dispatch) => {
|
|
17078
|
-
const { from, to } = state.selection;
|
|
17079
|
-
if (from === to) {
|
|
17080
|
-
return false;
|
|
17081
|
-
}
|
|
17082
|
-
const clipboardData = window.clipboardData;
|
|
17083
|
-
if (!clipboardData) {
|
|
17084
|
-
return false;
|
|
17085
|
-
}
|
|
17086
|
-
const copyPastedText = clipboardData.getData('text');
|
|
17087
|
-
if (!isValidUrl(copyPastedText)) {
|
|
17088
|
-
return false;
|
|
17089
|
-
}
|
|
17090
|
-
const linkMark = state.schema.marks.link.create({
|
|
17091
|
-
href: copyPastedText,
|
|
17092
|
-
target: isExternalLink(copyPastedText) ? '_blank' : null,
|
|
17093
|
-
});
|
|
17094
|
-
const selectedText = state.doc.textBetween(from, to, ' ');
|
|
17095
|
-
const newLink = state.schema.text(selectedText, [linkMark]);
|
|
17096
|
-
dispatch(state.tr.replaceWith(from, to, newLink));
|
|
17097
|
-
};
|
|
17098
17059
|
const commandMapping = {
|
|
17099
17060
|
strong: createToggleMarkCommand,
|
|
17100
17061
|
em: createToggleMarkCommand,
|
|
@@ -17133,7 +17094,6 @@ class MenuCommandFactory {
|
|
|
17133
17094
|
'Mod-Shift-X': this.getCommand(EditorMenuTypes.Strikethrough),
|
|
17134
17095
|
'Mod-`': this.getCommand(EditorMenuTypes.Code),
|
|
17135
17096
|
'Mod-Shift-C': this.getCommand(EditorMenuTypes.CodeBlock),
|
|
17136
|
-
'Mod-v': copyPasteLinkCommand,
|
|
17137
17097
|
};
|
|
17138
17098
|
}
|
|
17139
17099
|
}
|
|
@@ -26260,32 +26220,145 @@ const processClickEvent = (view, event) => {
|
|
|
26260
26220
|
}, DOUBLE_CLICK_DELAY);
|
|
26261
26221
|
return true;
|
|
26262
26222
|
};
|
|
26263
|
-
|
|
26264
|
-
|
|
26265
|
-
|
|
26223
|
+
/**
|
|
26224
|
+
* Regular expression for matching URLs, mailto links, and phone links
|
|
26225
|
+
*/
|
|
26226
|
+
const URL_REGEX = /(https?:\/\/[^\s<>"']+|mailto:[^\s<>"']+|tel:[^\s<>"']+)/g;
|
|
26227
|
+
/**
|
|
26228
|
+
* Checks if the text contains any URLs, mailto links, or phone links
|
|
26229
|
+
*/
|
|
26230
|
+
const hasUrls = (text) => {
|
|
26231
|
+
// Reset regex before use
|
|
26232
|
+
URL_REGEX.lastIndex = 0;
|
|
26233
|
+
return URL_REGEX.test(text);
|
|
26234
|
+
};
|
|
26235
|
+
/**
|
|
26236
|
+
* Creates a text node with the provided content
|
|
26237
|
+
*/
|
|
26238
|
+
const createTextNode = (schema, content) => {
|
|
26239
|
+
return schema.text(content);
|
|
26240
|
+
};
|
|
26241
|
+
/**
|
|
26242
|
+
* Creates a link node with the provided URL
|
|
26243
|
+
*/
|
|
26244
|
+
const createLinkNode = (schema, url) => {
|
|
26245
|
+
const linkMark = schema.marks.link.create(markdownParser.getLinkAttributes(url, url));
|
|
26246
|
+
return schema.text(url, [linkMark]);
|
|
26247
|
+
};
|
|
26248
|
+
/**
|
|
26249
|
+
* Finds all link matches in the provided text
|
|
26250
|
+
*/
|
|
26251
|
+
const findLinkMatches = (text) => {
|
|
26252
|
+
const matches = [];
|
|
26253
|
+
let match;
|
|
26254
|
+
// Reset regex before use
|
|
26255
|
+
URL_REGEX.lastIndex = 0;
|
|
26256
|
+
while ((match = URL_REGEX.exec(text)) !== null) {
|
|
26257
|
+
matches.push({
|
|
26258
|
+
url: match[0],
|
|
26259
|
+
start: match.index,
|
|
26260
|
+
end: match.index + match[0].length,
|
|
26261
|
+
});
|
|
26262
|
+
}
|
|
26263
|
+
return matches;
|
|
26264
|
+
};
|
|
26265
|
+
/**
|
|
26266
|
+
* Creates text nodes with links for any URLs, mailto links, or phone links found in the text
|
|
26267
|
+
*/
|
|
26268
|
+
const createNodesWithLinks = (text, schema) => {
|
|
26269
|
+
const nodes = [];
|
|
26270
|
+
const matches = findLinkMatches(text);
|
|
26271
|
+
if (matches.length === 0) {
|
|
26272
|
+
// No links found, just return the text as a single node
|
|
26273
|
+
return [createTextNode(schema, text)];
|
|
26274
|
+
}
|
|
26275
|
+
let lastIndex = 0;
|
|
26276
|
+
// Process each match
|
|
26277
|
+
for (const match of matches) {
|
|
26278
|
+
// Add text before the current link if any
|
|
26279
|
+
if (match.start > lastIndex) {
|
|
26280
|
+
nodes.push(createTextNode(schema, text.slice(lastIndex, match.start)));
|
|
26281
|
+
}
|
|
26282
|
+
// Add the link node
|
|
26283
|
+
nodes.push(createLinkNode(schema, match.url));
|
|
26284
|
+
lastIndex = match.end;
|
|
26285
|
+
}
|
|
26286
|
+
// Add any remaining text after the last link
|
|
26287
|
+
if (lastIndex < text.length) {
|
|
26288
|
+
nodes.push(createTextNode(schema, text.slice(lastIndex)));
|
|
26289
|
+
}
|
|
26290
|
+
return nodes;
|
|
26291
|
+
};
|
|
26292
|
+
/**
|
|
26293
|
+
* Pastes nodes at the current selection
|
|
26294
|
+
* @param view - The editor view
|
|
26295
|
+
* @param nodes - Array of nodes to paste
|
|
26296
|
+
*/
|
|
26297
|
+
const pasteAsLink = (view, nodes) => {
|
|
26298
|
+
if (nodes.length === 0) {
|
|
26299
|
+
return;
|
|
26300
|
+
}
|
|
26301
|
+
if (isSingleLinkNode(nodes)) {
|
|
26302
|
+
insertSingleLink(view, nodes[0]);
|
|
26303
|
+
}
|
|
26304
|
+
else {
|
|
26305
|
+
insertNodeFragment(view, nodes);
|
|
26306
|
+
}
|
|
26307
|
+
};
|
|
26308
|
+
/**
|
|
26309
|
+
* Checks if the nodes array contains just a single link node
|
|
26310
|
+
*/
|
|
26311
|
+
const isSingleLinkNode = (nodes) => {
|
|
26312
|
+
if (nodes.length !== 1) {
|
|
26266
26313
|
return false;
|
|
26267
26314
|
}
|
|
26268
|
-
const
|
|
26269
|
-
//
|
|
26270
|
-
if (
|
|
26271
|
-
|
|
26272
|
-
return true;
|
|
26315
|
+
const node = nodes[0];
|
|
26316
|
+
// Must be text with non-empty content
|
|
26317
|
+
if (!node.isText || !node.text || node.text.trim() === '') {
|
|
26318
|
+
return false;
|
|
26273
26319
|
}
|
|
26274
|
-
|
|
26320
|
+
// Must have a link mark (even if there are other marks, we just care about link presence)
|
|
26321
|
+
return !!node.marks.find((mark) => mark.type.name === 'link');
|
|
26275
26322
|
};
|
|
26276
|
-
|
|
26323
|
+
/**
|
|
26324
|
+
* Inserts a single link node, applying it to selected text if present
|
|
26325
|
+
*/
|
|
26326
|
+
const insertSingleLink = (view, linkNode) => {
|
|
26277
26327
|
const { state, dispatch } = view;
|
|
26278
26328
|
const { from, to } = state.selection;
|
|
26279
|
-
const linkMark =
|
|
26280
|
-
|
|
26281
|
-
|
|
26282
|
-
|
|
26283
|
-
|
|
26284
|
-
const selectedText = state.doc.textBetween(from, to, ' ') || href;
|
|
26285
|
-
const transaction = state.tr
|
|
26329
|
+
const linkMark = linkNode.marks.find((mark) => mark.type.name === 'link');
|
|
26330
|
+
// Use selected text if there's a selection, otherwise use the URL
|
|
26331
|
+
const selectedText = state.doc.textBetween(from, to, ' ') || linkMark.attrs.href;
|
|
26332
|
+
// Insert the text and add the link mark
|
|
26333
|
+
dispatch(state.tr
|
|
26286
26334
|
.insertText(selectedText, from, to)
|
|
26287
|
-
.addMark(from, from + selectedText.length, linkMark);
|
|
26288
|
-
|
|
26335
|
+
.addMark(from, from + selectedText.length, linkMark));
|
|
26336
|
+
};
|
|
26337
|
+
/**
|
|
26338
|
+
* Inserts multiple nodes as a fragment at the current selection
|
|
26339
|
+
* @param view - The editor view
|
|
26340
|
+
* @param nodes - Array of nodes to insert
|
|
26341
|
+
*/
|
|
26342
|
+
const insertNodeFragment = (view, nodes) => {
|
|
26343
|
+
const { state, dispatch } = view;
|
|
26344
|
+
const { from, to } = state.selection;
|
|
26345
|
+
// Create a fragment from the array of nodes
|
|
26346
|
+
const fragment = Fragment.fromArray(nodes);
|
|
26347
|
+
// Replace the current selection with the fragment
|
|
26348
|
+
dispatch(state.tr.replaceWith(from, to, fragment));
|
|
26349
|
+
};
|
|
26350
|
+
/**
|
|
26351
|
+
* Handles pasted content, converting URLs to links
|
|
26352
|
+
*/
|
|
26353
|
+
const processPasteEvent$1 = (view, event) => {
|
|
26354
|
+
var _a;
|
|
26355
|
+
const text = (_a = event.clipboardData) === null || _a === void 0 ? void 0 : _a.getData('text/plain');
|
|
26356
|
+
if (!text || !hasUrls(text)) {
|
|
26357
|
+
return false;
|
|
26358
|
+
}
|
|
26359
|
+
const nodes = createNodesWithLinks(text, view.state.schema);
|
|
26360
|
+
pasteAsLink(view, nodes);
|
|
26361
|
+
return true;
|
|
26289
26362
|
};
|
|
26290
26363
|
const createLinkPlugin = (updateLinkCallback) => {
|
|
26291
26364
|
return new Plugin({
|
|
@@ -26327,6 +26400,39 @@ const createLinkPlugin = (updateLinkCallback) => {
|
|
|
26327
26400
|
});
|
|
26328
26401
|
};
|
|
26329
26402
|
|
|
26403
|
+
const linkMarkSpec = {
|
|
26404
|
+
attrs: {
|
|
26405
|
+
href: { default: '' },
|
|
26406
|
+
title: { default: null },
|
|
26407
|
+
target: { default: null },
|
|
26408
|
+
rel: { default: null },
|
|
26409
|
+
referrerpolicy: { default: null },
|
|
26410
|
+
},
|
|
26411
|
+
inclusive: false,
|
|
26412
|
+
parseDOM: [
|
|
26413
|
+
{
|
|
26414
|
+
tag: 'a[href]',
|
|
26415
|
+
getAttrs: (dom) => {
|
|
26416
|
+
return {
|
|
26417
|
+
href: dom.getAttribute('href') || '',
|
|
26418
|
+
title: dom.getAttribute('title'),
|
|
26419
|
+
target: dom.getAttribute('target'),
|
|
26420
|
+
rel: dom.getAttribute('rel'),
|
|
26421
|
+
referrerpolicy: dom.getAttribute('referrerpolicy'),
|
|
26422
|
+
};
|
|
26423
|
+
},
|
|
26424
|
+
},
|
|
26425
|
+
],
|
|
26426
|
+
toDOM: (mark) => {
|
|
26427
|
+
const target = mark.attrs.target || null;
|
|
26428
|
+
const securityAttrs = {
|
|
26429
|
+
rel: target === '_blank' ? 'noopener noreferrer' : null,
|
|
26430
|
+
referrerpolicy: target === '_blank' ? 'noreferrer' : null,
|
|
26431
|
+
};
|
|
26432
|
+
return ['a', Object.assign(Object.assign({}, mark.attrs), securityAttrs), 0];
|
|
26433
|
+
},
|
|
26434
|
+
};
|
|
26435
|
+
|
|
26330
26436
|
const pluginKey = new PluginKey('imageInserterPlugin');
|
|
26331
26437
|
const createImageInserterPlugin = (imagePastedCallback) => {
|
|
26332
26438
|
return new Plugin({
|
|
@@ -26458,9 +26564,29 @@ const processPasteEvent = (view, event, slice) => {
|
|
|
26458
26564
|
if (!clipboardData) {
|
|
26459
26565
|
return false;
|
|
26460
26566
|
}
|
|
26567
|
+
const isImageFilePasted = handlePastedImages(view, clipboardData);
|
|
26568
|
+
const filteredSlice = new Slice(filterImageNodes(slice.content), slice.openStart, slice.openEnd);
|
|
26569
|
+
if (filteredSlice.content.childCount < slice.content.childCount) {
|
|
26570
|
+
const { state, dispatch } = view;
|
|
26571
|
+
const tr = state.tr.replaceSelection(filteredSlice);
|
|
26572
|
+
dispatch(tr);
|
|
26573
|
+
return true;
|
|
26574
|
+
}
|
|
26575
|
+
return isImageFilePasted;
|
|
26576
|
+
};
|
|
26577
|
+
/**
|
|
26578
|
+
* Processes any image files found in the clipboard data and dispatches an imagePasted event.
|
|
26579
|
+
*
|
|
26580
|
+
* @param view - The ProseMirror editor view
|
|
26581
|
+
* @param clipboardData - The clipboard data transfer object containing potential image files
|
|
26582
|
+
* @returns True if at least one valid image file was found and processed, false otherwise
|
|
26583
|
+
*/
|
|
26584
|
+
function handlePastedImages(view, clipboardData) {
|
|
26585
|
+
let isImageFilePasted = false;
|
|
26461
26586
|
const files$1 = Array.from(clipboardData.files || []);
|
|
26462
26587
|
for (const file of files$1) {
|
|
26463
|
-
if (file
|
|
26588
|
+
if (isImageFile(file, clipboardData)) {
|
|
26589
|
+
isImageFilePasted = true;
|
|
26464
26590
|
const reader = new FileReader();
|
|
26465
26591
|
reader.onloadend = () => {
|
|
26466
26592
|
view.dom.dispatchEvent(new CustomEvent('imagePasted', {
|
|
@@ -26470,15 +26596,45 @@ const processPasteEvent = (view, event, slice) => {
|
|
|
26470
26596
|
reader.readAsDataURL(file);
|
|
26471
26597
|
}
|
|
26472
26598
|
}
|
|
26473
|
-
|
|
26474
|
-
|
|
26475
|
-
|
|
26476
|
-
|
|
26477
|
-
|
|
26478
|
-
|
|
26599
|
+
return isImageFilePasted;
|
|
26600
|
+
}
|
|
26601
|
+
/**
|
|
26602
|
+
* Determines if a file is an image that should be processed by the image handler.
|
|
26603
|
+
*
|
|
26604
|
+
* This function checks both the file's MIME type and the clipboard HTML content.
|
|
26605
|
+
* It filters out HTML content from Excel and HTML tables, as they are not relevant for image processing.
|
|
26606
|
+
*
|
|
26607
|
+
* @param file - The file object to check
|
|
26608
|
+
* @param clipboardData - The full clipboard data transfer object to examine for context
|
|
26609
|
+
* @returns True if the file is an image that should be processed, false otherwise
|
|
26610
|
+
*/
|
|
26611
|
+
function isImageFile(file, clipboardData) {
|
|
26612
|
+
var _a, _b;
|
|
26613
|
+
if (!isContentTypeImage(file)) {
|
|
26614
|
+
return false;
|
|
26479
26615
|
}
|
|
26480
|
-
|
|
26481
|
-
|
|
26616
|
+
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 : '';
|
|
26617
|
+
return !isHtmlFromExcel(html) && !isHtmlTable(html);
|
|
26618
|
+
}
|
|
26619
|
+
function isContentTypeImage(file) {
|
|
26620
|
+
if (!(file === null || file === void 0 ? void 0 : file.type)) {
|
|
26621
|
+
return false;
|
|
26622
|
+
}
|
|
26623
|
+
return file.type.startsWith('image/');
|
|
26624
|
+
}
|
|
26625
|
+
function isHtmlFromExcel(html) {
|
|
26626
|
+
if (!html) {
|
|
26627
|
+
return false;
|
|
26628
|
+
}
|
|
26629
|
+
return (html.includes('name=generator content="microsoft excel"') ||
|
|
26630
|
+
html.includes('xmlns:x="urn:schemas-microsoft-com:office:excel"'));
|
|
26631
|
+
}
|
|
26632
|
+
function isHtmlTable(html) {
|
|
26633
|
+
if (!html) {
|
|
26634
|
+
return false;
|
|
26635
|
+
}
|
|
26636
|
+
return html.includes('<table');
|
|
26637
|
+
}
|
|
26482
26638
|
|
|
26483
26639
|
const MIN_WIDTH = 10;
|
|
26484
26640
|
const createImageViewPlugin = (language) => {
|
|
@@ -28664,6 +28820,7 @@ const ProsemirrorAdapter = class {
|
|
|
28664
28820
|
nodes: nodes,
|
|
28665
28821
|
marks: schema$1.spec.marks.append({
|
|
28666
28822
|
strikethrough: strikethrough,
|
|
28823
|
+
link: linkMarkSpec,
|
|
28667
28824
|
}),
|
|
28668
28825
|
});
|
|
28669
28826
|
}
|