vue-editify 0.1.39 → 0.1.41

Sign up to get free protection for your applications and to get access to all the features.
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)) {