vue-editify 0.1.36 → 0.1.37

Sign up to get free protection for your applications and to get access to all the features.
package/examples/App.vue CHANGED
@@ -6,7 +6,7 @@
6
6
  <script setup lang="ts">
7
7
  import { h, ref } from 'vue'
8
8
  import { AlexElement, MenuConfigType, Editify, attachment, PluginType } from '../src/index'
9
- const val = ref<string>('<p><br></p>')
9
+ const val = ref<string>('<p><span data-editify-attachment="xxxxx" ></span></p>')
10
10
  const editify = ref<InstanceType<typeof Editify> | null>(null)
11
11
  const menuConfig = ref<MenuConfigType>({
12
12
  use: true,
@@ -25,6 +25,7 @@ const menuConfig = ref<MenuConfigType>({
25
25
  const plugins = ref<PluginType[]>([
26
26
  attachment({
27
27
  multiple: true,
28
+ leftBorder: true,
28
29
  customUpload: (files: File[]) => {
29
30
  return files.map(item => {
30
31
  return 'xxx'
@@ -308,3 +308,10 @@ export declare const insertTable: (editor: AlexEditor, rowLength: number, colLen
308
308
  * @returns
309
309
  */
310
310
  export declare const insertCodeBlock: (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType) => void;
311
+ /**
312
+ * 插入分隔线
313
+ * @param editor
314
+ * @param dataRangeCaches
315
+ * @returns
316
+ */
317
+ export declare const insertSeparator: (editor: AlexEditor) => void;
@@ -14,11 +14,11 @@ export declare const parseList: (editor: AlexEditor, element: AlexElement) => vo
14
14
  */
15
15
  export declare const orderdListHandle: (editor: AlexEditor, element: AlexElement) => void;
16
16
  /**
17
- * 元素格式化时处理媒体元素和链接
17
+ * 元素格式化时处理常规元素(图片、视频、分隔线、行内代码)
18
18
  * @param editor
19
19
  * @param element
20
20
  */
21
- export declare const mediaHandle: (editor: AlexEditor, element: AlexElement) => void;
21
+ export declare const commonElementHandle: (editor: AlexEditor, element: AlexElement) => void;
22
22
  /**
23
23
  * 元素格式化时处理表格
24
24
  * @param editor
@@ -150,6 +150,7 @@ export type MenuConfigType = {
150
150
  heading?: MenuDisplayButtonType;
151
151
  indent?: MenuSelectButtonType;
152
152
  quote?: MenuButtonType;
153
+ separator?: MenuButtonType;
153
154
  align?: MenuSelectButtonType;
154
155
  orderList?: MenuButtonType;
155
156
  unorderList?: MenuButtonType;
package/lib/editify.es.js CHANGED
@@ -3194,7 +3194,7 @@ class AlexEditor {
3194
3194
  event$1.on(this.$el, "blur.alex_editor", handleBlur.bind(this));
3195
3195
  }
3196
3196
  /**
3197
- * 初始化range
3197
+ * 初始化设置默认的range
3198
3198
  */
3199
3199
  initRange() {
3200
3200
  const elements = AlexElement.flatElements(this.stack).filter((el) => {
@@ -4520,7 +4520,7 @@ class AlexEditor {
4520
4520
  event$1.off(this.$el, "beforeinput.alex_editor compositionstart.alex_editor compositionupdate.alex_editor compositionend.alex_editor keydown.alex_editor cut.alex_editor paste.alex_editor copy.alex_editor dragstart.alex_editor drop.alex_editor focus.alex_editor blur.alex_editor");
4521
4521
  }
4522
4522
  }
4523
- const version$2 = "1.3.36";
4523
+ const version$2 = "1.3.37";
4524
4524
  console.log(`%c alex-editor %c v${version$2} `, "padding: 2px 1px; border-radius: 3px 0 0 3px; color: #fff; background: #606060; font-weight: bold;", "padding: 2px 1px; border-radius: 0 3px 3px 0; color: #fff; background: #42c02e; font-weight: bold;");
4525
4525
  const number = {
4526
4526
  /**
@@ -18393,30 +18393,31 @@ const getMenuConfig = function(editTrans, editLocale) {
18393
18393
  heading: 2,
18394
18394
  indent: 3,
18395
18395
  quote: 4,
18396
- align: 5,
18397
- orderList: 6,
18398
- unorderList: 7,
18399
- task: 8,
18400
- bold: 9,
18401
- underline: 10,
18402
- italic: 11,
18403
- strikethrough: 12,
18404
- code: 13,
18405
- super: 14,
18406
- sub: 15,
18407
- formatClear: 16,
18408
- fontSize: 17,
18409
- fontFamily: 18,
18410
- lineHeight: 19,
18411
- foreColor: 20,
18412
- backColor: 21,
18413
- link: 22,
18414
- image: 23,
18415
- video: 24,
18416
- table: 25,
18417
- codeBlock: 26,
18418
- sourceView: 27,
18419
- fullScreen: 28
18396
+ separator: 5,
18397
+ align: 6,
18398
+ orderList: 7,
18399
+ unorderList: 8,
18400
+ task: 9,
18401
+ bold: 10,
18402
+ underline: 11,
18403
+ italic: 12,
18404
+ strikethrough: 13,
18405
+ code: 14,
18406
+ super: 15,
18407
+ sub: 16,
18408
+ formatClear: 17,
18409
+ fontSize: 18,
18410
+ fontFamily: 19,
18411
+ lineHeight: 20,
18412
+ foreColor: 21,
18413
+ backColor: 22,
18414
+ link: 23,
18415
+ image: 24,
18416
+ video: 25,
18417
+ table: 26,
18418
+ codeBlock: 27,
18419
+ sourceView: 28,
18420
+ fullScreen: 29
18420
18421
  },
18421
18422
  //撤销按钮配置
18422
18423
  undo: {
@@ -18468,7 +18469,7 @@ const getMenuConfig = function(editTrans, editLocale) {
18468
18469
  //右侧边框是否显示
18469
18470
  rightBorder: false
18470
18471
  },
18471
- //引用按钮配置
18472
+ //引用
18472
18473
  quote: {
18473
18474
  //是否显示此按钮
18474
18475
  show: true,
@@ -18477,6 +18478,15 @@ const getMenuConfig = function(editTrans, editLocale) {
18477
18478
  //右侧边框是否显示
18478
18479
  rightBorder: false
18479
18480
  },
18481
+ //分隔线
18482
+ separator: {
18483
+ //是否显示此按钮
18484
+ show: true,
18485
+ //左侧边框是否显示
18486
+ leftBorder: false,
18487
+ //右侧边框是否显示
18488
+ rightBorder: false
18489
+ },
18480
18490
  //对齐方式
18481
18491
  align: {
18482
18492
  //是否显示此工具
@@ -18492,7 +18502,7 @@ const getMenuConfig = function(editTrans, editLocale) {
18492
18502
  //右侧边框是否显示
18493
18503
  rightBorder: false
18494
18504
  },
18495
- //有序列表按钮配置
18505
+ //有序列表
18496
18506
  orderList: {
18497
18507
  //是否显示此按钮
18498
18508
  show: true,
@@ -18501,7 +18511,7 @@ const getMenuConfig = function(editTrans, editLocale) {
18501
18511
  //右侧边框是否显示
18502
18512
  rightBorder: false
18503
18513
  },
18504
- //无序列表按钮配置
18514
+ //无序列表
18505
18515
  unorderList: {
18506
18516
  //是否显示此按钮
18507
18517
  show: true,
@@ -18510,7 +18520,7 @@ const getMenuConfig = function(editTrans, editLocale) {
18510
18520
  //右侧边框是否显示
18511
18521
  rightBorder: false
18512
18522
  },
18513
- //任务列表按钮配置
18523
+ //任务列表
18514
18524
  task: {
18515
18525
  //是否显示此按钮
18516
18526
  show: true,
@@ -18519,7 +18529,7 @@ const getMenuConfig = function(editTrans, editLocale) {
18519
18529
  //右侧边框是否显示
18520
18530
  rightBorder: false
18521
18531
  },
18522
- //粗体按钮配置
18532
+ //粗体
18523
18533
  bold: {
18524
18534
  //是否显示此按钮
18525
18535
  show: true,
@@ -18528,7 +18538,7 @@ const getMenuConfig = function(editTrans, editLocale) {
18528
18538
  //右侧边框是否显示
18529
18539
  rightBorder: false
18530
18540
  },
18531
- //下划线按钮配置
18541
+ //下划线
18532
18542
  underline: {
18533
18543
  //是否显示此按钮
18534
18544
  show: true,
@@ -18537,7 +18547,7 @@ const getMenuConfig = function(editTrans, editLocale) {
18537
18547
  //右侧边框是否显示
18538
18548
  rightBorder: false
18539
18549
  },
18540
- //斜体按钮配置
18550
+ //斜体
18541
18551
  italic: {
18542
18552
  //是否显示此按钮
18543
18553
  show: true,
@@ -18546,7 +18556,7 @@ const getMenuConfig = function(editTrans, editLocale) {
18546
18556
  //右侧边框是否显示
18547
18557
  rightBorder: false
18548
18558
  },
18549
- //删除线按钮配置
18559
+ //删除线
18550
18560
  strikethrough: {
18551
18561
  //是否显示此按钮
18552
18562
  show: true,
@@ -18555,7 +18565,7 @@ const getMenuConfig = function(editTrans, editLocale) {
18555
18565
  //右侧边框是否显示
18556
18566
  rightBorder: false
18557
18567
  },
18558
- //行内代码按钮配置
18568
+ //行内代码
18559
18569
  code: {
18560
18570
  //是否显示此按钮
18561
18571
  show: true,
@@ -18742,7 +18752,7 @@ const getMenuConfig = function(editTrans, editLocale) {
18742
18752
  //是否显示此工具
18743
18753
  show: false,
18744
18754
  //左侧边框是否显示
18745
- leftBorder: false,
18755
+ leftBorder: true,
18746
18756
  //右侧边框是否显示
18747
18757
  rightBorder: false
18748
18758
  },
@@ -19709,6 +19719,19 @@ const insertCodeBlock = (editor, dataRangeCaches) => {
19709
19719
  }
19710
19720
  }
19711
19721
  };
19722
+ const insertSeparator = (editor) => {
19723
+ if (!editor.range) {
19724
+ return;
19725
+ }
19726
+ const separator = new AlexElement("closed", "hr", null, null, null);
19727
+ editor.insertElement(separator);
19728
+ const leftSpace = AlexElement.getSpaceElement();
19729
+ const rightSpace = AlexElement.getSpaceElement();
19730
+ editor.addElementAfter(rightSpace, separator);
19731
+ editor.addElementBefore(leftSpace, separator);
19732
+ editor.range.anchor.moveToEnd(rightSpace);
19733
+ editor.range.focus.moveToEnd(rightSpace);
19734
+ };
19712
19735
  const updateRangeInPre = (editor, element2, originalTextElements, newElements) => {
19713
19736
  if (!editor.range) {
19714
19737
  return;
@@ -19755,10 +19778,13 @@ const parseList = (editor, element2) => {
19755
19778
  const newEl = el.clone();
19756
19779
  newEl.parsedom = "div";
19757
19780
  newEl.type = element2.type;
19758
- if (!newEl.hasMarks()) {
19759
- newEl.marks = {};
19781
+ if (newEl.hasMarks()) {
19782
+ newEl.marks["data-editify-list"] = element2.parsedom;
19783
+ } else {
19784
+ newEl.marks = {
19785
+ "data-editify-list": element2.parsedom
19786
+ };
19760
19787
  }
19761
- newEl.marks["data-editify-list"] = element2.parsedom;
19762
19788
  editor.addElementBefore(newEl, element2);
19763
19789
  });
19764
19790
  }
@@ -19776,7 +19802,7 @@ const orderdListHandle = function(editor, element2) {
19776
19802
  }
19777
19803
  }
19778
19804
  };
19779
- const mediaHandle = function(editor, element2) {
19805
+ const commonElementHandle = function(editor, element2) {
19780
19806
  if (element2.parsedom == "img" || element2.parsedom == "video" || element2.parsedom == "a") {
19781
19807
  const marks = {
19782
19808
  "data-editify-element": element2.key
@@ -19787,18 +19813,29 @@ const mediaHandle = function(editor, element2) {
19787
19813
  element2.marks = marks;
19788
19814
  }
19789
19815
  }
19790
- if (element2.parsedom == "video") {
19816
+ if (element2.parsedom == "video" || element2.parsedom == "hr") {
19791
19817
  const previousElement = editor.getPreviousElement(element2);
19792
19818
  const newTextElement = editor.getNextElement(element2);
19793
- if (!previousElement || previousElement.isEmpty()) {
19819
+ if (!previousElement || !previousElement.isSpaceText()) {
19794
19820
  const spaceText = AlexElement.getSpaceElement();
19795
19821
  editor.addElementBefore(spaceText, element2);
19796
19822
  }
19797
- if (!newTextElement || newTextElement.isEmpty()) {
19823
+ if (!newTextElement || !newTextElement.isSpaceText()) {
19798
19824
  const spaceText = AlexElement.getSpaceElement();
19799
19825
  editor.addElementAfter(spaceText, element2);
19800
19826
  }
19801
19827
  }
19828
+ if (element2.parsedom == "code") {
19829
+ element2.parsedom = "span";
19830
+ const marks = {
19831
+ "data-editify-code": true
19832
+ };
19833
+ if (element2.hasMarks()) {
19834
+ Object.assign(element2.marks, marks);
19835
+ } else {
19836
+ element2.marks = marks;
19837
+ }
19838
+ }
19802
19839
  };
19803
19840
  const tableHandle = function(editor, element2) {
19804
19841
  if (element2.parsedom == "table") {
@@ -23465,6 +23502,13 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
23465
23502
  active: false,
23466
23503
  disabled: false
23467
23504
  });
23505
+ const separatorConfig = ref({
23506
+ show: props.config.separator.show,
23507
+ leftBorder: props.config.separator.leftBorder,
23508
+ rightBorder: props.config.separator.rightBorder,
23509
+ active: false,
23510
+ disabled: false
23511
+ });
23468
23512
  const alignConfig = ref({
23469
23513
  show: props.config.align.show,
23470
23514
  selectConfig: {
@@ -23764,6 +23808,11 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
23764
23808
  editor.value.formatElementStack();
23765
23809
  editor.value.domRender();
23766
23810
  editor.value.rangeRender();
23811
+ } else if (name == "separator") {
23812
+ insertSeparator(editor.value);
23813
+ editor.value.formatElementStack();
23814
+ editor.value.domRender();
23815
+ editor.value.rangeRender();
23767
23816
  } else if (name == "align") {
23768
23817
  setAlign(editor.value, dataRangeCaches.value, val);
23769
23818
  editor.value.formatElementStack();
@@ -24186,6 +24235,22 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
24186
24235
  () => h(Icon, { value: "quote" })
24187
24236
  );
24188
24237
  }
24238
+ if (itemProps.name == "separator" && separatorConfig.value.show) {
24239
+ return h(
24240
+ Button,
24241
+ {
24242
+ ...itemProps,
24243
+ title: $editTrans("separator"),
24244
+ leftBorder: separatorConfig.value.leftBorder,
24245
+ rightBorder: separatorConfig.value.rightBorder,
24246
+ color: props.color,
24247
+ disabled: separatorConfig.value.disabled || selfProps.disabled || disabled.value,
24248
+ active: separatorConfig.value.active,
24249
+ onOperate: handleOperate
24250
+ },
24251
+ () => h(Icon, { value: "separator" })
24252
+ );
24253
+ }
24189
24254
  if (itemProps.name == "align" && alignConfig.value.show) {
24190
24255
  return h(
24191
24256
  Button,
@@ -24789,7 +24854,7 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
24789
24854
  };
24790
24855
  }
24791
24856
  });
24792
- const Menu = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-98c51b8e"]]);
24857
+ const Menu = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-13b11735"]]);
24793
24858
  const EditifyProps = {
24794
24859
  //国际化语言类型
24795
24860
  locale: {
@@ -24994,6 +25059,7 @@ const en_US = {
24994
25059
  undo: "Undo",
24995
25060
  redo: "Redo",
24996
25061
  quote: "Quote",
25062
+ separator: "Separator",
24997
25063
  lineHeight: "Line height",
24998
25064
  indent: "Indent",
24999
25065
  insertLink: "Insert Link",
@@ -25088,6 +25154,7 @@ const zh_CN = {
25088
25154
  undo: "撤销",
25089
25155
  redo: "重做",
25090
25156
  quote: "引用",
25157
+ separator: "分隔线",
25091
25158
  lineHeight: "行高",
25092
25159
  indent: "缩进",
25093
25160
  insertLink: "插入链接",
@@ -25330,7 +25397,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
25330
25397
  orderdListHandle(editor.value, el);
25331
25398
  },
25332
25399
  (el) => {
25333
- mediaHandle(editor.value, el);
25400
+ commonElementHandle(editor.value, el);
25334
25401
  },
25335
25402
  (el) => {
25336
25403
  tableHandle(editor.value, el);
@@ -25540,17 +25607,6 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
25540
25607
  }
25541
25608
  };
25542
25609
  const handleCustomParseNode = (ele) => {
25543
- if (ele.parsedom == "code") {
25544
- ele.parsedom = "span";
25545
- const marks = {
25546
- "data-editify-code": true
25547
- };
25548
- if (ele.hasMarks()) {
25549
- Object.assign(ele.marks, marks);
25550
- } else {
25551
- ele.marks = marks;
25552
- }
25553
- }
25554
25610
  pluginResultList.value.forEach((pluginResult) => {
25555
25611
  if (pluginResult.customParseNode) {
25556
25612
  ele = pluginResult.customParseNode(ele);
@@ -25885,7 +25941,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
25885
25941
  };
25886
25942
  }
25887
25943
  });
25888
- const Editify = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-4c71ae18"]]);
25944
+ const Editify = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-21167e28"]]);
25889
25945
  const InsertAttachmentProps = {
25890
25946
  //主题色
25891
25947
  color: {
@@ -26132,7 +26188,7 @@ const isAttachment = (element2) => {
26132
26188
  if (element2.isEmpty()) {
26133
26189
  return false;
26134
26190
  }
26135
- return element2.parsedom == "span" && element2.type == "closed" && element2.hasMarks() && element2.marks["data-attachment"];
26191
+ return element2.parsedom == "span" && element2.type == "closed" && element2.hasMarks() && element2.marks["data-editify-attachment"];
26136
26192
  };
26137
26193
  const hasAttachmentInRange = (editor, dataRangeCaches) => {
26138
26194
  if (!editor.range) {
@@ -26193,18 +26249,17 @@ const attachment = (options) => {
26193
26249
  const editor = editifyInstance.exposed.editor.value;
26194
26250
  urls.forEach((url) => {
26195
26251
  const marks = {
26196
- "data-attachment": url,
26197
- "data-attachment-name": name || editTrans("attachmentDefaultName"),
26198
- contenteditable: "false"
26252
+ "data-editify-attachment": url,
26253
+ "data-editify-attachment-name": name || editTrans("attachmentDefaultName")
26199
26254
  };
26200
26255
  const attachmentElement = new AlexElement("closed", "span", marks, null, null);
26201
26256
  editor.insertElement(attachmentElement);
26202
- const beforeText = AlexElement.getSpaceElement();
26203
- const afterText = AlexElement.getSpaceElement();
26204
- editor.addElementAfter(afterText, attachmentElement);
26205
- editor.addElementBefore(beforeText, attachmentElement);
26206
- editor.range.anchor.moveToStart(afterText);
26207
- editor.range.focus.moveToStart(afterText);
26257
+ const leftSpace = AlexElement.getSpaceElement();
26258
+ const rightSpace = AlexElement.getSpaceElement();
26259
+ editor.addElementBefore(leftSpace, attachmentElement);
26260
+ editor.addElementAfter(rightSpace, attachmentElement);
26261
+ editor.range.anchor.moveToEnd(rightSpace);
26262
+ editor.range.focus.moveToEnd(rightSpace);
26208
26263
  });
26209
26264
  editor.formatElementStack();
26210
26265
  editor.domRender();
@@ -26219,10 +26274,10 @@ const attachment = (options) => {
26219
26274
  updateView: () => {
26220
26275
  const editor = editifyInstance.exposed.editor.value;
26221
26276
  AlexElement.flatElements(editor.stack).forEach((el) => {
26222
- if (el.parsedom == "span" && el.hasMarks() && el.marks["data-attachment"]) {
26277
+ if (el.parsedom == "span" && el.hasMarks() && el.marks["data-editify-attachment"]) {
26223
26278
  event.off(el.elm, "click");
26224
26279
  event.on(el.elm, "click", async () => {
26225
- const url = el.marks["data-attachment"];
26280
+ const url = el.marks["data-editify-attachment"];
26226
26281
  const res = await fetch(url, {
26227
26282
  method: "GET"
26228
26283
  });
@@ -26230,28 +26285,31 @@ const attachment = (options) => {
26230
26285
  const a = document.createElement("a");
26231
26286
  a.setAttribute("target", "_blank");
26232
26287
  a.setAttribute("href", URL.createObjectURL(blob));
26233
- a.setAttribute("download", el.marks["data-attachment-name"]);
26288
+ a.setAttribute("download", el.marks["data-editify-attachment-name"]);
26234
26289
  a.click();
26235
26290
  });
26236
26291
  }
26237
26292
  });
26238
26293
  },
26239
- //span含有data-attachment的元素设为自闭合元素
26294
+ //span含有data-editify-attachment的元素设为自闭合元素
26240
26295
  customParseNode: (el) => {
26241
- if (el.hasMarks() && el.marks["data-attachment"] && el.parsedom == "span") {
26296
+ if (el.hasMarks() && el.marks["data-editify-attachment"] && el.parsedom == "span") {
26242
26297
  el.type = "closed";
26243
26298
  }
26244
26299
  return el;
26245
26300
  },
26246
- //span元素粘贴保留data-attachment
26301
+ //span元素粘贴保留data-editify-attachment
26247
26302
  pasteKeepMarks: {
26248
- "data-attachment": ["span"],
26249
- "data-attachment-name": ["span"]
26303
+ "data-editify-attachment": ["span"],
26304
+ "data-editify-attachment-name": ["span"]
26250
26305
  },
26251
26306
  //自定义渲染规范
26252
26307
  renderRule: (el) => {
26253
- if (el.type == "closed" && el.hasMarks() && el.marks["data-attachment"]) {
26308
+ if (el.hasMarks() && el.marks["data-editify-attachment"]) {
26254
26309
  el.marks["title"] = editTrans("attachmentDownloadTitle");
26310
+ if (!el.marks["data-editify-attachment-name"]) {
26311
+ el.marks["data-editify-attachment-name"] = editTrans("attachmentDefaultName");
26312
+ }
26255
26313
  const editor = editifyInstance.exposed.editor.value;
26256
26314
  const previousElement = editor.getPreviousElement(el);
26257
26315
  const newTextElement = editor.getNextElement(el);
@@ -26272,7 +26330,7 @@ const attachment = (options) => {
26272
26330
  const install = (app) => {
26273
26331
  app.component(Editify.name, Editify);
26274
26332
  };
26275
- const version = "0.1.36";
26333
+ const version = "0.1.37";
26276
26334
  console.log(`%c vue-editify %c v${version} `, "padding: 2px 1px; border-radius: 3px 0 0 3px; color: #fff; background: #606060; font-weight: bold;", "padding: 2px 1px; border-radius: 0 3px 3px 0; color: #fff; background: #42c02e; font-weight: bold;");
26277
26335
  export {
26278
26336
  AlexElement,