slate-angular 17.1.3 → 17.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -203,33 +203,15 @@ const getPlainText = (domNode) => {
203
203
  }
204
204
  return text;
205
205
  };
206
+ const SlateFragmentAttributeKey = 'data-slate-angular-fragment';
206
207
  /**
207
- * Get x-slate-fragment attribute from data-slate-fragment
208
+ * Get x-slate-fragment attribute from data-slate-angular-fragment
208
209
  */
209
- const catchSlateFragment = /data-slate-fragment="(.+?)"/m;
210
- const getSlateFragmentAttribute = (dataTransfer) => {
211
- const htmlData = dataTransfer.getData('text/html');
210
+ const catchSlateFragment = /data-slate-angular-fragment="(.+?)"/m;
211
+ const getSlateFragmentAttribute = (htmlData) => {
212
212
  const [, fragment] = htmlData.match(catchSlateFragment) || [];
213
213
  return fragment;
214
214
  };
215
- /**
216
- * Get the x-slate-fragment attribute that exist in text/html data
217
- * and append it to the DataTransfer object
218
- */
219
- const getClipboardData = (dataTransfer, clipboardFormatKey = 'x-slate-fragment') => {
220
- if (!dataTransfer.getData(`application/${clipboardFormatKey}`)) {
221
- const fragment = getSlateFragmentAttribute(dataTransfer);
222
- if (fragment) {
223
- const clipboardData = new DataTransfer();
224
- dataTransfer.types.forEach(type => {
225
- clipboardData.setData(type, dataTransfer.getData(type));
226
- });
227
- clipboardData.setData(`application/${clipboardFormatKey}`, fragment);
228
- return clipboardData;
229
- }
230
- }
231
- return dataTransfer;
232
- };
233
215
 
234
216
  /**
235
217
  * An auto-incrementing identifier for keys.
@@ -1073,6 +1055,208 @@ const createThrottleRAF = () => {
1073
1055
  return throttleRAF;
1074
1056
  };
1075
1057
 
1058
+ const setDataTransferClipboard = (dataTransfer, htmlText) => {
1059
+ dataTransfer?.setData(`text/html`, htmlText);
1060
+ };
1061
+ const setDataTransferClipboardText = (data, text) => {
1062
+ data?.setData(`text/plain`, text);
1063
+ };
1064
+ const getDataTransferClipboard = (data) => {
1065
+ const html = data?.getData(`text/html`);
1066
+ if (html) {
1067
+ const htmlClipboardData = getClipboardFromHTMLText(html);
1068
+ if (htmlClipboardData) {
1069
+ return htmlClipboardData;
1070
+ }
1071
+ const textData = getDataTransferClipboardText(data);
1072
+ if (textData) {
1073
+ return {
1074
+ html,
1075
+ ...textData
1076
+ };
1077
+ }
1078
+ else {
1079
+ return { html };
1080
+ }
1081
+ }
1082
+ else {
1083
+ const textData = getDataTransferClipboardText(data);
1084
+ return textData;
1085
+ }
1086
+ };
1087
+ const getDataTransferClipboardText = (data) => {
1088
+ if (!data) {
1089
+ return null;
1090
+ }
1091
+ const text = data?.getData(`text/plain`);
1092
+ if (text) {
1093
+ const htmlClipboardData = getClipboardFromHTMLText(text);
1094
+ if (htmlClipboardData) {
1095
+ return htmlClipboardData;
1096
+ }
1097
+ }
1098
+ return { text };
1099
+ };
1100
+
1101
+ const isClipboardReadSupported = () => {
1102
+ return 'clipboard' in navigator && 'read' in navigator.clipboard;
1103
+ };
1104
+ const isClipboardWriteSupported = () => {
1105
+ return 'clipboard' in navigator && 'write' in navigator.clipboard;
1106
+ };
1107
+ const isClipboardWriteTextSupported = () => {
1108
+ return 'clipboard' in navigator && 'writeText' in navigator.clipboard;
1109
+ };
1110
+ const isClipboardFile = (item) => {
1111
+ return item.types.find(i => i.match(/^image\//));
1112
+ };
1113
+ const stripHtml = (html) => {
1114
+ // See <https://github.com/developit/preact-markup/blob/4788b8d61b4e24f83688710746ee36e7464f7bbc/src/parse-markup.js#L60-L69>
1115
+ const doc = document.implementation.createHTMLDocument('');
1116
+ doc.documentElement.innerHTML = html.trim();
1117
+ return doc.body.textContent || doc.body.innerText || '';
1118
+ };
1119
+ const blobAsString = (blob) => {
1120
+ return new Promise((resolve, reject) => {
1121
+ const reader = new FileReader();
1122
+ reader.addEventListener('loadend', () => {
1123
+ const text = reader.result;
1124
+ resolve(text);
1125
+ });
1126
+ reader.addEventListener('error', () => {
1127
+ reject(reader.error);
1128
+ });
1129
+ reader.readAsText(blob);
1130
+ });
1131
+ };
1132
+
1133
+ const setNavigatorClipboard = async (htmlText, data, text = '') => {
1134
+ let textClipboard = text;
1135
+ if (isClipboardWriteSupported()) {
1136
+ await navigator.clipboard.write([
1137
+ new ClipboardItem({
1138
+ 'text/html': new Blob([htmlText], {
1139
+ type: 'text/html'
1140
+ }),
1141
+ 'text/plain': new Blob([JSON.stringify(textClipboard ?? data)], { type: 'text/plain' })
1142
+ })
1143
+ ]);
1144
+ }
1145
+ };
1146
+ const getNavigatorClipboard = async () => {
1147
+ if (!isClipboardReadSupported()) {
1148
+ return null;
1149
+ }
1150
+ const clipboardItems = await navigator.clipboard.read();
1151
+ let clipboardData = {};
1152
+ if (Array.isArray(clipboardItems) && clipboardItems[0] instanceof ClipboardItem) {
1153
+ for (const item of clipboardItems) {
1154
+ if (isClipboardFile(item)) {
1155
+ const clipboardFiles = item.types.filter(type => type.match(/^image\//));
1156
+ const fileBlobs = await Promise.all(clipboardFiles.map(type => item.getType(type)));
1157
+ const urls = fileBlobs.filter(Boolean).map(blob => URL.createObjectURL(blob));
1158
+ const files = await Promise.all(urls.map(async (url) => {
1159
+ const blob = await (await fetch(url)).blob();
1160
+ return new File([blob], 'file', { type: blob.type });
1161
+ }));
1162
+ return {
1163
+ files
1164
+ };
1165
+ }
1166
+ if (item.types.includes('text/html')) {
1167
+ const htmlContent = await blobAsString(await item.getType('text/html'));
1168
+ const htmlClipboardData = getClipboardFromHTMLText(htmlContent);
1169
+ if (htmlClipboardData) {
1170
+ return htmlClipboardData;
1171
+ }
1172
+ if (htmlContent && htmlContent.trim()) {
1173
+ clipboardData = { html: htmlContent };
1174
+ }
1175
+ }
1176
+ if (item.types.includes('text/plain')) {
1177
+ const textContent = await blobAsString(await item.getType('text/plain'));
1178
+ clipboardData = {
1179
+ text: stripHtml(textContent)
1180
+ };
1181
+ }
1182
+ }
1183
+ }
1184
+ return clipboardData;
1185
+ };
1186
+
1187
+ const buildHTMLText = (wrapper, attach, data) => {
1188
+ const stringObj = JSON.stringify(data);
1189
+ const encoded = window.btoa(encodeURIComponent(stringObj));
1190
+ attach.setAttribute(SlateFragmentAttributeKey, encoded);
1191
+ return wrapper.innerHTML;
1192
+ };
1193
+ const getClipboardFromHTMLText = (html) => {
1194
+ const fragmentAttribute = getSlateFragmentAttribute(html);
1195
+ if (fragmentAttribute) {
1196
+ try {
1197
+ const decoded = decodeURIComponent(window.atob(fragmentAttribute));
1198
+ const result = JSON.parse(decoded);
1199
+ if (result && Array.isArray(result) && result.length > 0) {
1200
+ return {
1201
+ elements: result
1202
+ };
1203
+ }
1204
+ }
1205
+ catch (error) {
1206
+ console.error(error);
1207
+ return null;
1208
+ }
1209
+ }
1210
+ return null;
1211
+ };
1212
+ const createClipboardData = (html, elements, text, files) => {
1213
+ const data = { elements, text, html, files };
1214
+ return data;
1215
+ };
1216
+ const getClipboardData = async (dataTransfer) => {
1217
+ let clipboardData = null;
1218
+ if (dataTransfer) {
1219
+ if (dataTransfer.files.length) {
1220
+ return { files: Array.from(dataTransfer.files) };
1221
+ }
1222
+ clipboardData = getDataTransferClipboard(dataTransfer);
1223
+ return clipboardData;
1224
+ }
1225
+ if (isClipboardReadSupported()) {
1226
+ return await getNavigatorClipboard();
1227
+ }
1228
+ return clipboardData;
1229
+ };
1230
+ /**
1231
+ * @param wrapper get wrapper.innerHTML string which will be written in clipboard
1232
+ * @param attach attach must be child element of wrapper which will be attached json data
1233
+ * @returns void
1234
+ */
1235
+ const setClipboardData = async (clipboardData, wrapper, attach, dataTransfer) => {
1236
+ if (!clipboardData) {
1237
+ return;
1238
+ }
1239
+ const { elements, text } = clipboardData;
1240
+ if (isClipboardWriteSupported()) {
1241
+ const htmlText = buildHTMLText(wrapper, attach, elements);
1242
+ // TODO
1243
+ // maybe fail to write when copy some cell in table
1244
+ return await setNavigatorClipboard(htmlText, elements, text);
1245
+ }
1246
+ if (dataTransfer) {
1247
+ const htmlText = buildHTMLText(wrapper, attach, elements);
1248
+ setDataTransferClipboard(dataTransfer, htmlText);
1249
+ setDataTransferClipboardText(dataTransfer, text);
1250
+ return;
1251
+ }
1252
+ // Compatible with situations where navigator.clipboard.write is not supported and dataTransfer is empty
1253
+ // Such as contextmenu copy in Firefox.
1254
+ if (isClipboardWriteTextSupported()) {
1255
+ const htmlText = buildHTMLText(wrapper, attach, elements);
1256
+ return await navigator.clipboard.writeText(htmlText);
1257
+ }
1258
+ };
1259
+
1076
1260
  /**
1077
1261
  * Utilities for single-line deletion
1078
1262
  */
@@ -1195,7 +1379,7 @@ const withAngular = (editor, clipboardFormatKey = 'x-slate-fragment') => {
1195
1379
  }
1196
1380
  onChange();
1197
1381
  };
1198
- e.setFragmentData = (data) => {
1382
+ e.setFragmentData = (dataTransfer, originEvent) => {
1199
1383
  const { selection } = e;
1200
1384
  if (!selection) {
1201
1385
  return;
@@ -1254,19 +1438,13 @@ const withAngular = (editor, clipboardFormatKey = 'x-slate-fragment') => {
1254
1438
  attach = span;
1255
1439
  }
1256
1440
  const fragment = e.getFragment();
1257
- const stringObj = JSON.stringify(fragment);
1258
- const encoded = window.btoa(encodeURIComponent(stringObj));
1259
- attach.setAttribute('data-slate-fragment', encoded);
1260
- data.setData(`application/${clipboardFormatKey}`, encoded);
1261
1441
  // Add the content to a <div> so that we can get its inner HTML.
1262
1442
  const div = contents.ownerDocument.createElement('div');
1263
1443
  div.appendChild(contents);
1264
1444
  div.setAttribute('hidden', 'true');
1265
1445
  contents.ownerDocument.body.appendChild(div);
1266
- data.setData('text/html', div.innerHTML);
1267
- data.setData('text/plain', getPlainText(div));
1446
+ setClipboardData({ text: getPlainText(div), elements: fragment }, div, attach, dataTransfer);
1268
1447
  contents.ownerDocument.body.removeChild(div);
1269
- return data;
1270
1448
  };
1271
1449
  e.deleteCutData = () => {
1272
1450
  const { selection } = editor;
@@ -1282,28 +1460,26 @@ const withAngular = (editor, clipboardFormatKey = 'x-slate-fragment') => {
1282
1460
  }
1283
1461
  }
1284
1462
  };
1285
- e.insertData = (data) => {
1286
- if (!e.insertFragmentData(data)) {
1463
+ e.insertData = async (data) => {
1464
+ if (!(await e.insertFragmentData(data))) {
1287
1465
  e.insertTextData(data);
1288
1466
  }
1289
1467
  };
1290
- e.insertFragmentData = (data) => {
1468
+ e.insertFragmentData = async (data) => {
1291
1469
  /**
1292
1470
  * Checking copied fragment from application/x-slate-fragment or data-slate-fragment
1293
1471
  */
1294
- const fragment = data.getData(`application/${clipboardFormatKey}`) || getSlateFragmentAttribute(data);
1295
- if (fragment) {
1296
- const decoded = decodeURIComponent(window.atob(fragment));
1297
- const parsed = JSON.parse(decoded);
1298
- e.insertFragment(parsed);
1472
+ const clipboardData = await getClipboardData(data);
1473
+ if (clipboardData && clipboardData.elements) {
1474
+ e.insertFragment(clipboardData.elements);
1299
1475
  return true;
1300
1476
  }
1301
1477
  return false;
1302
1478
  };
1303
- e.insertTextData = (data) => {
1304
- const text = data.getData('text/plain');
1305
- if (text) {
1306
- const lines = text.split(/\r\n|\r|\n/);
1479
+ e.insertTextData = async (data) => {
1480
+ const clipboardData = await getClipboardData(data);
1481
+ if (clipboardData && clipboardData.text) {
1482
+ const lines = clipboardData.text.split(/\r\n|\r|\n/);
1307
1483
  let split = false;
1308
1484
  for (const line of lines) {
1309
1485
  if (split) {
@@ -4311,5 +4487,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImpor
4311
4487
  * Generated bundle index. Do not edit.
4312
4488
  */
4313
4489
 
4314
- export { AngularEditor, BaseComponent, BaseElementComponent, BaseLeafComponent, BaseTextComponent, DOMComment, DOMElement, DOMNode, DOMRange, DOMSelection, DOMStaticRange, DOMText, EDITOR_TO_AFTER_VIEW_INIT_QUEUE, EDITOR_TO_ELEMENT, EDITOR_TO_ON_CHANGE, EDITOR_TO_PLACEHOLDER, EDITOR_TO_WINDOW, ELEMENT_TO_COMPONENT, ELEMENT_TO_NODE, FAKE_LEFT_BLOCK_CARD_OFFSET, FAKE_RIGHT_BLOCK_CARD_OFFSET, HAS_BEFORE_INPUT_SUPPORT, IS_ANDROID, IS_APPLE, IS_CHROME, IS_CHROME_LEGACY, IS_CLICKING, IS_DRAGGING, IS_EDGE_LEGACY, IS_FIREFOX, IS_FIREFOX_LEGACY, IS_FOCUSED, IS_IOS, IS_QQBROWSER, IS_READONLY, IS_SAFARI, IS_UC_MOBILE, IS_WECHATBROWSER, KEY_TO_ELEMENT, Key, NODE_TO_ELEMENT, NODE_TO_INDEX, NODE_TO_KEY, NODE_TO_PARENT, PLACEHOLDER_SYMBOL, SlateChildren, SlateChildrenOutlet, SlateDefaultString, SlateEditable, SlateElement, SlateErrorCode, SlateLeaves, SlateModule, SlateString, check, createThrottleRAF, defaultScrollSelectionIntoView, getCardTargetAttribute, getClipboardData, getDefaultView, getEditableChild, getEditableChildAndIndex, getPlainText, getSlateFragmentAttribute, hasAfterContextChange, hasBeforeContextChange, hasBlockCard, hasBlockCardWithNode, hasEditableTarget, hasShadowRoot, hotkeys, isCardCenterByTargetAttr, isCardLeft, isCardLeftByTargetAttr, isCardRightByTargetAttr, isComponentType, isDOMComment, isDOMElement, isDOMNode, isDOMSelection, isDOMText, isDecoratorRangeListEqual, isEmpty, isPlainTextOnlyPaste, isTemplateRef, isValid, normalize, normalizeDOMPoint, shallowCompare, withAngular };
4490
+ export { AngularEditor, BaseComponent, BaseElementComponent, BaseLeafComponent, BaseTextComponent, DOMComment, DOMElement, DOMNode, DOMRange, DOMSelection, DOMStaticRange, DOMText, EDITOR_TO_AFTER_VIEW_INIT_QUEUE, EDITOR_TO_ELEMENT, EDITOR_TO_ON_CHANGE, EDITOR_TO_PLACEHOLDER, EDITOR_TO_WINDOW, ELEMENT_TO_COMPONENT, ELEMENT_TO_NODE, FAKE_LEFT_BLOCK_CARD_OFFSET, FAKE_RIGHT_BLOCK_CARD_OFFSET, HAS_BEFORE_INPUT_SUPPORT, IS_ANDROID, IS_APPLE, IS_CHROME, IS_CHROME_LEGACY, IS_CLICKING, IS_DRAGGING, IS_EDGE_LEGACY, IS_FIREFOX, IS_FIREFOX_LEGACY, IS_FOCUSED, IS_IOS, IS_QQBROWSER, IS_READONLY, IS_SAFARI, IS_UC_MOBILE, IS_WECHATBROWSER, KEY_TO_ELEMENT, Key, NODE_TO_ELEMENT, NODE_TO_INDEX, NODE_TO_KEY, NODE_TO_PARENT, PLACEHOLDER_SYMBOL, SlateChildren, SlateChildrenOutlet, SlateDefaultString, SlateEditable, SlateElement, SlateErrorCode, SlateFragmentAttributeKey, SlateLeaves, SlateModule, SlateString, blobAsString, buildHTMLText, check, createClipboardData, createThrottleRAF, defaultScrollSelectionIntoView, getCardTargetAttribute, getClipboardData, getClipboardFromHTMLText, getDataTransferClipboard, getDataTransferClipboardText, getDefaultView, getEditableChild, getEditableChildAndIndex, getNavigatorClipboard, getPlainText, getSlateFragmentAttribute, hasAfterContextChange, hasBeforeContextChange, hasBlockCard, hasBlockCardWithNode, hasEditableTarget, hasShadowRoot, hotkeys, isCardCenterByTargetAttr, isCardLeft, isCardLeftByTargetAttr, isCardRightByTargetAttr, isClipboardFile, isClipboardReadSupported, isClipboardWriteSupported, isClipboardWriteTextSupported, isComponentType, isDOMComment, isDOMElement, isDOMNode, isDOMSelection, isDOMText, isDecoratorRangeListEqual, isEmpty, isPlainTextOnlyPaste, isTemplateRef, isValid, normalize, normalizeDOMPoint, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setNavigatorClipboard, shallowCompare, stripHtml, withAngular };
4315
4491
  //# sourceMappingURL=slate-angular.mjs.map