diff --git a/LexicalClipboard.dev.js b/LexicalClipboard.dev.js index 9e72de896d52d9c342e520a79b05dbf8fd9bcee3..78aa3bc5048bb4354339efc558031ec0185163dd 100644 --- a/LexicalClipboard.dev.js +++ b/LexicalClipboard.dev.js @@ -3,7 +3,9 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. + * */ + 'use strict'; var html = require('@lexical/html'); @@ -102,7 +104,7 @@ function $insertDataTransferForPlainText(dataTransfer, selection) { * @param selection the selection to use as the insertion point for the content in the DataTransfer object * @param editor the LexicalEditor the content is being inserted into. */ -function $insertDataTransferForRichText(dataTransfer, selection, editor) { +function $insertDataTransferForRichText(dataTransfer, selection, editor, event) { const lexicalString = dataTransfer.getData('application/x-lexical-editor'); if (lexicalString) { try { @@ -115,15 +117,18 @@ function $insertDataTransferForRichText(dataTransfer, selection, editor) { // Fail silently. } } - const htmlString = dataTransfer.getData('text/html'); - if (htmlString) { - try { - const parser = new DOMParser(); - const dom = parser.parseFromString(htmlString, 'text/html'); - const nodes = html.$generateNodesFromDOM(editor, dom); - return $insertGeneratedNodes(editor, nodes, selection); - } catch (_unused2) { - // Fail silently. + const shouldIgnoreHTML = event && event.inputType === 'insertReplacementText' && dataTransfer.types.includes('text/plain'); + if (!shouldIgnoreHTML) { + const htmlString = dataTransfer.getData('text/html'); + if (htmlString) { + try { + const parser = new DOMParser(); + const dom = parser.parseFromString(htmlString, 'text/html'); + const nodes = html.$generateNodesFromDOM(editor, dom); + return $insertGeneratedNodes(editor, nodes, selection); + } catch (_unused2) { + // Fail silently. + } } } @@ -138,13 +143,16 @@ function $insertDataTransferForRichText(dataTransfer, selection, editor) { parts.pop(); } for (let i = 0; i < parts.length; i++) { - const part = parts[i]; - if (part === '\n' || part === '\r\n') { - selection.insertParagraph(); - } else if (part === '\t') { - selection.insertNodes([lexical.$createTabNode()]); - } else { - selection.insertText(part); + const currentSelection = lexical.$getSelection(); + if (lexical.$isRangeSelection(currentSelection)) { + const part = parts[i]; + if (part === '\n' || part === '\r\n') { + currentSelection.insertParagraph(); + } else if (part === '\t') { + currentSelection.insertNodes([lexical.$createTabNode()]); + } else { + currentSelection.insertText(part); + } } } } else { diff --git a/LexicalClipboard.dev.mjs b/LexicalClipboard.dev.mjs index e5b580537bc7b3ce1bd9546f6858988b4f58003f..ef944d097da9cc4383c38c874a6d1e7c20ab22d0 100644 --- a/LexicalClipboard.dev.mjs +++ b/LexicalClipboard.dev.mjs @@ -3,7 +3,9 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. + * */ + import { $generateHtmlFromNodes, $generateNodesFromDOM } from '@lexical/html'; import { $addNodeStyle, $cloneWithProperties, $sliceSelectedTextNodeContent } from '@lexical/selection'; import { objectKlassEquals } from '@lexical/utils'; @@ -100,7 +102,7 @@ function $insertDataTransferForPlainText(dataTransfer, selection) { * @param selection the selection to use as the insertion point for the content in the DataTransfer object * @param editor the LexicalEditor the content is being inserted into. */ -function $insertDataTransferForRichText(dataTransfer, selection, editor) { +function $insertDataTransferForRichText(dataTransfer, selection, editor, event) { const lexicalString = dataTransfer.getData('application/x-lexical-editor'); if (lexicalString) { try { @@ -113,15 +115,18 @@ function $insertDataTransferForRichText(dataTransfer, selection, editor) { // Fail silently. } } - const htmlString = dataTransfer.getData('text/html'); - if (htmlString) { - try { - const parser = new DOMParser(); - const dom = parser.parseFromString(htmlString, 'text/html'); - const nodes = $generateNodesFromDOM(editor, dom); - return $insertGeneratedNodes(editor, nodes, selection); - } catch (_unused2) { - // Fail silently. + const shouldIgnoreHTML = event && event.inputType === 'insertReplacementText' && dataTransfer.types.includes('text/plain'); + if (!shouldIgnoreHTML) { + const htmlString = dataTransfer.getData('text/html'); + if (htmlString) { + try { + const parser = new DOMParser(); + const dom = parser.parseFromString(htmlString, 'text/html'); + const nodes = $generateNodesFromDOM(editor, dom); + return $insertGeneratedNodes(editor, nodes, selection); + } catch (_unused2) { + // Fail silently. + } } } @@ -136,13 +141,16 @@ function $insertDataTransferForRichText(dataTransfer, selection, editor) { parts.pop(); } for (let i = 0; i < parts.length; i++) { - const part = parts[i]; - if (part === '\n' || part === '\r\n') { - selection.insertParagraph(); - } else if (part === '\t') { - selection.insertNodes([$createTabNode()]); - } else { - selection.insertText(part); + const currentSelection = $getSelection(); + if ($isRangeSelection(currentSelection)) { + const part = parts[i]; + if (part === '\n' || part === '\r\n') { + currentSelection.insertParagraph(); + } else if (part === '\t') { + currentSelection.insertNodes([$createTabNode()]); + } else { + currentSelection.insertText(part); + } } } } else { diff --git a/LexicalClipboard.js b/LexicalClipboard.js index ab45df643f3d23d7c917a4961db63d49045831f4..b7a8117bf55550d7b25c5385f164922b48fa6e17 100644 --- a/LexicalClipboard.js +++ b/LexicalClipboard.js @@ -3,7 +3,9 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. + * */ + 'use strict' const LexicalClipboard = process.env.NODE_ENV === 'development' ? require('./LexicalClipboard.dev.js') : require('./LexicalClipboard.prod.js'); module.exports = LexicalClipboard; \ No newline at end of file diff --git a/LexicalClipboard.mjs b/LexicalClipboard.mjs index 92cf644354b39f5011db1c739c29bfc14cec689a..b0a924f9cc33893ef74d5fb574a280602d859f9d 100644 --- a/LexicalClipboard.mjs +++ b/LexicalClipboard.mjs @@ -3,7 +3,9 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. + * */ + import * as modDev from './LexicalClipboard.dev.mjs'; import * as modProd from './LexicalClipboard.prod.mjs'; const mod = process.env.NODE_ENV === 'development' ? modDev : modProd; diff --git a/LexicalClipboard.node.mjs b/LexicalClipboard.node.mjs index d6561d32c2e79f9070851f7352e43ea4bcb5bd86..2112c40f0b771340e778d9026049df85f405228e 100644 --- a/LexicalClipboard.node.mjs +++ b/LexicalClipboard.node.mjs @@ -3,7 +3,9 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. + * */ + const mod = await (process.env.NODE_ENV === 'development' ? import('./LexicalClipboard.dev.mjs') : import('./LexicalClipboard.prod.mjs')); export const $generateJSONFromSelectedNodes = mod.$generateJSONFromSelectedNodes; export const $generateNodesFromSerializedNodes = mod.$generateNodesFromSerializedNodes; diff --git a/LexicalClipboard.prod.js b/LexicalClipboard.prod.js index 494ab7597d14cfa0386f7bad294c567a8f0110c1..8b3d21203d28eb2be142ad3d7061f2e0cffbdd23 100644 --- a/LexicalClipboard.prod.js +++ b/LexicalClipboard.prod.js @@ -3,15 +3,17 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. + * */ + 'use strict';var f=require("@lexical/html"),m=require("@lexical/selection"),q=require("@lexical/utils"),r=require("lexical");function t(a){let b=new URLSearchParams;b.append("code",a);for(let c=1;c{a.update(()=>{g(C(a,b))})});var c=a.getRootElement();let d=null==a._window?window.document:a._window.document,e=u?(a._window||window).getSelection():null;if(null===c||null===e)return!1;let h=d.createElement("span");h.style.cssText="position: fixed; top: -1000px;";h.append(d.createTextNode("#"));c.append(h);c=new Range;c.setStart(h,0);c.setEnd(h,1);e.removeAllRanges();e.addRange(c);return new Promise(g=> -{let k=a.registerCommand(r.COPY_COMMAND,n=>{q.objectKlassEquals(n,ClipboardEvent)&&(k(),null!==B&&(window.clearTimeout(B),B=null),g(C(a,n)));return!0},r.COMMAND_PRIORITY_CRITICAL);B=window.setTimeout(()=>{k();B=null;g(!1)},50);d.execCommand("copy");h.remove()})} +exports.$insertDataTransferForRichText=function(a,b,c,e){let g=a.getData("application/x-lexical-editor");if(g)try{let d=JSON.parse(g);if(d.namespace===c._config.namespace&&Array.isArray(d.nodes)){let h=A(d.nodes);return y(c,h,b)}}catch(d){}if(!e||"insertReplacementText"!==e.inputType||!a.types.includes("text/plain"))if(e=a.getData("text/html"))try{var k=(new DOMParser).parseFromString(e,"text/html");let d=f.$generateNodesFromDOM(c,k);return y(c,d,b)}catch(d){}a=a.getData("text/plain")||a.getData("text/uri-list"); +if(null!=a)if(r.$isRangeSelection(b))for(b=a.split(/(\r?\n|\t)/),""===b[b.length-1]&&b.pop(),a=0;a{a.update(()=>{d(C(a,b))})});var c=a.getRootElement();let e=null==a._window?window.document:a._window.document,g=u?(a._window||window).getSelection():null;if(null===c||null===g)return!1;let k=e.createElement("span");k.style.cssText="position: fixed; top: -1000px;";k.append(e.createTextNode("#"));c.append(k);c=new Range;c.setStart(k,0);c.setEnd(k,1);g.removeAllRanges();g.addRange(c);return new Promise(d=> +{let h=a.registerCommand(r.COPY_COMMAND,n=>{q.objectKlassEquals(n,ClipboardEvent)&&(h(),null!==B&&(window.clearTimeout(B),B=null),d(C(a,n)));return!0},r.COMMAND_PRIORITY_CRITICAL);B=window.setTimeout(()=>{h();B=null;d(!1)},50);e.execCommand("copy");k.remove()})} diff --git a/LexicalClipboard.prod.mjs b/LexicalClipboard.prod.mjs index e975808a82c8e8bd1b7dc80867ba65bec9a96fa9..48e6331eaa95219007cb3066fbe4a9c73551912e 100644 --- a/LexicalClipboard.prod.mjs +++ b/LexicalClipboard.prod.mjs @@ -3,5 +3,7 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. + * */ -import{$generateHtmlFromNodes as e,$generateNodesFromDOM as t}from"@lexical/html";import{$addNodeStyle as n,$cloneWithProperties as o,$sliceSelectedTextNodeContent as l}from"@lexical/selection";import{objectKlassEquals as r}from"@lexical/utils";import{$getSelection as i,$isRangeSelection as a,$createTabNode as c,SELECTION_INSERT_CLIPBOARD_NODES_COMMAND as s,$getRoot as u,$parseSerializedNode as d,$isTextNode as f,COPY_COMMAND as p,COMMAND_PRIORITY_CRITICAL as m,isSelectionWithinEditor as h,$isElementNode as x}from"lexical";var g=function(e){const t=new URLSearchParams;t.append("code",e);for(let e=1;ew?(e||window).getSelection():null;function v(t){const n=i();if(null==n)throw Error("Expected valid LexicalSelection");return a(n)&&n.isCollapsed()||0===n.getNodes().length?"":e(t,n)}function D(e){const t=i();if(null==t)throw Error("Expected valid LexicalSelection");return a(t)&&t.isCollapsed()||0===t.getNodes().length?null:JSON.stringify(T(e,t))}function C(e,t){const n=e.getData("text/plain")||e.getData("text/uri-list");null!=n&&t.insertRawText(n)}function E(e,n,o){const l=e.getData("application/x-lexical-editor");if(l)try{const e=JSON.parse(l);if(e.namespace===o._config.namespace&&Array.isArray(e.nodes)){return N(o,_(e.nodes),n)}}catch(e){}const r=e.getData("text/html");if(r)try{const e=(new DOMParser).parseFromString(r,"text/html");return N(o,t(o,e),n)}catch(e){}const i=e.getData("text/plain")||e.getData("text/uri-list");if(null!=i)if(a(n)){const e=i.split(/(\r?\n|\t)/);""===e[e.length-1]&&e.pop();for(let t=0;t0?u.text=e:i=!1}for(let o=0;o{e.update((()=>{n(P(e,t))}))}));const n=e.getRootElement(),o=null==e._window?window.document:e._window.document,l=y(e._window);if(null===n||null===l)return!1;const i=o.createElement("span");i.style.cssText="position: fixed; top: -1000px;",i.append(o.createTextNode("#")),n.append(i);const a=new Range;return a.setStart(i,0),a.setEnd(i,1),l.removeAllRanges(),l.addRange(a),new Promise(((t,n)=>{const l=e.registerCommand(p,(n=>(r(n,ClipboardEvent)&&(l(),null!==A&&(window.clearTimeout(A),A=null),t(P(e,n))),!0)),m);A=window.setTimeout((()=>{l(),A=null,t(!1)}),50),o.execCommand("copy"),i.remove()}))}function P(e,t){const n=y(e._window);if(!n)return!1;const o=n.anchorNode,l=n.focusNode;if(null!==o&&null!==l&&!h(e,o,l))return!1;t.preventDefault();const r=t.clipboardData,a=i();if(null===r||null===a)return!1;const c=v(e),s=D(e);let u="";return null!==a&&(u=a.getTextContent()),null!==c&&r.setData("text/html",c),null!==s&&r.setData("application/x-lexical-editor",s),r.setData("text/plain",u),!0}export{T as $generateJSONFromSelectedNodes,_ as $generateNodesFromSerializedNodes,v as $getHtmlContent,D as $getLexicalContent,C as $insertDataTransferForPlainText,E as $insertDataTransferForRichText,N as $insertGeneratedNodes,R as copyToClipboard}; + +import{$generateHtmlFromNodes as e,$generateNodesFromDOM as t}from"@lexical/html";import{$addNodeStyle as n,$cloneWithProperties as l,$sliceSelectedTextNodeContent as o}from"@lexical/selection";import{objectKlassEquals as r}from"@lexical/utils";import{$getSelection as i,$isRangeSelection as c,$createTabNode as a,SELECTION_INSERT_CLIPBOARD_NODES_COMMAND as s,$getRoot as u,$parseSerializedNode as d,$isTextNode as p,COPY_COMMAND as f,COMMAND_PRIORITY_CRITICAL as m,isSelectionWithinEditor as h,$isElementNode as x}from"lexical";var g=function(e){const t=new URLSearchParams;t.append("code",e);for(let e=1;ew?(e||window).getSelection():null;function v(t){const n=i();if(null==n)throw Error("Expected valid LexicalSelection");return c(n)&&n.isCollapsed()||0===n.getNodes().length?"":e(t,n)}function D(e){const t=i();if(null==t)throw Error("Expected valid LexicalSelection");return c(t)&&t.isCollapsed()||0===t.getNodes().length?null:JSON.stringify(S(e,t))}function C(e,t){const n=e.getData("text/plain")||e.getData("text/uri-list");null!=n&&t.insertRawText(n)}function T(e,n,l,o){const r=e.getData("application/x-lexical-editor");if(r)try{const e=JSON.parse(r);if(e.namespace===l._config.namespace&&Array.isArray(e.nodes)){return E(l,R(e.nodes),n)}}catch(e){}if(!(o&&"insertReplacementText"===o.inputType&&e.types.includes("text/plain"))){const o=e.getData("text/html");if(o)try{const e=(new DOMParser).parseFromString(o,"text/html");return E(l,t(l,e),n)}catch(e){}}const s=e.getData("text/plain")||e.getData("text/uri-list");if(null!=s)if(c(n)){const e=s.split(/(\r?\n|\t)/);""===e[e.length-1]&&e.pop();for(let t=0;t0?u.text=e:i=!1}for(let l=0;l{e.update((()=>{n(P(e,t))}))}));const n=e.getRootElement(),l=null==e._window?window.document:e._window.document,o=y(e._window);if(null===n||null===o)return!1;const i=l.createElement("span");i.style.cssText="position: fixed; top: -1000px;",i.append(l.createTextNode("#")),n.append(i);const c=new Range;return c.setStart(i,0),c.setEnd(i,1),o.removeAllRanges(),o.addRange(c),new Promise(((t,n)=>{const o=e.registerCommand(f,(n=>(r(n,ClipboardEvent)&&(o(),null!==_&&(window.clearTimeout(_),_=null),t(P(e,n))),!0)),m);_=window.setTimeout((()=>{o(),_=null,t(!1)}),50),l.execCommand("copy"),i.remove()}))}function P(e,t){const n=y(e._window);if(!n)return!1;const l=n.anchorNode,o=n.focusNode;if(null!==l&&null!==o&&!h(e,l,o))return!1;t.preventDefault();const r=t.clipboardData,c=i();if(null===r||null===c)return!1;const a=v(e),s=D(e);let u="";return null!==c&&(u=c.getTextContent()),null!==a&&r.setData("text/html",a),null!==s&&r.setData("application/x-lexical-editor",s),r.setData("text/plain",u),!0}export{S as $generateJSONFromSelectedNodes,R as $generateNodesFromSerializedNodes,v as $getHtmlContent,D as $getLexicalContent,C as $insertDataTransferForPlainText,T as $insertDataTransferForRichText,E as $insertGeneratedNodes,A as copyToClipboard}; diff --git a/clipboard.d.ts b/clipboard.d.ts index 99e2138389b64d298a1330d7b354ba87d2e6f24e..83250a4c2049f94e08bfdfc757e03e8a85a08dd4 100644 --- a/clipboard.d.ts +++ b/clipboard.d.ts @@ -44,7 +44,7 @@ export declare function $insertDataTransferForPlainText(dataTransfer: DataTransf * @param selection the selection to use as the insertion point for the content in the DataTransfer object * @param editor the LexicalEditor the content is being inserted into. */ -export declare function $insertDataTransferForRichText(dataTransfer: DataTransfer, selection: BaseSelection, editor: LexicalEditor): void; +export declare function $insertDataTransferForRichText(dataTransfer: DataTransfer, selection: BaseSelection, editor: LexicalEditor, event?: InputEvent): void; /** * Inserts Lexical nodes into the editor using different strategies depending on * some simple selection-based heuristics. If you're looking for a generic way to