vue-editify 0.1.13 → 0.1.16

Sign up to get free protection for your applications and to get access to all the features.
package/lib/editify.es.js CHANGED
@@ -1146,6 +1146,151 @@ const event$1 = {
1146
1146
  return events;
1147
1147
  }
1148
1148
  };
1149
+ const file$1 = {
1150
+ /**
1151
+ * 根据文件获取可预览的图片路径
1152
+ * @param {Object} file
1153
+ */
1154
+ getImageUrl(file2) {
1155
+ if (!file2 || !(file2 instanceof File)) {
1156
+ throw new TypeError("The argument must be a File object");
1157
+ }
1158
+ return window.URL.createObjectURL(file2);
1159
+ },
1160
+ /**
1161
+ * 将JS的file对象转为BASE64位字符串,通过then方法回调,参数为base64字符串
1162
+ * @param {Object} file
1163
+ */
1164
+ dataFileToBase64(file2) {
1165
+ return new Promise((resolve, reject) => {
1166
+ if (!file2 || !(file2 instanceof File)) {
1167
+ reject(new TypeError("The argument must be a File object"));
1168
+ }
1169
+ let reader = new FileReader();
1170
+ reader.readAsDataURL(file2);
1171
+ reader.onloadend = () => {
1172
+ let dataURL = reader.result;
1173
+ resolve(dataURL);
1174
+ };
1175
+ });
1176
+ },
1177
+ /**
1178
+ * 将base64位格式文件转换为file对象
1179
+ * @param {Object} base64String base64位格式字符串
1180
+ * @param {Object} fileName 转换后的文件名字,包含后缀
1181
+ */
1182
+ dataBase64toFile(base64String, fileName) {
1183
+ if (!base64String || typeof base64String != "string") {
1184
+ throw new TypeError("The first argument must be a string");
1185
+ }
1186
+ if (!fileName || typeof fileName != "string") {
1187
+ throw new TypeError("The second argument must be a string");
1188
+ }
1189
+ let arr = base64String.split(",");
1190
+ let mime = arr[0].match(/:(.*?);/)[1];
1191
+ let bstr = atob(arr[1]);
1192
+ let n = bstr.length;
1193
+ let u8arr = new Uint8Array(n);
1194
+ while (n--) {
1195
+ u8arr[n] = bstr.charCodeAt(n);
1196
+ }
1197
+ return new File([u8arr], fileName, {
1198
+ type: mime
1199
+ });
1200
+ },
1201
+ /**
1202
+ * 图片压缩方法
1203
+ * @param {*} file 需要压缩的图片File文件
1204
+ * @param {*} opts 压缩参数
1205
+ */
1206
+ compressImage(file2, opts) {
1207
+ const options = {
1208
+ //压缩图片的宽,单位px,如果不设置默认为原图宽
1209
+ width: void 0,
1210
+ //压缩图片质量,默认为原图的0.8
1211
+ quality: 0.8,
1212
+ //图片类型,jpeg或者webp,默认为jpeg
1213
+ mimeType: "jpeg",
1214
+ //压缩后的最大值,单位kb,默认为0表示不设置此值
1215
+ maxSize: 0,
1216
+ //小于该大小的图片不进行压缩,单位kb,默认为0表示任何图片都要压缩
1217
+ minSize: 0
1218
+ };
1219
+ if (common$1.isObject(opts)) {
1220
+ if (number$1.isNumber(opts.width)) {
1221
+ options.width = opts.width;
1222
+ }
1223
+ if (number$1.isNumber(opts.quality) && opts.quality >= 0 && opts.quality <= 1) {
1224
+ options.quality = opts.quality;
1225
+ }
1226
+ if (opts.mimeType == "jpeg" || opts.mimeType == "webp") {
1227
+ options.mimeType = opts.mimeType;
1228
+ }
1229
+ if (number$1.isNumber(opts.maxSize)) {
1230
+ options.maxSize = opts.maxSize;
1231
+ }
1232
+ if (number$1.isNumber(opts.minSize)) {
1233
+ options.minSize = opts.minSize;
1234
+ }
1235
+ }
1236
+ const createFile = (canvas, fileName, quality) => {
1237
+ let url = canvas.toDataURL("image/" + options.mimeType, quality);
1238
+ let file22 = this.dataBase64toFile(url, fileName);
1239
+ if (options.maxSize > 0 && file22.size > options.maxSize * 1024) {
1240
+ quality = quality <= 0 ? 0 : Number((quality - 0.01).toFixed(2));
1241
+ const res = createFile(canvas, fileName, quality);
1242
+ url = res.url;
1243
+ file22 = res.file;
1244
+ quality = res.quality;
1245
+ }
1246
+ return {
1247
+ file: file22,
1248
+ url,
1249
+ quality
1250
+ };
1251
+ };
1252
+ return new Promise((resolve, reject) => {
1253
+ let reader = new FileReader();
1254
+ reader.readAsDataURL(file2);
1255
+ reader.onload = () => {
1256
+ let url = reader.result;
1257
+ let img = new Image();
1258
+ img.src = url;
1259
+ img.onload = () => {
1260
+ if (options.minSize > 0 && file2.size <= options.minSize * 1024) {
1261
+ resolve({
1262
+ file: file2,
1263
+ url,
1264
+ quality: 1,
1265
+ width: img.width,
1266
+ height: img.height
1267
+ });
1268
+ return;
1269
+ }
1270
+ let canvas = document.createElement("canvas");
1271
+ let context = canvas.getContext("2d");
1272
+ canvas.width = options.width || img.width;
1273
+ canvas.height = options.width ? options.width / (img.width / img.height) : img.height;
1274
+ context.drawImage(img, 0, 0, canvas.width, canvas.height);
1275
+ let index = file2.name.lastIndexOf(".");
1276
+ const fileName = file2.name.substring(0, index) + "." + options.mimeType;
1277
+ let res = createFile(canvas, fileName, options.quality);
1278
+ resolve({
1279
+ ...res,
1280
+ width: canvas.width,
1281
+ height: canvas.height
1282
+ });
1283
+ };
1284
+ img.onerror = () => {
1285
+ reject(new Error("Failed to load image file"));
1286
+ };
1287
+ };
1288
+ reader.onerror = () => {
1289
+ reject(new Error("Failed to load image file"));
1290
+ };
1291
+ });
1292
+ }
1293
+ };
1149
1294
  const platform = {
1150
1295
  //设备语言类型
1151
1296
  language() {
@@ -1349,15 +1494,6 @@ const isContains = function(parentNode, childNode) {
1349
1494
  }
1350
1495
  return element$1.isContains(parentNode, childNode);
1351
1496
  };
1352
- const blobToBase64 = function(blob) {
1353
- return new Promise((resolve) => {
1354
- const fileReader = new FileReader();
1355
- fileReader.onload = (e) => {
1356
- resolve(e.target.result);
1357
- };
1358
- fileReader.readAsDataURL(blob);
1359
- });
1360
- };
1361
1497
  const canUseClipboard = function() {
1362
1498
  if (!window.ClipboardItem) {
1363
1499
  console.warn("window.ClipboardItem must be obtained in a secure environment, such as localhost, 127.0.0.1, or https, so the editor's copy, paste, and cut functions cannot be used");
@@ -1395,6 +1531,7 @@ const initEditorOptions = function(options) {
1395
1531
  customHtmlPaste: null,
1396
1532
  customImagePaste: null,
1397
1533
  customVideoPaste: null,
1534
+ customFilePaste: null,
1398
1535
  customMerge: null,
1399
1536
  customParseNode: null
1400
1537
  };
@@ -1432,6 +1569,9 @@ const initEditorOptions = function(options) {
1432
1569
  if (typeof options.customVideoPaste == "function") {
1433
1570
  opts.customVideoPaste = options.customVideoPaste;
1434
1571
  }
1572
+ if (typeof options.customFilePaste == "function") {
1573
+ opts.customFilePaste = options.customFilePaste;
1574
+ }
1435
1575
  if (typeof options.customMerge == "function") {
1436
1576
  opts.customMerge = options.customMerge;
1437
1577
  }
@@ -2805,18 +2945,126 @@ const handleCut = async function(e) {
2805
2945
  this.rangeRender();
2806
2946
  }
2807
2947
  };
2948
+ const doPaste = async function(html, text, files) {
2949
+ if (html) {
2950
+ if (this.allowPasteHtml) {
2951
+ const elements = this.parseHtml(html).filter((el) => {
2952
+ return !el.isEmpty();
2953
+ });
2954
+ if (typeof this.customHtmlPaste == "function") {
2955
+ await this.customHtmlPaste.apply(this, [elements, html]);
2956
+ } else {
2957
+ for (let i = 0; i < elements.length; i++) {
2958
+ this.insertElement(elements[i], false);
2959
+ }
2960
+ this.emit("pasteHtml", elements, html);
2961
+ }
2962
+ } else if (text) {
2963
+ if (typeof this.customTextPaste == "function") {
2964
+ await this.customTextPaste.apply(this, [text]);
2965
+ } else {
2966
+ this.insertText(text);
2967
+ this.emit("pasteText", text);
2968
+ }
2969
+ }
2970
+ } else {
2971
+ if (text) {
2972
+ if (typeof this.customTextPaste == "function") {
2973
+ await this.customTextPaste.apply(this, [text]);
2974
+ } else {
2975
+ this.insertText(text);
2976
+ this.emit("pasteText", text);
2977
+ }
2978
+ } else {
2979
+ let length = files.length;
2980
+ for (let i = 0; i < length; i++) {
2981
+ const url = await file$1.dataFileToBase64(files[i]);
2982
+ if (files[i].type.startsWith("image/")) {
2983
+ if (typeof this.customImagePaste == "function") {
2984
+ await this.customImagePaste.apply(this, [url]);
2985
+ } else {
2986
+ const image = new AlexElement(
2987
+ "closed",
2988
+ "img",
2989
+ {
2990
+ src: url
2991
+ },
2992
+ null,
2993
+ null
2994
+ );
2995
+ this.insertElement(image);
2996
+ this.emit("pasteImage", url);
2997
+ }
2998
+ } else if (files[i].type.startsWith("video/")) {
2999
+ if (typeof this.customVideoPaste == "function") {
3000
+ await this.customVideoPaste.apply(this, [url]);
3001
+ } else {
3002
+ const video = new AlexElement(
3003
+ "closed",
3004
+ "video",
3005
+ {
3006
+ src: url
3007
+ },
3008
+ null,
3009
+ null
3010
+ );
3011
+ this.insertElement(video);
3012
+ this.emit("pasteVideo", url);
3013
+ }
3014
+ } else {
3015
+ if (typeof this.customFilePaste == "function") {
3016
+ await this.customFilePaste.apply(this, [url]);
3017
+ }
3018
+ }
3019
+ }
3020
+ }
3021
+ }
3022
+ };
2808
3023
  const handlePaste = async function(e) {
2809
3024
  e.preventDefault();
2810
3025
  if (this.disabled) {
2811
3026
  return;
2812
3027
  }
2813
- await this.paste();
2814
- this.formatElementStack();
2815
- this.domRender();
2816
- this.rangeRender();
3028
+ if (!this.range) {
3029
+ return;
3030
+ }
3031
+ if (!this.allowPaste) {
3032
+ return;
3033
+ }
3034
+ const event2 = e;
3035
+ if (event2.clipboardData) {
3036
+ const html = event2.clipboardData.getData("text/html");
3037
+ const text = event2.clipboardData.getData("text/plain");
3038
+ const files = event2.clipboardData.files;
3039
+ await doPaste.apply(this, [html, text, files]);
3040
+ this.formatElementStack();
3041
+ this.domRender();
3042
+ this.rangeRender();
3043
+ }
2817
3044
  };
2818
- const handleDragDrop = function(e) {
3045
+ const handleDragDrop = async function(e) {
2819
3046
  e.preventDefault();
3047
+ if (e.type == "drop") {
3048
+ if (this.disabled) {
3049
+ return;
3050
+ }
3051
+ if (!this.range) {
3052
+ return;
3053
+ }
3054
+ if (!this.allowPaste) {
3055
+ return;
3056
+ }
3057
+ const event2 = e;
3058
+ if (event2.dataTransfer) {
3059
+ const html = event2.dataTransfer.getData("text/html");
3060
+ const text = event2.dataTransfer.getData("text/plain");
3061
+ const files = event2.dataTransfer.files;
3062
+ await doPaste.apply(this, [html, text, files]);
3063
+ this.formatElementStack();
3064
+ this.domRender();
3065
+ this.rangeRender();
3066
+ }
3067
+ }
2820
3068
  };
2821
3069
  const handleFocus = function() {
2822
3070
  if (this.disabled) {
@@ -2844,6 +3092,7 @@ class AlexEditor {
2844
3092
  __publicField(this, "customHtmlPaste");
2845
3093
  __publicField(this, "customImagePaste");
2846
3094
  __publicField(this, "customVideoPaste");
3095
+ __publicField(this, "customFilePaste");
2847
3096
  __publicField(this, "customMerge");
2848
3097
  __publicField(this, "customParseNode");
2849
3098
  __publicField(this, "useClipboard", canUseClipboard());
@@ -2869,6 +3118,7 @@ class AlexEditor {
2869
3118
  this.customHtmlPaste = options.customHtmlPaste;
2870
3119
  this.customImagePaste = options.customImagePaste;
2871
3120
  this.customVideoPaste = options.customVideoPaste;
3121
+ this.customFilePaste = options.customFilePaste;
2872
3122
  this.customMerge = options.customMerge;
2873
3123
  this.customParseNode = options.customParseNode;
2874
3124
  this.stack = this.parseHtml(this.value);
@@ -2881,7 +3131,7 @@ class AlexEditor {
2881
3131
  event$1.on(this.$el, "cut.alex_editor", handleCut.bind(this));
2882
3132
  event$1.on(this.$el, "paste.alex_editor", handlePaste.bind(this));
2883
3133
  event$1.on(this.$el, "copy.alex_editor", handleCopy.bind(this));
2884
- event$1.on(this.$el, "dragstart.alex_editor drop.alex_editor ", handleDragDrop.bind(this));
3134
+ event$1.on(this.$el, "dragstart.alex_editor drop.alex_editor", handleDragDrop.bind(this));
2885
3135
  event$1.on(this.$el, "focus.alex_editor", handleFocus.bind(this));
2886
3136
  event$1.on(this.$el, "blur.alex_editor", handleBlur.bind(this));
2887
3137
  }
@@ -2958,114 +3208,6 @@ class AlexEditor {
2958
3208
  }
2959
3209
  return result;
2960
3210
  }
2961
- /**
2962
- * 根据光标进行粘贴操作
2963
- */
2964
- async paste() {
2965
- if (this.disabled) {
2966
- return;
2967
- }
2968
- if (!this.range) {
2969
- return;
2970
- }
2971
- if (!this.useClipboard) {
2972
- return;
2973
- }
2974
- if (!this.allowPaste) {
2975
- return;
2976
- }
2977
- const clipboardItems = await navigator.clipboard.read();
2978
- const clipboardItem = clipboardItems[0];
2979
- const getTypeFunctions = [];
2980
- clipboardItem.types.forEach((type) => {
2981
- getTypeFunctions.push(clipboardItem.getType(type));
2982
- });
2983
- const blobs = await Promise.all(getTypeFunctions);
2984
- const length = blobs.length;
2985
- const hasHtml = blobs.some((blob) => {
2986
- return blob.type == "text/html";
2987
- });
2988
- if (hasHtml) {
2989
- for (let i = 0; i < length; i++) {
2990
- const blob = blobs[i];
2991
- if (blob.type == "text/plain" && !this.allowPasteHtml) {
2992
- const data2 = await blob.text();
2993
- if (data2) {
2994
- if (typeof this.customTextPaste == "function") {
2995
- await this.customTextPaste.apply(this, [data2]);
2996
- } else {
2997
- this.insertText(data2);
2998
- this.emit("pasteText", data2);
2999
- }
3000
- }
3001
- } else if (blob.type == "text/html" && this.allowPasteHtml) {
3002
- const data2 = await blob.text();
3003
- if (data2) {
3004
- const elements = this.parseHtml(data2).filter((el) => {
3005
- return !el.isEmpty();
3006
- });
3007
- if (typeof this.customHtmlPaste == "function") {
3008
- await this.customHtmlPaste.apply(this, [elements, data2]);
3009
- } else {
3010
- for (let i2 = 0; i2 < elements.length; i2++) {
3011
- this.insertElement(elements[i2], false);
3012
- }
3013
- this.emit("pasteHtml", elements, data2);
3014
- }
3015
- }
3016
- }
3017
- }
3018
- } else {
3019
- for (let i = 0; i < length; i++) {
3020
- const blob = blobs[i];
3021
- if (blob.type.startsWith("image/")) {
3022
- const url = await blobToBase64(blob);
3023
- if (typeof this.customImagePaste == "function") {
3024
- await this.customImagePaste.apply(this, [url]);
3025
- } else {
3026
- const image = new AlexElement(
3027
- "closed",
3028
- "img",
3029
- {
3030
- src: url
3031
- },
3032
- null,
3033
- null
3034
- );
3035
- this.insertElement(image);
3036
- this.emit("pasteImage", url);
3037
- }
3038
- } else if (blob.type.startsWith("video/")) {
3039
- const url = await blobToBase64(blob);
3040
- if (typeof this.customVideoPaste == "function") {
3041
- await this.customVideoPaste.apply(this, [url]);
3042
- } else {
3043
- const video = new AlexElement(
3044
- "closed",
3045
- "video",
3046
- {
3047
- src: url
3048
- },
3049
- null,
3050
- null
3051
- );
3052
- this.insertElement(video);
3053
- this.emit("pasteVideo", url);
3054
- }
3055
- } else if (blob.type == "text/plain") {
3056
- const data2 = await blob.text();
3057
- if (data2) {
3058
- if (typeof this.customTextPaste == "function") {
3059
- await this.customTextPaste.apply(this, [data2]);
3060
- } else {
3061
- this.insertText(data2);
3062
- this.emit("pasteText", data2);
3063
- }
3064
- }
3065
- }
3066
- }
3067
- }
3068
- }
3069
3211
  /**
3070
3212
  * 根据光标进行删除操作
3071
3213
  */
@@ -19655,6 +19797,15 @@ const tableHandle = function(editor, element2) {
19655
19797
  } else {
19656
19798
  element2.marks = marks;
19657
19799
  }
19800
+ const styles = {
19801
+ "white-space": "pre-wrap",
19802
+ "word-break": "break-word"
19803
+ };
19804
+ if (element2.hasStyles()) {
19805
+ Object.assign(element2.styles, styles);
19806
+ } else {
19807
+ element2.styles = styles;
19808
+ }
19658
19809
  const elements = AlexElement.flatElements(element2.children);
19659
19810
  const rows = elements.filter((el) => {
19660
19811
  return el.parsedom == "tr";
@@ -20528,7 +20679,8 @@ const _sfc_main$b = /* @__PURE__ */ defineComponent({
20528
20679
  "show-triangle": "",
20529
20680
  color: "#fff",
20530
20681
  placement: "bottom",
20531
- animation: "fade"
20682
+ animation: "fade",
20683
+ "z-index": 10
20532
20684
  }, {
20533
20685
  default: withCtx(() => [
20534
20686
  createElementVNode("div", _hoisted_1$a, toDisplayString(_ctx.content), 1)
@@ -20539,7 +20691,7 @@ const _sfc_main$b = /* @__PURE__ */ defineComponent({
20539
20691
  };
20540
20692
  }
20541
20693
  });
20542
- const Tooltip = /* @__PURE__ */ _export_sfc(_sfc_main$b, [["__scopeId", "data-v-638bc915"]]);
20694
+ const Tooltip = /* @__PURE__ */ _export_sfc(_sfc_main$b, [["__scopeId", "data-v-8372de0b"]]);
20543
20695
  const IconProps = {
20544
20696
  //图标值
20545
20697
  value: {
@@ -21896,7 +22048,8 @@ const _sfc_main$6 = /* @__PURE__ */ defineComponent({
21896
22048
  border: "",
21897
22049
  placement: "bottom-start",
21898
22050
  onShow: layerShow,
21899
- useRange: _ctx.type == "text"
22051
+ useRange: _ctx.type == "text",
22052
+ "z-index": 10
21900
22053
  }, {
21901
22054
  default: withCtx(() => [
21902
22055
  createElementVNode("div", {
@@ -22608,7 +22761,7 @@ const _sfc_main$6 = /* @__PURE__ */ defineComponent({
22608
22761
  };
22609
22762
  }
22610
22763
  });
22611
- const Toolbar = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["__scopeId", "data-v-23266de7"]]);
22764
+ const Toolbar = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["__scopeId", "data-v-44b03ca9"]]);
22612
22765
  const InsertLinkProps = {
22613
22766
  //主题色
22614
22767
  color: {
@@ -24558,7 +24711,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
24558
24711
  };
24559
24712
  }
24560
24713
  });
24561
- const Menu = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-e2dd8748"]]);
24714
+ const Menu = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-226bbacd"]]);
24562
24715
  const EditifyProps = {
24563
24716
  //国际化语言类型
24564
24717
  locale: {
@@ -24643,6 +24796,11 @@ const EditifyProps = {
24643
24796
  type: Function,
24644
24797
  default: null
24645
24798
  },
24799
+ //自定义粘贴文件
24800
+ customFilePaste: {
24801
+ type: Function,
24802
+ default: null
24803
+ },
24646
24804
  //菜单栏配置
24647
24805
  menu: {
24648
24806
  type: Object,
@@ -25066,8 +25224,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
25066
25224
  allowPaste: props.allowPaste,
25067
25225
  allowCut: props.allowCut,
25068
25226
  allowPasteHtml: props.allowPasteHtml,
25069
- customImagePaste: handleCustomImagePaste,
25070
- customVideoPaste: handleCustomVideoPaste,
25227
+ customImagePaste: props.customImagePaste,
25228
+ customVideoPaste: props.customVideoPaste,
25229
+ customFilePaste: props.customFilePaste,
25071
25230
  customMerge: handleCustomMerge,
25072
25231
  customParseNode: handleCustomParseNode
25073
25232
  });
@@ -25197,18 +25356,6 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
25197
25356
  }
25198
25357
  }
25199
25358
  };
25200
- const handleCustomImagePaste = async (url) => {
25201
- const newUrl = await props.customImagePaste.apply(instance.proxy, [url]);
25202
- if (newUrl) {
25203
- insertImage(editor.value, newUrl);
25204
- }
25205
- };
25206
- const handleCustomVideoPaste = async (url) => {
25207
- const newUrl = await props.customVideoPaste.apply(instance.proxy, [url]);
25208
- if (newUrl) {
25209
- insertVideo(editor.value, newUrl);
25210
- }
25211
- };
25212
25359
  const handleCustomMerge = (ele, preEle) => {
25213
25360
  const uneditable = preEle.getUneditableElement();
25214
25361
  if (uneditable) {
@@ -25569,8 +25716,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
25569
25716
  };
25570
25717
  }
25571
25718
  });
25572
- const Editify = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-99f85ef5"]]);
25573
- const version = "0.1.13";
25719
+ const Editify = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-fed58116"]]);
25720
+ const version = "0.1.16";
25574
25721
  const install = (app) => {
25575
25722
  app.component(Editify.name, Editify);
25576
25723
  };