vue-editify 0.1.39 → 0.1.41

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue-editify",
3
- "version": "0.1.39",
3
+ "version": "0.1.41",
4
4
  "private": false,
5
5
  "sideEffects": [
6
6
  "*.css"
@@ -7,7 +7,7 @@
7
7
  font-size: @font-size;
8
8
 
9
9
  .editify-button-wrap {
10
- padding: 0 4px;
10
+ padding: 2px 4px;
11
11
  position: relative;
12
12
 
13
13
  &.editify-right-border::after {
@@ -1,6 +1,6 @@
1
1
  @font-face {
2
2
  font-family: 'editify-icon';
3
- src: url('../../icon/iconfont.woff?t=1699274556400') format('woff'), url('../../icon/iconfont.ttf?t=1699274556400') format('truetype');
3
+ src: url('../../icon/iconfont.woff?t=2024051301') format('woff'), url('../../icon/iconfont.ttf?t=2024051301') format('truetype');
4
4
  }
5
5
 
6
6
  .editify-icon {
@@ -14,7 +14,7 @@ import InsertVideo from '../insertVideo/insertVideo.vue'
14
14
  import InsertTable from '../insertTable/insertTable.vue'
15
15
  import { h, getCurrentInstance, ref, computed, inject, ComponentInternalInstance, Ref, ComputedRef, defineComponent } from 'vue'
16
16
  import { common as DapCommon } from 'dap-util'
17
- import { getRangeText, setHeading, setIndentIncrease, setIndentDecrease, setQuote, setAlign, setList, setTask, setTextStyle, setTextMark, removeTextStyle, removeTextMark, setLineHeight, insertLink, insertImage, insertVideo, insertTable, insertCodeBlock, hasPreInRange, hasTableInRange, hasQuoteInRange, hasLinkInRange, isRangeInQuote, isRangeInList, isRangeInTask, queryTextStyle, queryTextMark, getCurrentParsedomElement, hasImageInRange, hasVideoInRange, insertSeparator } from '../../core/function'
17
+ import { getRangeText, setHeading, setIndentIncrease, setIndentDecrease, setQuote, setAlign, setList, setTask, setTextStyle, setTextMark, removeTextStyle, removeTextMark, setLineHeight, insertLink, insertImage, insertVideo, insertTable, insertCodeBlock, hasPreInRange, hasTableInRange, hasQuoteInRange, hasLinkInRange, isRangeInQuote, isRangeInList, isRangeInTask, queryTextStyle, queryTextMark, getMatchElementsByRange, hasImageInRange, hasVideoInRange, insertSeparator } from '../../core/function'
18
18
  import { MenuProps } from './props'
19
19
  import { MenuModeType, ObjectType, PluginResultType, MenuExtendType, MenuSequenceType, mergeObject } from '../../core/tool'
20
20
  import { AlexEditor, AlexElementsRangeType } from 'alex-editor'
@@ -923,7 +923,7 @@ const handleRangeUpdate = () => {
923
923
  tableConfig.value.disabled = value_hasPreInRange || value_hasTableInRange || value_hasQuoteInRange || extraDisabled('table')
924
924
 
925
925
  //代码块按钮激活
926
- codeBlockConfig.value.active = !!getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'pre')
926
+ codeBlockConfig.value.active = getMatchElementsByRange(editor.value, dataRangeCaches.value, { parsedom: 'pre' }).length == 1
927
927
  //代码块按钮禁用
928
928
  codeBlockConfig.value.disabled = value_hasTableInRange || value_hasQuoteInRange || value_hasImageInRange || value_hasVideoInRange || extraDisabled('codeBlock')
929
929
 
@@ -100,7 +100,7 @@
100
100
  <Icon value="delete-column"></Icon>
101
101
  </Button>
102
102
  <!-- 删除表格 -->
103
- <Button @operate="deleteElement('table')" name="deleteTable" :title="$editTrans('deleteTable')" :tooltip="config.tooltip" :color="color">
103
+ <Button @operate="deleteElement('table')" leftBorder name="deleteTable" :title="$editTrans('deleteTable')" :tooltip="config.tooltip" :color="color">
104
104
  <Icon value="delete-table"></Icon>
105
105
  </Button>
106
106
  </template>
@@ -201,7 +201,7 @@ import Checkbox from '../checkbox/checkbox.vue'
201
201
  import Colors from '../colors/colors.vue'
202
202
  import { AlexEditor, AlexElement, AlexElementsRangeType } from 'alex-editor'
203
203
  import { common as DapCommon } from 'dap-util'
204
- import { getCurrentParsedomElement, removeTextStyle, removeTextMark, setTextStyle, setLineHeight, setTextMark, setList, setTask, setHeading, setAlign, isRangeInList, isRangeInTask, queryTextStyle, queryTextMark } from '../../core/function'
204
+ import { getMatchElementsByRange, removeTextStyle, removeTextMark, setTextStyle, setLineHeight, setTextMark, setList, setTask, setHeading, setAlign, isRangeInList, isRangeInTask, queryTextStyle, queryTextMark } from '../../core/function'
205
205
  import { ToolbarProps } from './props'
206
206
  import { Ref, computed, inject, ref } from 'vue'
207
207
  import { ObjectType } from '../../core/tool'
@@ -229,6 +229,7 @@ const linkConfig = ref<ObjectType>({
229
229
  //链接是否新窗口打开
230
230
  newOpen: false
231
231
  })
232
+
232
233
  //视频参数配置
233
234
  const videoConfig = ref<ObjectType>({
234
235
  //是否显示控制器
@@ -240,6 +241,7 @@ const videoConfig = ref<ObjectType>({
240
241
  //是否静音
241
242
  muted: false
242
243
  })
244
+
243
245
  //代码块选择语言按钮配置
244
246
  const languageConfig = ref<ObjectType>({
245
247
  show: props.config.codeBlock!.languages!.show,
@@ -254,6 +256,8 @@ const languageConfig = ref<ObjectType>({
254
256
  active: false,
255
257
  disabled: false
256
258
  })
259
+
260
+ /** 以下是文本工具条的配置参数信息 */
257
261
  //标题按钮配置
258
262
  const headingConfig = ref<ObjectType>({
259
263
  show: props.config.text!.heading!.show,
@@ -674,36 +678,36 @@ const modifyLink = () => {
674
678
  if (!linkConfig.value.url) {
675
679
  return
676
680
  }
677
- const link = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'a')
678
- if (link) {
679
- link.marks!.href = linkConfig.value.url
681
+ const links = getMatchElementsByRange(editor.value, dataRangeCaches.value, { parsedom: 'a' })
682
+ if (links.length == 1) {
683
+ links[0].marks!.href = linkConfig.value.url
680
684
  if (linkConfig.value.newOpen) {
681
- link.marks!.target = '_blank'
685
+ links[0].marks!.target = '_blank'
682
686
  } else {
683
- delete link.marks!.target
687
+ delete links[0].marks!.target
684
688
  }
689
+ editor.value.formatElementStack()
690
+ editor.value.domRender()
685
691
  }
686
- editor.value.formatElementStack()
687
- editor.value.domRender()
688
692
  }
689
693
  //移除链接
690
694
  const removeLink = () => {
691
- const link = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'a')
692
- if (link) {
693
- link.parsedom = AlexElement.TEXT_NODE
694
- delete link.marks!['target']
695
- delete link.marks!['href']
696
- delete link.marks!['data-editify-element']
695
+ const links = getMatchElementsByRange(editor.value, dataRangeCaches.value, { parsedom: 'a' })
696
+ if (links.length == 1) {
697
+ links[0].parsedom = AlexElement.TEXT_NODE
698
+ delete links[0].marks!['target']
699
+ delete links[0].marks!['href']
700
+ delete links[0].marks!['data-editify-element']
701
+ editor.value.formatElementStack()
702
+ editor.value.domRender()
703
+ editor.value.rangeRender()
697
704
  }
698
- editor.value.formatElementStack()
699
- editor.value.domRender()
700
- editor.value.rangeRender()
701
705
  }
702
706
  //选择代码语言
703
707
  const selectLanguage = (_name: string, value: string) => {
704
- const pre = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'pre')
705
- if (pre) {
706
- Object.assign(pre.marks!, {
708
+ const pres = getMatchElementsByRange(editor.value, dataRangeCaches.value, { parsedom: 'pre' })
709
+ if (pres.length == 1) {
710
+ Object.assign(pres[0].marks!, {
707
711
  'data-editify-hljs': value
708
712
  })
709
713
  editor.value.formatElementStack()
@@ -717,15 +721,15 @@ const insertParagraphWithPre = (type: string | undefined = 'up') => {
717
721
  editor.value.range!.anchor.element = editor.value.range!.focus.element
718
722
  editor.value.range!.anchor.offset = editor.value.range!.focus.offset
719
723
  }
720
- const pre = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'pre')
721
- if (pre) {
724
+ const pres = getMatchElementsByRange(editor.value, dataRangeCaches.value, { parsedom: 'pre' })
725
+ if (pres.length == 1) {
722
726
  const paragraph = new AlexElement('block', AlexElement.BLOCK_NODE, null, null, null)
723
727
  const breakEl = new AlexElement('closed', 'br', null, null, null)
724
728
  editor.value.addElementTo(breakEl, paragraph)
725
729
  if (type == 'up') {
726
- editor.value.addElementBefore(paragraph, pre)
730
+ editor.value.addElementBefore(paragraph, pres[0])
727
731
  } else {
728
- editor.value.addElementAfter(paragraph, pre)
732
+ editor.value.addElementAfter(paragraph, pres[0])
729
733
  }
730
734
  editor.value.range!.anchor.moveToEnd(paragraph)
731
735
  editor.value.range!.focus.moveToEnd(paragraph)
@@ -740,17 +744,17 @@ const insertTableColumn = (type: string | undefined = 'left') => {
740
744
  editor.value.range!.anchor.element = editor.value.range!.focus.element
741
745
  editor.value.range!.anchor.offset = editor.value.range!.focus.offset
742
746
  }
743
- const table = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'table')
744
- const column = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'td')
745
- const tbody = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'tbody')
746
- if (column && table && tbody) {
747
- const rows = tbody.children
748
- const index = column.parent!.children!.findIndex(item => {
749
- return item.isEqual(column)
747
+ const tables = getMatchElementsByRange(editor.value, dataRangeCaches.value, { parsedom: 'table' })
748
+ const columns = getMatchElementsByRange(editor.value, dataRangeCaches.value, { parsedom: 'td' })
749
+ const tbodys = getMatchElementsByRange(editor.value, dataRangeCaches.value, { parsedom: 'tbody' })
750
+ if (tables.length == 1 && tbodys.length == 1 && columns.length == 1) {
751
+ const rows = tbodys[0].children
752
+ const index = columns[0].parent!.children!.findIndex(item => {
753
+ return item.isEqual(columns[0])
750
754
  })
751
755
  //插入列
752
756
  rows!.forEach(row => {
753
- const newColumn = column.clone(false)
757
+ const newColumn = columns[0].clone(false)
754
758
  const breakEl = new AlexElement('closed', 'br', null, null, null)
755
759
  editor.value.addElementTo(breakEl, newColumn)
756
760
  if (type == 'left') {
@@ -760,7 +764,7 @@ const insertTableColumn = (type: string | undefined = 'left') => {
760
764
  }
761
765
  })
762
766
  //插入col
763
- const colgroup = table.children!.find(item => {
767
+ const colgroup = tables[0].children!.find(item => {
764
768
  return item.parsedom == 'colgroup'
765
769
  })!
766
770
  const col = new AlexElement('closed', 'col', null, null, null)
@@ -772,11 +776,11 @@ const insertTableColumn = (type: string | undefined = 'left') => {
772
776
  //渲染
773
777
  editor.value.formatElementStack()
774
778
  if (type == 'left') {
775
- const previousColumn = editor.value.getPreviousElement(column)!
779
+ const previousColumn = editor.value.getPreviousElement(columns[0])!
776
780
  editor.value.range!.anchor.moveToStart(previousColumn)
777
781
  editor.value.range!.focus.moveToStart(previousColumn)
778
782
  } else {
779
- const nextColumn = editor.value.getNextElement(column)!
783
+ const nextColumn = editor.value.getNextElement(columns[0])!
780
784
  editor.value.range!.anchor.moveToStart(nextColumn)
781
785
  editor.value.range!.focus.moveToStart(nextColumn)
782
786
  }
@@ -790,19 +794,19 @@ const insertTableRow = (type: string | undefined = 'up') => {
790
794
  editor.value.range!.anchor.element = editor.value.range!.focus.element
791
795
  editor.value.range!.anchor.offset = editor.value.range!.focus.offset
792
796
  }
793
- const table = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'table')
794
- const row = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'tr')
795
- if (table && row) {
796
- const newRow = row.clone()
797
+ const tables = getMatchElementsByRange(editor.value, dataRangeCaches.value, { parsedom: 'table' })
798
+ const rows = getMatchElementsByRange(editor.value, dataRangeCaches.value, { parsedom: 'tr' })
799
+ if (tables.length == 1 && rows.length == 1) {
800
+ const newRow = rows[0].clone()
797
801
  newRow.children!.forEach(column => {
798
802
  column.children = []
799
803
  const breakEl = new AlexElement('closed', 'br', null, null, null)
800
804
  editor.value.addElementTo(breakEl, column)
801
805
  })
802
806
  if (type == 'up') {
803
- editor.value.addElementBefore(newRow, row)
807
+ editor.value.addElementBefore(newRow, rows[0])
804
808
  } else {
805
- editor.value.addElementAfter(newRow, row)
809
+ editor.value.addElementAfter(newRow, rows[0])
806
810
  }
807
811
  editor.value.formatElementStack()
808
812
  editor.value.range!.anchor.moveToStart(newRow)
@@ -817,15 +821,15 @@ const insertTableRow = (type: string | undefined = 'up') => {
817
821
  }
818
822
  //表格前后插入段落
819
823
  const insertParagraphWithTable = (type: string | undefined = 'up') => {
820
- const table = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'table')
821
- if (table) {
824
+ const tables = getMatchElementsByRange(editor.value, dataRangeCaches.value, { parsedom: 'table' })
825
+ if (tables.length == 1) {
822
826
  const paragraph = new AlexElement('block', AlexElement.BLOCK_NODE, null, null, null)
823
827
  const breakEl = new AlexElement('closed', 'br', null, null, null)
824
828
  editor.value.addElementTo(breakEl, paragraph)
825
829
  if (type == 'up') {
826
- editor.value.addElementBefore(paragraph, table)
830
+ editor.value.addElementBefore(paragraph, tables[0])
827
831
  } else {
828
- editor.value.addElementAfter(paragraph, table)
832
+ editor.value.addElementAfter(paragraph, tables[0])
829
833
  }
830
834
  editor.value.range!.anchor.moveToEnd(paragraph)
831
835
  editor.value.range!.focus.moveToEnd(paragraph)
@@ -836,9 +840,9 @@ const insertParagraphWithTable = (type: string | undefined = 'up') => {
836
840
  }
837
841
  //删除元素
838
842
  const deleteElement = (parsedom: string) => {
839
- const element = getCurrentParsedomElement(editor.value, dataRangeCaches.value, parsedom)
840
- if (element) {
841
- element.toEmpty()
843
+ const elements = getMatchElementsByRange(editor.value, dataRangeCaches.value, { parsedom })
844
+ if (elements.length == 1) {
845
+ elements[0].toEmpty()
842
846
  editor.value.formatElementStack()
843
847
  editor.value.domRender()
844
848
  editor.value.rangeRender()
@@ -850,17 +854,17 @@ const deleteTableRow = () => {
850
854
  editor.value.range!.anchor.element = editor.value.range!.focus.element
851
855
  editor.value.range!.anchor.offset = editor.value.range!.focus.offset
852
856
  }
853
- const table = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'table')
854
- const row = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'tr')
855
- if (table && row) {
856
- const parent = row.parent!
857
+ const tables = getMatchElementsByRange(editor.value, dataRangeCaches.value, { parsedom: 'table' })
858
+ const rows = getMatchElementsByRange(editor.value, dataRangeCaches.value, { parsedom: 'tr' })
859
+ if (tables.length == 1 && rows.length == 1) {
860
+ const parent = rows[0].parent!
857
861
  if (parent.children!.length == 1) {
858
862
  deleteElement('table')
859
863
  return
860
864
  }
861
- const previousRow = editor.value.getPreviousElement(row)!
862
- const nextRow = editor.value.getNextElement(row)!
863
- row.toEmpty()
865
+ const previousRow = editor.value.getPreviousElement(rows[0])!
866
+ const nextRow = editor.value.getNextElement(rows[0])!
867
+ rows[0].toEmpty()
864
868
  editor.value.formatElementStack()
865
869
  if (previousRow) {
866
870
  editor.value.range!.anchor.moveToEnd(previousRow.children![0])
@@ -883,27 +887,27 @@ const deleteTableColumn = () => {
883
887
  editor.value.range!.anchor.element = editor.value.range!.focus.element
884
888
  editor.value.range!.anchor.offset = editor.value.range!.focus.offset
885
889
  }
886
- const column = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'td')
887
- const tbody = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'tbody')
888
- const table = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'table')
889
- if (column && table && tbody) {
890
- const rows = tbody.children!
891
- const parent = column.parent!
890
+ const columns = getMatchElementsByRange(editor.value, dataRangeCaches.value, { parsedom: 'td' })
891
+ const tbodys = getMatchElementsByRange(editor.value, dataRangeCaches.value, { parsedom: 'tbody' })
892
+ const tables = getMatchElementsByRange(editor.value, dataRangeCaches.value, { parsedom: 'table' })
893
+ if (tables.length == 1 && tbodys.length == 1 && columns.length == 1) {
894
+ const rows = tbodys[0].children!
895
+ const parent = columns[0].parent!
892
896
  if (parent.children!.length == 1) {
893
897
  deleteElement('table')
894
898
  return
895
899
  }
896
- const previousColumn = editor.value.getPreviousElement(column)!
897
- const nextColumn = editor.value.getNextElement(column)!
898
- const index = column.parent!.children!.findIndex(item => {
899
- return item.isEqual(column)
900
+ const previousColumn = editor.value.getPreviousElement(columns[0])!
901
+ const nextColumn = editor.value.getNextElement(columns[0])!
902
+ const index = columns[0].parent!.children!.findIndex(item => {
903
+ return item.isEqual(columns[0])
900
904
  })
901
905
  //删除列
902
906
  rows.forEach(row => {
903
907
  row.children![index].toEmpty()
904
908
  })
905
909
  //删除col
906
- const colgroup = table.children!.find(item => {
910
+ const colgroup = tables[0].children!.find(item => {
907
911
  return item.parsedom == 'colgroup'
908
912
  })!
909
913
  colgroup.children![index].toEmpty()
@@ -922,29 +926,31 @@ const deleteTableColumn = () => {
922
926
  }
923
927
  //浮层显示时
924
928
  const layerShow = () => {
925
- //代码块初始化展示设置
926
- if (props.type == 'codeBlock') {
927
- const pre = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'pre')
928
- if (pre) {
929
- languageConfig.value.displayConfig.value = pre.marks!['data-editify-hljs'] || ''
930
- }
931
- }
932
929
  //链接初始化展示
933
- else if (props.type == 'link') {
934
- const link = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'a')
935
- if (link) {
936
- linkConfig.value.url = link.marks!['href']
937
- linkConfig.value.newOpen = link.marks!['target'] == '_blank'
930
+ if (props.type == 'link') {
931
+ const links = getMatchElementsByRange(editor.value, dataRangeCaches.value, { parsedom: 'a' })
932
+ if (links.length == 1) {
933
+ linkConfig.value.url = links[0].marks!['href']
934
+ linkConfig.value.newOpen = links[0].marks!['target'] == '_blank'
938
935
  }
939
936
  }
940
937
  //视频初始化显示
941
938
  else if (props.type == 'video') {
942
- const video = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'video')
943
- if (video) {
944
- videoConfig.value.autoplay = !!video.marks!['autoplay']
945
- videoConfig.value.loop = !!video.marks!['loop']
946
- videoConfig.value.controls = !!video.marks!['controls']
947
- videoConfig.value.muted = !!video.marks!['muted']
939
+ const videos = getMatchElementsByRange(editor.value, dataRangeCaches.value, { parsedom: 'video' })
940
+ if (videos.length == 1) {
941
+ videoConfig.value.autoplay = !!videos[0].marks!['autoplay']
942
+ videoConfig.value.loop = !!videos[0].marks!['loop']
943
+ videoConfig.value.controls = !!videos[0].marks!['controls']
944
+ videoConfig.value.muted = !!videos[0].marks!['muted']
945
+ }
946
+ }
947
+ //代码块初始化展示设置
948
+ else if (props.type == 'codeBlock') {
949
+ const pres = getMatchElementsByRange(editor.value, dataRangeCaches.value, {
950
+ parsedom: 'pre'
951
+ })
952
+ if (pres.length == 1) {
953
+ languageConfig.value.displayConfig.value = pres[0].marks!['data-editify-hljs'] || ''
948
954
  }
949
955
  }
950
956
  //文本工具条初始化显示
@@ -6,63 +6,94 @@ import { common as DapCommon } from 'dap-util'
6
6
  import { cloneData, queryHasValue, getButtonOptionsConfig, ObjectType } from './tool'
7
7
  import { ButtonOptionsItemType } from '../components/button/props'
8
8
 
9
+ export type ElementMatchConfig = {
10
+ parsedom?: string
11
+ marks?: ObjectType
12
+ styles?: ObjectType
13
+ }
14
+
9
15
  /**
10
- * 判断元素是否在某个标签下,如果是返回该标签对应的元素,否则返回null
16
+ * 判断元素是否符合指定的条件
11
17
  * @param element
12
- * @param parsedom
18
+ * @param config
13
19
  * @returns
14
20
  */
15
- export const getParsedomElementByElement = (element: AlexElement, parsedom: string): AlexElement | null => {
21
+ export const elementIsMatch = (element: AlexElement, config: ElementMatchConfig) => {
22
+ //如果是文本元素直接返回false
23
+ if (element.isText()) {
24
+ return false
25
+ }
26
+ //默认是符合的
27
+ let isMatch = true
28
+ //如果存在parsedom判断并且parsedom不一样
29
+ if (config.parsedom && config.parsedom != element.parsedom) {
30
+ isMatch = false
31
+ }
32
+ //如果存在marks判断
33
+ if (config.marks) {
34
+ const hasMarks = Object.keys(config.marks).every(key => {
35
+ return element.hasMarks() && element.marks![key] && element.marks![key] == config.marks![key]
36
+ })
37
+ //如果不是所有的mark都有
38
+ if (!hasMarks) {
39
+ isMatch = false
40
+ }
41
+ }
42
+ //如果存在styles判断
43
+ if (config.styles) {
44
+ const hasStyles = Object.keys(config.styles).every(key => {
45
+ return element.hasStyles() && element.styles![key] && element.styles![key] == config.styles![key]
46
+ })
47
+ //如果不是所有的styles都有
48
+ if (!hasStyles) {
49
+ isMatch = false
50
+ }
51
+ }
52
+ return isMatch
53
+ }
54
+
55
+ /**
56
+ * 判断元素是否在符合条件的元素下,如果是返回符合条件的元素,否则返回null
57
+ * @param element
58
+ * @param config
59
+ * @returns
60
+ */
61
+ export const getMatchElementByElement = (element: AlexElement, config: ElementMatchConfig): AlexElement | null => {
16
62
  if (element.isBlock()) {
17
- return element.parsedom == parsedom ? element : null
63
+ return elementIsMatch(element, config) ? element : null
18
64
  }
19
- if (!element.isText() && element.parsedom == parsedom) {
65
+ if (elementIsMatch(element, config)) {
20
66
  return element
21
67
  }
22
- return getParsedomElementByElement(element.parent!, parsedom)
68
+ return getMatchElementByElement(element.parent!, config)
23
69
  }
24
70
 
25
71
  /**
26
- * 获取光标是否在指定标签下,如果是返回该标签对应的元素,否则返回null
72
+ * 判断光标范围内的元素是否在符合条件的元素下,如果是所有的返回符合条件的元素,否则返回[]
27
73
  * @param editor
28
74
  * @param dataRangeCaches
29
- * @param parsedom
75
+ * @param config
30
76
  * @returns
31
77
  */
32
- export const getCurrentParsedomElement = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, parsedom: string) => {
78
+ export const getMatchElementsByRange = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, config: ElementMatchConfig) => {
79
+ let elements: AlexElement[] = []
33
80
  if (!editor.range) {
34
- return null
81
+ return elements
35
82
  }
36
83
  if (editor.range.anchor.element.isEqual(editor.range.focus.element)) {
37
- return getParsedomElementByElement(editor.range.anchor.element, parsedom)
38
- }
39
- const arr = dataRangeCaches.list.map(item => {
40
- return getParsedomElementByElement(item.element, parsedom)
41
- })
42
- let hasNull = arr.some(el => {
43
- return el == null
44
- })
45
- //如果存在null,则表示有的选区元素不在指定标签下,返回null
46
- if (hasNull) {
47
- return null
48
- }
49
- //如果只有一个元素,则返回该元素
50
- if (arr.length == 1) {
51
- return arr[0]!
52
- }
53
- //默认数组中的元素都相等
54
- let flag = true
55
- for (let i = 1; i < arr.length; i++) {
56
- if (!arr[i]!.isEqual(arr[0]!)) {
57
- flag = false
58
- break
84
+ const element = getMatchElementByElement(editor.range.anchor.element, config)
85
+ if (element) {
86
+ elements = [element]
59
87
  }
88
+ return elements
60
89
  }
61
- //如果相等,则返回该元素
62
- if (flag) {
63
- return arr[0]
64
- }
65
- return null
90
+ dataRangeCaches.flatList.forEach(item => {
91
+ const element = getMatchElementByElement(item.element, config)
92
+ if (element && !elements.some(el => el.isEqual(element))) {
93
+ elements.push(element)
94
+ }
95
+ })
96
+ return elements
66
97
  }
67
98
 
68
99
  /**
@@ -132,10 +163,10 @@ export const hasPreInRange = (editor: AlexEditor, dataRangeCaches: AlexElementsR
132
163
  return false
133
164
  }
134
165
  if (editor.range.anchor.isEqual(editor.range.focus)) {
135
- return !!getParsedomElementByElement(editor.range.anchor.element, 'pre')
166
+ return !!getMatchElementByElement(editor.range.anchor.element, { parsedom: 'pre' })
136
167
  }
137
168
  return dataRangeCaches.flatList.some(item => {
138
- return !!getParsedomElementByElement(item.element, 'pre')
169
+ return !!getMatchElementByElement(item.element, { parsedom: 'pre' })
139
170
  })
140
171
  }
141
172
 
@@ -150,10 +181,10 @@ export const isRangeInPre = (editor: AlexEditor, dataRangeCaches: AlexElementsRa
150
181
  return false
151
182
  }
152
183
  if (editor.range.anchor.isEqual(editor.range.focus)) {
153
- return !!getParsedomElementByElement(editor.range.anchor.element, 'pre')
184
+ return !!getMatchElementByElement(editor.range.anchor.element, { parsedom: 'pre' })
154
185
  }
155
186
  return dataRangeCaches.list.every(item => {
156
- return !!getParsedomElementByElement(item.element, 'pre')
187
+ return !!getMatchElementByElement(item.element, { parsedom: 'pre' })
157
188
  })
158
189
  }
159
190
 
@@ -168,10 +199,10 @@ export const hasQuoteInRange = (editor: AlexEditor, dataRangeCaches: AlexElement
168
199
  return false
169
200
  }
170
201
  if (editor.range.anchor.isEqual(editor.range.focus)) {
171
- return !!getParsedomElementByElement(editor.range.anchor.element, 'blockquote')
202
+ return !!getMatchElementByElement(editor.range.anchor.element, { parsedom: 'blockquote' })
172
203
  }
173
204
  return dataRangeCaches.flatList.some(item => {
174
- return !!getParsedomElementByElement(item.element, 'blockquote')
205
+ return !!getMatchElementByElement(item.element, { parsedom: 'blockquote' })
175
206
  })
176
207
  }
177
208
 
@@ -186,10 +217,10 @@ export const isRangeInQuote = (editor: AlexEditor, dataRangeCaches: AlexElements
186
217
  return false
187
218
  }
188
219
  if (editor.range.anchor.isEqual(editor.range.focus)) {
189
- return !!getParsedomElementByElement(editor.range.anchor.element, 'blockquote')
220
+ return !!getMatchElementByElement(editor.range.anchor.element, { parsedom: 'blockquote' })
190
221
  }
191
222
  return dataRangeCaches.list.every(item => {
192
- return !!getParsedomElementByElement(item.element, 'blockquote')
223
+ return !!getMatchElementByElement(item.element, { parsedom: 'blockquote' })
193
224
  })
194
225
  }
195
226
 
@@ -278,10 +309,10 @@ export const hasLinkInRange = (editor: AlexEditor, dataRangeCaches: AlexElements
278
309
  return false
279
310
  }
280
311
  if (editor.range.anchor.isEqual(editor.range.focus)) {
281
- return !!getParsedomElementByElement(editor.range.anchor.element, 'a')
312
+ return !!getMatchElementByElement(editor.range.anchor.element, { parsedom: 'a' })
282
313
  }
283
314
  return dataRangeCaches.flatList.some(item => {
284
- return !!getParsedomElementByElement(item.element, 'a')
315
+ return !!getMatchElementByElement(item.element, { parsedom: 'a' })
285
316
  })
286
317
  }
287
318
 
@@ -296,10 +327,10 @@ export const hasTableInRange = (editor: AlexEditor, dataRangeCaches: AlexElement
296
327
  return false
297
328
  }
298
329
  if (editor.range.anchor.isEqual(editor.range.focus)) {
299
- return !!getParsedomElementByElement(editor.range.anchor.element, 'table')
330
+ return !!getMatchElementByElement(editor.range.anchor.element, { parsedom: 'table' })
300
331
  }
301
332
  return dataRangeCaches.flatList.some(item => {
302
- return !!getParsedomElementByElement(item.element, 'table')
333
+ return !!getMatchElementByElement(item.element, { parsedom: 'table' })
303
334
  })
304
335
  }
305
336
 
@@ -314,10 +345,10 @@ export const hasImageInRange = (editor: AlexEditor, dataRangeCaches: AlexElement
314
345
  return false
315
346
  }
316
347
  if (editor.range.anchor.isEqual(editor.range.focus)) {
317
- return !!getParsedomElementByElement(editor.range.anchor.element, 'img')
348
+ return !!getMatchElementByElement(editor.range.anchor.element, { parsedom: 'img' })
318
349
  }
319
350
  return dataRangeCaches.flatList.some(item => {
320
- return !!getParsedomElementByElement(item.element, 'img')
351
+ return !!getMatchElementByElement(item.element, { parsedom: 'img' })
321
352
  })
322
353
  }
323
354
 
@@ -332,10 +363,10 @@ export const hasVideoInRange = (editor: AlexEditor, dataRangeCaches: AlexElement
332
363
  return false
333
364
  }
334
365
  if (editor.range.anchor.isEqual(editor.range.focus)) {
335
- return !!getParsedomElementByElement(editor.range.anchor.element, 'video')
366
+ return !!getMatchElementByElement(editor.range.anchor.element, { parsedom: 'video' })
336
367
  }
337
368
  return dataRangeCaches.flatList.some(item => {
338
- return !!getParsedomElementByElement(item.element, 'video')
369
+ return !!getMatchElementByElement(item.element, { parsedom: 'video' })
339
370
  })
340
371
  }
341
372
 
@@ -1298,10 +1329,10 @@ export const insertCodeBlock = (editor: AlexEditor, dataRangeCaches: AlexElement
1298
1329
  if (!editor.range) {
1299
1330
  return
1300
1331
  }
1301
- const pre = getCurrentParsedomElement(editor, dataRangeCaches, 'pre')
1302
- if (pre) {
1332
+ const pres = getMatchElementsByRange(editor, dataRangeCaches, { parsedom: 'pre' })
1333
+ if (pres.length == 1) {
1303
1334
  let content = ''
1304
- AlexElement.flatElements(pre.children!)
1335
+ AlexElement.flatElements(pres[0].children!)
1305
1336
  .filter(item => {
1306
1337
  return item.isText()
1307
1338
  })
@@ -1313,9 +1344,9 @@ export const insertCodeBlock = (editor: AlexEditor, dataRangeCaches: AlexElement
1313
1344
  const paragraph = new AlexElement('block', AlexElement.BLOCK_NODE, null, null, null)
1314
1345
  const text = new AlexElement('text', null, null, null, item)
1315
1346
  editor.addElementTo(text, paragraph)
1316
- editor.addElementBefore(paragraph, pre)
1347
+ editor.addElementBefore(paragraph, pres[0])
1317
1348
  })
1318
- pre.toEmpty()
1349
+ pres[0].toEmpty()
1319
1350
  } else {
1320
1351
  //起点和终点在一起
1321
1352
  if (editor.range.anchor.isEqual(editor.range.focus)) {