@haluo/biz 2.0.38 → 2.0.39

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.
@@ -316,7 +316,7 @@
316
316
  }
317
317
  return target;
318
318
  };
319
- const _sfc_main$7 = {
319
+ const _sfc_main$8 = {
320
320
  components: {
321
321
  ElTooltip: elementPlus.ElTooltip,
322
322
  ElDivider: elementPlus.ElDivider,
@@ -518,7 +518,7 @@
518
518
  }
519
519
  }
520
520
  };
521
- const _hoisted_1$7 = {
521
+ const _hoisted_1$8 = {
522
522
  key: 0,
523
523
  class: "tools"
524
524
  };
@@ -584,13 +584,13 @@
584
584
  const _hoisted_43 = ["src"];
585
585
  const _hoisted_44 = ["src"];
586
586
  const _hoisted_45 = ["src"];
587
- function _sfc_render$3(_ctx, _cache, $props, $setup, $data, $options) {
587
+ function _sfc_render$4(_ctx, _cache, $props, $setup, $data, $options) {
588
588
  const _component_el_tooltip = vue.resolveComponent("el-tooltip");
589
589
  const _component_el_divider = vue.resolveComponent("el-divider");
590
590
  const _component_el_popover = vue.resolveComponent("el-popover");
591
591
  const _component_colorPicker = vue.resolveComponent("colorPicker");
592
592
  const _directive_click_outside = vue.resolveDirective("click-outside");
593
- return $props.editor.fontInfo ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$7, [
593
+ return $props.editor.fontInfo ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$8, [
594
594
  vue.createElementVNode("div", _hoisted_2$5, [
595
595
  vue.createVNode(_component_el_tooltip, {
596
596
  class: "item",
@@ -1104,15 +1104,15 @@
1104
1104
  ])
1105
1105
  ])) : vue.createCommentVNode("", true);
1106
1106
  }
1107
- const ToolBar = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["render", _sfc_render$3], ["__scopeId", "data-v-50235bb8"]]);
1107
+ const ToolBar = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["render", _sfc_render$4], ["__scopeId", "data-v-50235bb8"]]);
1108
1108
  const __vite_glob_0_0 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAmCAYAAAClI5npAAAA0UlEQVR42uWYwQnDMAxFfckAXkFDmGzgS1foDpnFS3gTb+IFtIDyA4UeBKUtNR8qwTvlkAdyfmSletySmRUwgIIJOijXs9VcLxegwNVDRFYLdHtdCg6wrRKY9l4NUFYIqH1WDeTfCXxXE9w5Ar4tQhBwh7SBjSDg2lJJAj47SAI+OwgC7pDuJAGfHQQBnx0kAZ8dBAF3SOtTgCchybjV2QLKFpihW6BAQn6GA0i4KG4g037H4QaSDiTWUMocyweQcFezBjLrer5TFxR/uaKhL6lOdeUQ8G6X1pQAAAAASUVORK5CYII=";
1109
- const _hoisted_1$6 = { key: 0 };
1109
+ const _hoisted_1$7 = { key: 0 };
1110
1110
  const _hoisted_2$4 = { class: "basic-dialog_title" };
1111
1111
  const _hoisted_3$4 = {
1112
1112
  key: 0,
1113
1113
  class: "dialog-footer"
1114
1114
  };
1115
- const _sfc_main$6 = /* @__PURE__ */ vue.defineComponent({
1115
+ const _sfc_main$7 = /* @__PURE__ */ vue.defineComponent({
1116
1116
  __name: "index",
1117
1117
  props: {
1118
1118
  visible: { type: Boolean, default: false },
@@ -1153,7 +1153,7 @@
1153
1153
  class: vue.normalizeClass(["basic-dialog", { "hide-title": !_ctx.showTitle }])
1154
1154
  }, {
1155
1155
  header: vue.withCtx(() => [
1156
- _ctx.showTitle ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$6, [
1156
+ _ctx.showTitle ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$7, [
1157
1157
  vue.createElementVNode("div", _hoisted_2$4, [
1158
1158
  _cache[1] || (_cache[1] = vue.createElementVNode("span", { class: "basic-dialog_divider" }, null, -1)),
1159
1159
  vue.renderSlot(_ctx.$slots, "title")
@@ -1194,7 +1194,7 @@
1194
1194
  };
1195
1195
  }
1196
1196
  });
1197
- const index_vue_vue_type_style_index_0_lang$4 = "";
1197
+ const index_vue_vue_type_style_index_0_lang$5 = "";
1198
1198
  var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
1199
1199
  function getDefaultExportFromCjs(x) {
1200
1200
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
@@ -3484,7 +3484,7 @@
3484
3484
  tools$2.exports = new ToolsClass();
3485
3485
  var toolsExports = tools$2.exports;
3486
3486
  const tools$1 = /* @__PURE__ */ getDefaultExportFromCjs(toolsExports);
3487
- const _hoisted_1$5 = { style: { "margin-left": "20px", "color": "#FF5A25" } };
3487
+ const _hoisted_1$6 = { style: { "margin-left": "20px", "color": "#FF5A25" } };
3488
3488
  const _hoisted_2$3 = { class: "insert-article" };
3489
3489
  const _hoisted_3$3 = { class: "insert-article_input" };
3490
3490
  const _hoisted_4$2 = {
@@ -3505,7 +3505,7 @@
3505
3505
  key: 1,
3506
3506
  style: { "display": "inline-flex", "flex-direction": "column" }
3507
3507
  };
3508
- const _sfc_main$5 = /* @__PURE__ */ vue.defineComponent({
3508
+ const _sfc_main$6 = /* @__PURE__ */ vue.defineComponent({
3509
3509
  __name: "index",
3510
3510
  props: {
3511
3511
  visible: { type: Boolean, default: false },
@@ -3581,6 +3581,8 @@
3581
3581
  data.busy = true;
3582
3582
  const userInfo = JSON.parse(localStorage.getItem("user")) || JSON.parse(localStorage.getItem("userInfo"));
3583
3583
  const userId = userInfo.uid || userInfo.userid;
3584
+ if (!getList.value)
3585
+ return;
3584
3586
  const res = await getList.value({
3585
3587
  uid: data.params.radio !== Radio_Type.ALL_ARITICLE ? userId : "",
3586
3588
  autherid: data.params.radio !== Radio_Type.ALL_ARITICLE ? userId : "",
@@ -3600,14 +3602,14 @@
3600
3602
  data.busy = false;
3601
3603
  }, 1e3);
3602
3604
  return (_ctx, _cache) => {
3603
- return vue.openBlock(), vue.createBlock(_sfc_main$6, {
3605
+ return vue.openBlock(), vue.createBlock(_sfc_main$7, {
3604
3606
  visible: vue.unref(visible),
3605
3607
  onSubmit: confirm
3606
3608
  }, {
3607
3609
  title: vue.withCtx(() => [
3608
3610
  vue.createElementVNode("span", null, [
3609
3611
  _cache[8] || (_cache[8] = vue.createTextVNode("插入文章/视频")),
3610
- vue.createElementVNode("strong", _hoisted_1$5, "平台仅支持插入" + vue.toDisplayString(`${isVideo.value ? "2年" : "18个月"}`) + "内的推荐内容", 1)
3612
+ vue.createElementVNode("strong", _hoisted_1$6, "平台仅支持插入" + vue.toDisplayString(`${isVideo.value ? "2年" : "18个月"}`) + "内的推荐内容", 1)
3611
3613
  ])
3612
3614
  ]),
3613
3615
  default: vue.withCtx(() => [
@@ -3717,7 +3719,7 @@
3717
3719
  };
3718
3720
  }
3719
3721
  });
3720
- const index_vue_vue_type_style_index_0_lang$3 = "";
3722
+ const index_vue_vue_type_style_index_0_lang$4 = "";
3721
3723
  let getRandomValues;
3722
3724
  const rnds8 = new Uint8Array(16);
3723
3725
  function rng() {
@@ -3757,7 +3759,7 @@
3757
3759
  }
3758
3760
  return unsafeStringify(rnds);
3759
3761
  }
3760
- const _hoisted_1$4 = { class: "img-upload-content" };
3762
+ const _hoisted_1$5 = { class: "img-upload-content" };
3761
3763
  const _hoisted_2$2 = { class: "title-box" };
3762
3764
  const _hoisted_3$2 = ["onClick"];
3763
3765
  const _hoisted_4$1 = {
@@ -3819,7 +3821,7 @@
3819
3821
  class: "protocol-box"
3820
3822
  };
3821
3823
  const _hoisted_29 = ["href"];
3822
- const _sfc_main$4 = /* @__PURE__ */ vue.defineComponent({
3824
+ const _sfc_main$5 = /* @__PURE__ */ vue.defineComponent({
3823
3825
  __name: "index",
3824
3826
  props: {
3825
3827
  visible: { type: Boolean, default: false },
@@ -4101,12 +4103,12 @@
4101
4103
  emits("update:imgList", list);
4102
4104
  };
4103
4105
  return (_ctx, _cache) => {
4104
- return vue.openBlock(), vue.createBlock(_sfc_main$6, {
4106
+ return vue.openBlock(), vue.createBlock(_sfc_main$7, {
4105
4107
  visible: props.visible,
4106
4108
  showTitle: false
4107
4109
  }, {
4108
4110
  default: vue.withCtx(() => [
4109
- vue.createElementVNode("div", _hoisted_1$4, [
4111
+ vue.createElementVNode("div", _hoisted_1$5, [
4110
4112
  vue.createElementVNode("div", _hoisted_2$2, [
4111
4113
  (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(titleList.value, (item, index) => {
4112
4114
  return vue.openBlock(), vue.createElementBlock("div", {
@@ -4346,9 +4348,9 @@
4346
4348
  };
4347
4349
  }
4348
4350
  });
4349
- const index_vue_vue_type_style_index_0_lang$2 = "";
4350
- const _hoisted_1$3 = { class: "insert-video" };
4351
- const _sfc_main$3 = /* @__PURE__ */ vue.defineComponent({
4351
+ const index_vue_vue_type_style_index_0_lang$3 = "";
4352
+ const _hoisted_1$4 = { class: "insert-video" };
4353
+ const _sfc_main$4 = /* @__PURE__ */ vue.defineComponent({
4352
4354
  __name: "index",
4353
4355
  props: {
4354
4356
  visible: { type: Boolean, default: false },
@@ -4370,7 +4372,7 @@
4370
4372
  ele[0].dispatchEvent(event);
4371
4373
  };
4372
4374
  return (_ctx, _cache) => {
4373
- return vue.openBlock(), vue.createBlock(_sfc_main$6, {
4375
+ return vue.openBlock(), vue.createBlock(_sfc_main$7, {
4374
4376
  "show-btn": false,
4375
4377
  visible: vue.unref(visible),
4376
4378
  width: "600px",
@@ -4380,7 +4382,7 @@
4380
4382
  vue.createElementVNode("span", null, "插入视频", -1)
4381
4383
  ])),
4382
4384
  default: vue.withCtx(() => [
4383
- vue.createElementVNode("div", _hoisted_1$3, [
4385
+ vue.createElementVNode("div", _hoisted_1$4, [
4384
4386
  vue.createVNode(vue.unref(elementPlus.ElButton), {
4385
4387
  style: { "width": "120px" },
4386
4388
  round: "",
@@ -4407,7 +4409,703 @@
4407
4409
  };
4408
4410
  }
4409
4411
  });
4412
+ const index_vue_vue_type_style_index_0_lang$2 = "";
4410
4413
  const index_vue_vue_type_style_index_0_lang$1 = "";
4414
+ const _sfc_main$3 = {
4415
+ name: "TopicManager",
4416
+ props: {
4417
+ // 编辑器DOM引用
4418
+ editorDom: {
4419
+ type: Object,
4420
+ default: null
4421
+ },
4422
+ // 话题API请求方法
4423
+ request: {
4424
+ type: Object,
4425
+ default: null
4426
+ }
4427
+ },
4428
+ data() {
4429
+ return {
4430
+ // 话题弹框相关数据
4431
+ topicPopover: {
4432
+ visible: false,
4433
+ type: "hot",
4434
+ // 'hot' 热门话题, 'search' 搜索话题
4435
+ activeTab: "hot",
4436
+ // 'hot' 热门话题, 'recent' 最近使用
4437
+ position: { top: 0, left: 0 },
4438
+ searchKeyword: "",
4439
+ hotTopics: [],
4440
+ searchTopics: [],
4441
+ recentTopics: [],
4442
+ loading: false,
4443
+ page: 1,
4444
+ hasMore: true,
4445
+ searchPage: 1,
4446
+ searchHasMore: true,
4447
+ // 保存原始的selection和range信息
4448
+ originalRange: null,
4449
+ originalSelection: null,
4450
+ // 保存触发位置信息
4451
+ triggerInfo: {
4452
+ paragraph: null,
4453
+ hashIndex: -1,
4454
+ cursorPosition: 0
4455
+ },
4456
+ // 全局弹框DOM引用
4457
+ globalContainer: null,
4458
+ globalMask: null
4459
+ }
4460
+ };
4461
+ },
4462
+ methods: {
4463
+ // 初始化话题管理器
4464
+ init() {
4465
+ if (!this.editorDom) {
4466
+ console.warn("TopicManager: editorDom is required");
4467
+ return;
4468
+ }
4469
+ setTimeout(() => this.bindEditorEvents(), 0);
4470
+ },
4471
+ // 绑定编辑器事件
4472
+ bindEditorEvents() {
4473
+ if (!this.editorDom)
4474
+ return;
4475
+ this.editorDom.addEventListener("keydown", this.handleTopicInput.bind(this));
4476
+ },
4477
+ // 解绑编辑器事件
4478
+ unbindEditorEvents() {
4479
+ if (!this.editorDom)
4480
+ return;
4481
+ this.editorDom.removeEventListener("keydown", this.handleTopicInput.bind(this));
4482
+ },
4483
+ // 话题输入处理
4484
+ handleTopicInput(event) {
4485
+ var _a;
4486
+ const activeElement = document.activeElement;
4487
+ if (activeElement && (activeElement.tagName === "INPUT" || activeElement.tagName === "TEXTAREA")) {
4488
+ return;
4489
+ }
4490
+ const selection = window.getSelection();
4491
+ if (selection.rangeCount === 0)
4492
+ return;
4493
+ const range = selection.getRangeAt(0);
4494
+ const container = range.startContainer;
4495
+ if (!this.editorDom.contains(container))
4496
+ return;
4497
+ let currentNode = container;
4498
+ while (currentNode && currentNode !== this.editorDom) {
4499
+ if (currentNode.nodeType === Node.ELEMENT_NODE && currentNode.tagName === "MDD-TOPIC") {
4500
+ return;
4501
+ }
4502
+ currentNode = currentNode.parentNode;
4503
+ }
4504
+ let paragraph = container;
4505
+ while (paragraph && paragraph.nodeType !== Node.ELEMENT_NODE) {
4506
+ paragraph = paragraph.parentNode;
4507
+ }
4508
+ while (paragraph && !((_a = paragraph.classList) == null ? void 0 : _a.contains("halo-paragraph"))) {
4509
+ paragraph = paragraph.parentNode;
4510
+ }
4511
+ if (!paragraph)
4512
+ return;
4513
+ const { textContent: paragraphText, cursorPosition } = this.getParagraphTextExcludingTopics(paragraph, range);
4514
+ if (event.key === "#") {
4515
+ const afterCursor = paragraphText.substring(cursorPosition);
4516
+ if (afterCursor.length > 0 && (afterCursor[0] === "@" || afterCursor[0] === " ")) {
4517
+ return;
4518
+ }
4519
+ setTimeout(() => {
4520
+ const position = this.getCaretPosition();
4521
+ const triggerInfo = {
4522
+ paragraph,
4523
+ hashIndex: cursorPosition,
4524
+ // #号的位置
4525
+ cursorPosition: cursorPosition + 1
4526
+ // #号后的位置
4527
+ };
4528
+ this.showTopicPopover("hot", position, "", triggerInfo);
4529
+ }, 10);
4530
+ } else if (this.shouldTriggerSearch(event.key)) {
4531
+ setTimeout(() => {
4532
+ this.checkAndTriggerSearch(paragraph);
4533
+ }, 10);
4534
+ }
4535
+ },
4536
+ shouldTriggerSearch(key) {
4537
+ return key.length === 1 || key === "Backspace" || key === "Delete";
4538
+ },
4539
+ checkAndTriggerSearch(paragraph) {
4540
+ const selection = window.getSelection();
4541
+ if (selection.rangeCount === 0)
4542
+ return;
4543
+ const range = selection.getRangeAt(0);
4544
+ let currentNode = range.startContainer;
4545
+ while (currentNode && currentNode !== paragraph) {
4546
+ if (currentNode.nodeType === Node.ELEMENT_NODE && currentNode.tagName === "MDD-TOPIC") {
4547
+ this.hideTopicPopover();
4548
+ return;
4549
+ }
4550
+ currentNode = currentNode.parentNode;
4551
+ }
4552
+ const { textContent: paragraphText, cursorPosition } = this.getParagraphTextExcludingTopics(paragraph, range);
4553
+ const beforeCursor = paragraphText.substring(0, cursorPosition);
4554
+ const hashIndex = beforeCursor.lastIndexOf("#");
4555
+ if (hashIndex !== -1) {
4556
+ const afterHash = beforeCursor.substring(hashIndex + 1);
4557
+ if (afterHash.indexOf(" ") === -1 && afterHash.indexOf("@") === -1) {
4558
+ if (afterHash.length <= 15) {
4559
+ const position = this.getCaretPosition();
4560
+ const triggerInfo = {
4561
+ paragraph,
4562
+ hashIndex,
4563
+ cursorPosition
4564
+ };
4565
+ if (afterHash.length === 0) {
4566
+ this.showTopicPopover("hot", position, "", triggerInfo);
4567
+ } else {
4568
+ this.showTopicPopover("search", position, afterHash, triggerInfo);
4569
+ }
4570
+ } else if (afterHash.length > 15) {
4571
+ this.hideTopicPopover();
4572
+ }
4573
+ } else {
4574
+ this.hideTopicPopover();
4575
+ }
4576
+ } else {
4577
+ this.hideTopicPopover();
4578
+ }
4579
+ },
4580
+ getParagraphTextExcludingTopics(paragraph, range) {
4581
+ let textContent = "";
4582
+ let cursorPosition = 0;
4583
+ let foundCursor = false;
4584
+ const walker = document.createTreeWalker(
4585
+ paragraph,
4586
+ NodeFilter.SHOW_ALL,
4587
+ {
4588
+ acceptNode: function(node2) {
4589
+ if (node2.nodeType === Node.ELEMENT_NODE && node2.tagName === "MDD-TOPIC") {
4590
+ return NodeFilter.FILTER_REJECT;
4591
+ }
4592
+ return NodeFilter.FILTER_ACCEPT;
4593
+ }
4594
+ },
4595
+ false
4596
+ );
4597
+ let node;
4598
+ while (node = walker.nextNode()) {
4599
+ if (node.nodeType === Node.TEXT_NODE) {
4600
+ const nodeText = node.textContent;
4601
+ if (!foundCursor && node === range.startContainer) {
4602
+ cursorPosition = textContent.length + range.startOffset;
4603
+ foundCursor = true;
4604
+ }
4605
+ textContent += nodeText;
4606
+ }
4607
+ }
4608
+ return { textContent, cursorPosition };
4609
+ },
4610
+ getCaretPosition() {
4611
+ const selection = window.getSelection();
4612
+ if (selection.rangeCount === 0)
4613
+ return { top: 0, left: 0 };
4614
+ const range = selection.getRangeAt(0);
4615
+ const rect = range.getBoundingClientRect();
4616
+ return {
4617
+ top: rect.bottom + window.scrollY,
4618
+ left: rect.left + window.scrollX
4619
+ };
4620
+ },
4621
+ // 话题弹框相关方法
4622
+ showTopicPopover(type, position, searchKeyword = "", triggerInfo = null) {
4623
+ if (!this.request || !this.request.getTopic) {
4624
+ console.warn("话题功能需要提供 request.getTopic 方法");
4625
+ return;
4626
+ }
4627
+ const selection = window.getSelection();
4628
+ if (selection.rangeCount > 0) {
4629
+ this.topicPopover.originalRange = selection.getRangeAt(0).cloneRange();
4630
+ this.topicPopover.originalSelection = selection;
4631
+ }
4632
+ if (triggerInfo) {
4633
+ this.topicPopover.triggerInfo = triggerInfo;
4634
+ }
4635
+ this.topicPopover.visible = true;
4636
+ this.topicPopover.type = type;
4637
+ this.topicPopover.position = position;
4638
+ this.topicPopover.searchKeyword = searchKeyword;
4639
+ if (type === "hot") {
4640
+ this.topicPopover.activeTab = "hot";
4641
+ this.loadHotTopics();
4642
+ this.loadRecentTopics();
4643
+ } else if (type === "search") {
4644
+ this.searchTopics(searchKeyword);
4645
+ }
4646
+ this.createGlobalTopicPopover();
4647
+ },
4648
+ hideTopicPopover() {
4649
+ this.topicPopover.visible = false;
4650
+ this.topicPopover.hotTopics = [];
4651
+ this.topicPopover.searchTopics = [];
4652
+ this.topicPopover.page = 1;
4653
+ this.topicPopover.searchPage = 1;
4654
+ this.topicPopover.hasMore = true;
4655
+ this.topicPopover.searchHasMore = true;
4656
+ this.topicPopover.originalRange = null;
4657
+ this.topicPopover.originalSelection = null;
4658
+ this.topicPopover.triggerInfo = {
4659
+ paragraph: null,
4660
+ hashIndex: -1,
4661
+ cursorPosition: 0
4662
+ };
4663
+ this.removeGlobalTopicPopover();
4664
+ },
4665
+ switchTopicTab(tab) {
4666
+ this.topicPopover.activeTab = tab;
4667
+ this.updateGlobalTopicPopover();
4668
+ },
4669
+ async loadHotTopics() {
4670
+ if (this.topicPopover.loading || !this.topicPopover.hasMore)
4671
+ return;
4672
+ this.topicPopover.loading = true;
4673
+ try {
4674
+ const response = await this.request.getTopic({
4675
+ action: "201023",
4676
+ page: this.topicPopover.page,
4677
+ limit: 50,
4678
+ hoopId: 0,
4679
+ type: 0,
4680
+ orderBy: "view"
4681
+ });
4682
+ if (response && response.data && response.data.code === 0) {
4683
+ const topics = response.data.data || [];
4684
+ if (topics.length === 0) {
4685
+ this.topicPopover.hasMore = false;
4686
+ } else {
4687
+ const existingIds = new Set(this.topicPopover.hotTopics.map((t) => t.id));
4688
+ const newTopics = topics.filter((t) => !existingIds.has(t.id));
4689
+ this.topicPopover.hotTopics = [...this.topicPopover.hotTopics, ...newTopics];
4690
+ this.topicPopover.page++;
4691
+ if (newTopics.length === 0) {
4692
+ this.topicPopover.hasMore = false;
4693
+ }
4694
+ }
4695
+ } else {
4696
+ console.warn("加载热门话题失败:", response);
4697
+ this.topicPopover.hasMore = false;
4698
+ }
4699
+ } catch (error) {
4700
+ console.error("加载热门话题失败:", error);
4701
+ this.topicPopover.hasMore = false;
4702
+ } finally {
4703
+ this.topicPopover.loading = false;
4704
+ this.updateGlobalTopicPopover();
4705
+ }
4706
+ },
4707
+ async searchTopics(keyword) {
4708
+ this.topicPopover.searchKeyword = keyword;
4709
+ this.topicPopover.searchTopics = [];
4710
+ this.topicPopover.searchPage = 1;
4711
+ this.topicPopover.searchHasMore = true;
4712
+ if (this.topicPopover.loading) {
4713
+ this.topicPopover.loading = false;
4714
+ }
4715
+ this.topicPopover.loading = true;
4716
+ try {
4717
+ const response = await this.request.getTopic({
4718
+ action: "201023",
4719
+ title: keyword,
4720
+ highlightTitle: "title",
4721
+ page: this.topicPopover.searchPage,
4722
+ limit: 50
4723
+ });
4724
+ if (response && response.data && response.data.code === 0) {
4725
+ const topics = response.data.data || [];
4726
+ this.topicPopover.searchTopics = topics;
4727
+ this.topicPopover.searchPage++;
4728
+ if (topics.length === 0) {
4729
+ this.topicPopover.searchHasMore = false;
4730
+ } else {
4731
+ this.topicPopover.searchHasMore = topics.length >= 50;
4732
+ }
4733
+ } else {
4734
+ console.warn("搜索话题失败:", response);
4735
+ this.topicPopover.searchHasMore = false;
4736
+ }
4737
+ } catch (error) {
4738
+ console.error("搜索话题失败:", error);
4739
+ this.topicPopover.searchHasMore = false;
4740
+ } finally {
4741
+ this.topicPopover.loading = false;
4742
+ this.updateGlobalTopicPopover();
4743
+ }
4744
+ },
4745
+ loadRecentTopics() {
4746
+ try {
4747
+ const localTopics = JSON.parse(localStorage.getItem("localTopic") || "[]");
4748
+ this.topicPopover.recentTopics = localTopics;
4749
+ } catch (error) {
4750
+ console.error("加载最近使用话题失败:", error);
4751
+ this.topicPopover.recentTopics = [];
4752
+ }
4753
+ },
4754
+ selectTopic(topic) {
4755
+ this.saveToRecentTopics(topic);
4756
+ this.insertTopicToEditor(topic);
4757
+ this.hideTopicPopover();
4758
+ this.$emit("topic-inserted", topic);
4759
+ },
4760
+ saveToRecentTopics(topic) {
4761
+ try {
4762
+ let recentTopics = JSON.parse(localStorage.getItem("localTopic") || "[]");
4763
+ recentTopics = recentTopics.filter((item) => item.id !== topic.id);
4764
+ recentTopics.unshift(topic);
4765
+ if (recentTopics.length > 20) {
4766
+ recentTopics = recentTopics.slice(0, 20);
4767
+ }
4768
+ localStorage.setItem("localTopic", JSON.stringify(recentTopics));
4769
+ } catch (error) {
4770
+ console.error("保存最近使用话题失败:", error);
4771
+ }
4772
+ },
4773
+ // 创建全局话题弹框
4774
+ createGlobalTopicPopover() {
4775
+ this.removeGlobalTopicPopover();
4776
+ const mask = document.createElement("div");
4777
+ mask.className = "topic-popover-mask";
4778
+ mask.addEventListener("click", () => {
4779
+ this.hideTopicPopover();
4780
+ });
4781
+ const container = document.createElement("div");
4782
+ container.className = "topic-popover";
4783
+ container.style.position = "fixed";
4784
+ container.style.top = this.topicPopover.position.top + "px";
4785
+ container.style.left = this.topicPopover.position.left + "px";
4786
+ container.style.zIndex = "9999";
4787
+ container.addEventListener("click", (e) => {
4788
+ e.stopPropagation();
4789
+ });
4790
+ container.innerHTML = this.createTopicPopoverContent();
4791
+ document.body.appendChild(mask);
4792
+ document.body.appendChild(container);
4793
+ this.topicPopover.globalMask = mask;
4794
+ this.topicPopover.globalContainer = container;
4795
+ this.bindTopicPopoverEvents();
4796
+ },
4797
+ // 移除全局话题弹框
4798
+ removeGlobalTopicPopover() {
4799
+ if (this.topicPopover.globalMask) {
4800
+ document.body.removeChild(this.topicPopover.globalMask);
4801
+ this.topicPopover.globalMask = null;
4802
+ }
4803
+ if (this.topicPopover.globalContainer) {
4804
+ document.body.removeChild(this.topicPopover.globalContainer);
4805
+ this.topicPopover.globalContainer = null;
4806
+ }
4807
+ },
4808
+ // 更新全局话题弹框内容
4809
+ updateGlobalTopicPopover() {
4810
+ if (!this.topicPopover.globalContainer)
4811
+ return;
4812
+ this.topicPopover.globalContainer.innerHTML = this.createTopicPopoverContent();
4813
+ this.bindTopicPopoverEvents();
4814
+ },
4815
+ // 创建话题弹框内容
4816
+ createTopicPopoverContent() {
4817
+ if (this.topicPopover.type === "hot") {
4818
+ return this.getHotTopicPopoverHTML();
4819
+ } else if (this.topicPopover.type === "search") {
4820
+ return this.getSearchTopicPopoverHTML();
4821
+ }
4822
+ return "";
4823
+ },
4824
+ // 获取热门话题弹框HTML
4825
+ getHotTopicPopoverHTML() {
4826
+ const activeTab = this.topicPopover.activeTab;
4827
+ const hotTopics = this.topicPopover.hotTopics;
4828
+ const recentTopics = this.topicPopover.recentTopics;
4829
+ const loading = this.topicPopover.loading;
4830
+ const hasMore = this.topicPopover.hasMore;
4831
+ let topicListHTML = "";
4832
+ if (activeTab === "hot") {
4833
+ if (loading && hotTopics.length === 0) {
4834
+ topicListHTML = '<div class="topic-loading">加载中...</div>';
4835
+ } else if (hotTopics.length === 0) {
4836
+ topicListHTML = '<div class="topic-empty">暂无热门话题</div>';
4837
+ } else {
4838
+ topicListHTML = hotTopics.map(
4839
+ (topic) => `<div class="topic-item" data-topic-id="${topic.id}">#${topic.exactlyMatchTitle}</div>`
4840
+ ).join("");
4841
+ if (loading) {
4842
+ topicListHTML += '<div class="topic-loading">加载更多...</div>';
4843
+ } else if (!hasMore) {
4844
+ topicListHTML += '<div class="topic-empty">没有更多了</div>';
4845
+ }
4846
+ }
4847
+ } else {
4848
+ if (recentTopics.length === 0) {
4849
+ topicListHTML = '<div class="topic-empty">暂无最近使用记录</div>';
4850
+ } else {
4851
+ topicListHTML = recentTopics.map(
4852
+ (topic) => `<div class="topic-item" data-topic-id="${topic.id}">#${topic.exactlyMatchTitle}</div>`
4853
+ ).join("");
4854
+ }
4855
+ }
4856
+ return `
4857
+ <div class="topic-popover-content">
4858
+ <div class="topic-tabs">
4859
+ <div class="topic-tab ${activeTab === "hot" ? "active" : ""}" data-tab="hot">
4860
+ 热门话题
4861
+ </div>
4862
+ <div class="topic-tab ${activeTab === "recent" ? "active" : ""}" data-tab="recent">
4863
+ 最近使用
4864
+ </div>
4865
+ </div>
4866
+ <div class="topic-list-container">
4867
+ <div class="topic-list">
4868
+ ${topicListHTML}
4869
+ </div>
4870
+ </div>
4871
+ </div>
4872
+ `;
4873
+ },
4874
+ // 获取搜索话题弹框HTML
4875
+ getSearchTopicPopoverHTML() {
4876
+ const searchKeyword = this.topicPopover.searchKeyword;
4877
+ const searchTopics = this.topicPopover.searchTopics;
4878
+ const loading = this.topicPopover.loading;
4879
+ const searchHasMore = this.topicPopover.searchHasMore;
4880
+ let topicListHTML = "";
4881
+ if (loading && searchTopics.length === 0) {
4882
+ topicListHTML = '<div class="topic-loading">搜索中...</div>';
4883
+ } else if (searchTopics.length === 0) {
4884
+ topicListHTML = '<div class="topic-empty">没有匹配到话题,请重新输入</div>';
4885
+ } else {
4886
+ topicListHTML = searchTopics.map(
4887
+ (topic) => `<div class="topic-item" data-topic-id="${topic.id}">#${topic.exactlyMatchTitle}</div>`
4888
+ ).join("");
4889
+ if (loading) {
4890
+ topicListHTML += '<div class="topic-loading">加载更多...</div>';
4891
+ } else if (!searchHasMore) {
4892
+ topicListHTML += '<div class="topic-empty">没有更多了</div>';
4893
+ }
4894
+ }
4895
+ return `
4896
+ <div class="topic-popover-content">
4897
+ <div class="topic-search-header">
4898
+ <span class="topic-search-title">#${searchKeyword}</span>
4899
+ </div>
4900
+ <div class="topic-list-container">
4901
+ <div class="topic-list">
4902
+ ${topicListHTML}
4903
+ </div>
4904
+ </div>
4905
+ </div>
4906
+ `;
4907
+ },
4908
+ // 绑定话题弹框事件
4909
+ bindTopicPopoverEvents() {
4910
+ if (!this.topicPopover.globalContainer)
4911
+ return;
4912
+ const tabs = this.topicPopover.globalContainer.querySelectorAll(".topic-tab");
4913
+ tabs.forEach((tab) => {
4914
+ tab.addEventListener("click", (e) => {
4915
+ const tabType = e.target.getAttribute("data-tab");
4916
+ this.switchTopicTab(tabType);
4917
+ });
4918
+ });
4919
+ const topicItems = this.topicPopover.globalContainer.querySelectorAll(".topic-item");
4920
+ topicItems.forEach((item) => {
4921
+ item.addEventListener("click", (e) => {
4922
+ const topicId = parseInt(e.target.getAttribute("data-topic-id"));
4923
+ const topic = this.findTopicById(topicId);
4924
+ if (topic) {
4925
+ this.selectTopic(topic);
4926
+ }
4927
+ });
4928
+ });
4929
+ const listContainer = this.topicPopover.globalContainer.querySelector(".topic-list-container");
4930
+ if (listContainer) {
4931
+ listContainer.addEventListener("scroll", (e) => {
4932
+ if (this.topicPopover.type === "hot") {
4933
+ this.handleTopicScroll(e);
4934
+ } else if (this.topicPopover.type === "search") {
4935
+ this.handleSearchTopicScroll(e);
4936
+ }
4937
+ });
4938
+ }
4939
+ },
4940
+ // 根据ID查找话题
4941
+ findTopicById(topicId) {
4942
+ let topic = this.topicPopover.hotTopics.find((t) => t.id === topicId);
4943
+ if (topic)
4944
+ return topic;
4945
+ topic = this.topicPopover.searchTopics.find((t) => t.id === topicId);
4946
+ if (topic)
4947
+ return topic;
4948
+ topic = this.topicPopover.recentTopics.find((t) => t.id === topicId);
4949
+ if (topic)
4950
+ return topic;
4951
+ return null;
4952
+ },
4953
+ handleTopicScroll(event) {
4954
+ if (this.topicPopover.activeTab !== "hot")
4955
+ return;
4956
+ const container = event.target;
4957
+ const scrollTop = container.scrollTop;
4958
+ const scrollHeight = container.scrollHeight;
4959
+ const clientHeight = container.clientHeight;
4960
+ if (scrollTop + clientHeight >= scrollHeight - 10) {
4961
+ this.loadHotTopics();
4962
+ }
4963
+ },
4964
+ handleSearchTopicScroll(event) {
4965
+ const container = event.target;
4966
+ const scrollTop = container.scrollTop;
4967
+ const scrollHeight = container.scrollHeight;
4968
+ const clientHeight = container.clientHeight;
4969
+ if (scrollTop + clientHeight >= scrollHeight - 10) {
4970
+ this.searchTopics(this.topicPopover.searchKeyword);
4971
+ }
4972
+ },
4973
+ insertTopicToEditor(topic) {
4974
+ const originalRange = this.topicPopover.originalRange;
4975
+ const triggerInfo = this.topicPopover.triggerInfo;
4976
+ const popoverType = this.topicPopover.type;
4977
+ this.hideTopicPopover();
4978
+ let range = originalRange;
4979
+ if (!range) {
4980
+ const selection2 = window.getSelection();
4981
+ if (selection2.rangeCount === 0)
4982
+ return;
4983
+ range = selection2.getRangeAt(0);
4984
+ }
4985
+ const topicText = `#${topic.exactlyMatchTitle}`;
4986
+ if (popoverType === "search" && triggerInfo && triggerInfo.paragraph) {
4987
+ const paragraph = triggerInfo.paragraph;
4988
+ const hashIndex = triggerInfo.hashIndex;
4989
+ const deleteRange = document.createRange();
4990
+ const walker = document.createTreeWalker(
4991
+ paragraph,
4992
+ NodeFilter.SHOW_TEXT,
4993
+ {
4994
+ acceptNode: function(node2) {
4995
+ let parent = node2.parentNode;
4996
+ while (parent && parent !== paragraph) {
4997
+ if (parent.tagName === "MDD-TOPIC") {
4998
+ return NodeFilter.FILTER_REJECT;
4999
+ }
5000
+ parent = parent.parentNode;
5001
+ }
5002
+ return NodeFilter.FILTER_ACCEPT;
5003
+ }
5004
+ },
5005
+ false
5006
+ );
5007
+ let position = 0;
5008
+ let startNode = null;
5009
+ let startOffset = 0;
5010
+ let endNode = null;
5011
+ let endOffset = 0;
5012
+ let node;
5013
+ while (node = walker.nextNode()) {
5014
+ if (position + node.textContent.length > hashIndex) {
5015
+ startNode = node;
5016
+ startOffset = hashIndex - position;
5017
+ break;
5018
+ }
5019
+ position += node.textContent.length;
5020
+ }
5021
+ const currentCursorPosition = triggerInfo.cursorPosition;
5022
+ position = 0;
5023
+ walker.currentNode = paragraph;
5024
+ while (node = walker.nextNode()) {
5025
+ if (position + node.textContent.length >= currentCursorPosition) {
5026
+ endNode = node;
5027
+ endOffset = currentCursorPosition - position;
5028
+ break;
5029
+ }
5030
+ position += node.textContent.length;
5031
+ }
5032
+ if (startNode && endNode) {
5033
+ deleteRange.setStart(startNode, startOffset);
5034
+ deleteRange.setEnd(endNode, endOffset);
5035
+ deleteRange.deleteContents();
5036
+ range = document.createRange();
5037
+ range.setStart(startNode, startOffset);
5038
+ range.collapse(true);
5039
+ }
5040
+ } else if (popoverType === "hot") {
5041
+ const container = range.startContainer;
5042
+ if (container.nodeType === Node.TEXT_NODE && container.textContent) {
5043
+ const offset = range.startOffset;
5044
+ if (offset > 0 && container.textContent[offset - 1] === "#") {
5045
+ const deleteRange = document.createRange();
5046
+ deleteRange.setStart(container, offset - 1);
5047
+ deleteRange.setEnd(container, offset);
5048
+ deleteRange.deleteContents();
5049
+ range.setStart(container, offset - 1);
5050
+ range.collapse(true);
5051
+ }
5052
+ }
5053
+ }
5054
+ const topicElement = document.createElement("mdd-topic");
5055
+ topicElement.setAttribute("data-topic", JSON.stringify({
5056
+ topicId: topic.id,
5057
+ topicType: 0,
5058
+ startIndex: 0,
5059
+ // 会在updateTopicPosition中更新
5060
+ endIndex: 0
5061
+ // 会在updateTopicPosition中更新
5062
+ }));
5063
+ topicElement.textContent = topicText;
5064
+ topicElement.setAttribute("contenteditable", "false");
5065
+ range.deleteContents();
5066
+ range.insertNode(topicElement);
5067
+ const spaceNode = document.createTextNode(" ");
5068
+ range.setStartAfter(topicElement);
5069
+ range.insertNode(spaceNode);
5070
+ const newRange = document.createRange();
5071
+ newRange.setStartAfter(spaceNode);
5072
+ newRange.collapse(true);
5073
+ const selection = window.getSelection();
5074
+ selection.removeAllRanges();
5075
+ selection.addRange(newRange);
5076
+ setTimeout(() => {
5077
+ const currentSelection = window.getSelection();
5078
+ if (currentSelection.rangeCount > 0) {
5079
+ const currentRange = currentSelection.getRangeAt(0);
5080
+ if (currentRange.startContainer !== spaceNode.nextSibling) {
5081
+ const correctRange = document.createRange();
5082
+ correctRange.setStartAfter(spaceNode);
5083
+ correctRange.collapse(true);
5084
+ currentSelection.removeAllRanges();
5085
+ currentSelection.addRange(correctRange);
5086
+ }
5087
+ }
5088
+ }, 0);
5089
+ this.$emit("update-topic-position");
5090
+ },
5091
+ // 销毁话题管理器
5092
+ destroy() {
5093
+ this.unbindEditorEvents();
5094
+ this.hideTopicPopover();
5095
+ }
5096
+ },
5097
+ mounted() {
5098
+ this.init();
5099
+ },
5100
+ beforeUnmount() {
5101
+ this.destroy();
5102
+ }
5103
+ };
5104
+ const _hoisted_1$3 = { class: "topic-manager" };
5105
+ function _sfc_render$3(_ctx, _cache, $props, $setup, $data, $options) {
5106
+ return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$3);
5107
+ }
5108
+ const TopicManager = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["render", _sfc_render$3]]);
4411
5109
  const index_vue_vue_type_style_index_0_lang = "";
4412
5110
  const _sfc_main$2 = {
4413
5111
  provide() {
@@ -4417,7 +5115,7 @@
4417
5115
  },
4418
5116
  components: {
4419
5117
  ElInput: elementPlus.ElInput,
4420
- BasicDialog: _sfc_main$6,
5118
+ BasicDialog: _sfc_main$7,
4421
5119
  draggable
4422
5120
  },
4423
5121
  props: {
@@ -4588,14 +5286,15 @@
4588
5286
  name: "Edit",
4589
5287
  components: {
4590
5288
  ElInput: elementPlus.ElInput,
4591
- InsertArticle: _sfc_main$5,
4592
- ImgUpload: _sfc_main$4,
4593
- VideoUpload: _sfc_main$3,
5289
+ InsertArticle: _sfc_main$6,
5290
+ ImgUpload: _sfc_main$5,
5291
+ VideoUpload: _sfc_main$4,
4594
5292
  CollectArticle,
4595
5293
  ElFormItem: elementPlus.ElFormItem,
4596
5294
  ElForm: elementPlus.ElForm,
4597
5295
  ElDialog: elementPlus.ElDialog,
4598
- ElButton: elementPlus.ElButton
5296
+ ElButton: elementPlus.ElButton,
5297
+ TopicManager
4599
5298
  },
4600
5299
  props: [
4601
5300
  "disabled",
@@ -4605,7 +5304,8 @@
4605
5304
  "importEssay",
4606
5305
  "uploadImageByOther",
4607
5306
  "chartGallery",
4608
- "request"
5307
+ "request",
5308
+ "placeholder"
4609
5309
  ],
4610
5310
  data() {
4611
5311
  return {
@@ -4765,7 +5465,6 @@
4765
5465
  },
4766
5466
  setCursor() {
4767
5467
  this.cursorStyle = this.cursorStyle === cursorImg ? "auto" : cursorImg;
4768
- console.log(this.styleStatus, 999);
4769
5468
  this.curStyle = { ...this.styleStatus };
4770
5469
  this.editorDom.addEventListener("mouseup", this.handleCopyFormatUp);
4771
5470
  },
@@ -4895,7 +5594,6 @@
4895
5594
  this.updateData(true);
4896
5595
  this.viewLinkDialog = false;
4897
5596
  },
4898
- // mark MDD-TOPIC
4899
5597
  updateTopicPosition() {
4900
5598
  const paragraphList = document.querySelectorAll("#editor-content .halo-paragraph") || [];
4901
5599
  Array.from(paragraphList).forEach((paragraph) => {
@@ -4916,6 +5614,10 @@
4916
5614
  });
4917
5615
  });
4918
5616
  },
5617
+ // TopicManager事件处理
5618
+ onTopicInserted(topic) {
5619
+ this.updateData(true);
5620
+ },
4919
5621
  getHtml(type) {
4920
5622
  this.updateTopicPosition();
4921
5623
  const html = this.editor.getHTML();
@@ -5017,6 +5719,8 @@
5017
5719
  const frag = document.createDocumentFragment();
5018
5720
  frag.appendChild(this.editor.empty(div));
5019
5721
  const nodes = [...frag.childNodes];
5722
+ const mddTopics = frag.querySelectorAll("mdd-topic");
5723
+ mddTopics.forEach((topic) => topic.setAttribute("contenteditable", "false"));
5020
5724
  for (let i = 0; i < nodes.length; i++) {
5021
5725
  const node = nodes[i];
5022
5726
  if (node.nodeType === 1) {
@@ -5110,6 +5814,8 @@
5110
5814
  },
5111
5815
  async parseArticle(node) {
5112
5816
  const data = JSON.parse(node.dataset.article);
5817
+ if (!this.getEassyDetail)
5818
+ return;
5113
5819
  await this.getEassyDetail(data.id, (info) => {
5114
5820
  const el = mountArticleDom(
5115
5821
  {
@@ -5402,7 +6108,6 @@
5402
6108
  }
5403
6109
  });
5404
6110
  var descInputWrap;
5405
- console.log(data.seamlessFlag, "count<<<<<<");
5406
6111
  var descInput = editor.createElement("textarea", {
5407
6112
  class: "desc-input",
5408
6113
  maxlength: "50",
@@ -5491,7 +6196,7 @@
5491
6196
  }
5492
6197
  }
5493
6198
  },
5494
- // 初始化编辑器数据 displayData
6199
+ // 初始化编辑器数据,数据是 html 格式(displayData
5495
6200
  initData(data = "", essayPicRelVOList) {
5496
6201
  this.parseHtml(data, essayPicRelVOList).then((res) => {
5497
6202
  this.editorDom.innerHTML = "";
@@ -5499,6 +6204,12 @@
5499
6204
  this.updateData();
5500
6205
  });
5501
6206
  },
6207
+ // TODO jsonToHtml、htmlToJson 实现这 2 个方法里面的逻辑,数据结构参考方法里面的注释,出参入参都为字符串,注意:mdd-topic 里面的属性数据 和 json 中的topicPosition数据是一一对应的,startIndex、endIndex为mdd-topic的起止位置 从 content 里面进行分割处理
6208
+ // json、html 数据格式互转,暂时只支持文字、短话题
6209
+ jsonToHtml(json) {
6210
+ },
6211
+ htmlToJson(html) {
6212
+ },
5502
6213
  // 设置富文本组件
5503
6214
  initSquire() {
5504
6215
  const me2 = this;
@@ -5587,7 +6298,8 @@
5587
6298
  event.preventDefault();
5588
6299
  });
5589
6300
  me2.editor.addEventListener("keydown", function(event) {
5590
- if (event.keyCode === 8 || event.keyCode === 46) {
6301
+ var _a, _b, _c;
6302
+ if (["Backspace", "Delete"].includes(event.key)) {
5591
6303
  try {
5592
6304
  const selection2 = getSelection();
5593
6305
  if (me2.selectDom && me2.moverClasses.includes(me2.selectDom.className)) {
@@ -5621,32 +6333,10 @@
5621
6333
  } catch (error) {
5622
6334
  console.log(error);
5623
6335
  }
5624
- }
5625
- const selection = window.getSelection();
5626
- if (selection.rangeCount > 0) {
5627
- const range = selection.getRangeAt(0);
5628
- const startContainer = range.startContainer;
5629
- let isInMddTopic = false;
5630
- if (startContainer.nodeType === Node.ELEMENT_NODE && startContainer.tagName === "MDD-TOPIC") {
5631
- isInMddTopic = true;
5632
- } else if (startContainer.nodeType === Node.TEXT_NODE) {
5633
- const parent = startContainer.parentNode;
5634
- if (parent.tagName === "MDD-TOPIC") {
5635
- isInMddTopic = true;
5636
- }
5637
- }
5638
- if (isInMddTopic) {
5639
- if (event.key === "Enter") {
5640
- event.preventDefault();
5641
- return;
5642
- }
5643
- const isPrintableKey = event.key.length === 1;
5644
- if (isPrintableKey) {
5645
- event.preventDefault();
5646
- return;
5647
- }
5648
- }
5649
- if ((event.key === "Backspace" || event.key === "Delete") && isInMddTopic) {
6336
+ const selection = window.getSelection();
6337
+ if (selection.rangeCount > 0) {
6338
+ const range = selection.getRangeAt(0);
6339
+ const startContainer = range.startContainer;
5650
6340
  if (startContainer.nodeType === Node.ELEMENT_NODE && startContainer.tagName === "MDD-TOPIC") {
5651
6341
  startContainer.remove();
5652
6342
  event.preventDefault();
@@ -5659,6 +6349,228 @@
5659
6349
  return;
5660
6350
  }
5661
6351
  }
6352
+ let currentParagraph = startContainer;
6353
+ while (currentParagraph && currentParagraph.nodeType !== Node.ELEMENT_NODE) {
6354
+ currentParagraph = currentParagraph.parentNode;
6355
+ }
6356
+ while (currentParagraph && !((_a = currentParagraph.classList) == null ? void 0 : _a.contains("halo-paragraph"))) {
6357
+ currentParagraph = currentParagraph.parentNode;
6358
+ }
6359
+ if (currentParagraph && event.key === "Backspace") {
6360
+ const container = range.startContainer;
6361
+ const offset = range.startOffset;
6362
+ let isAtParagraphStart = false;
6363
+ let cursorBeforeContent = null;
6364
+ if (container === currentParagraph && offset === 0) {
6365
+ isAtParagraphStart = true;
6366
+ cursorBeforeContent = currentParagraph.firstChild;
6367
+ } else if (container.nodeType === Node.TEXT_NODE && offset === 0) {
6368
+ let isFirstContent = true;
6369
+ let currentNode = currentParagraph.firstChild;
6370
+ while (currentNode && currentNode !== container) {
6371
+ if (currentNode.nodeType === Node.TEXT_NODE && currentNode.textContent.trim() !== "") {
6372
+ isFirstContent = false;
6373
+ break;
6374
+ } else if (currentNode.nodeType === Node.ELEMENT_NODE) {
6375
+ isFirstContent = false;
6376
+ break;
6377
+ }
6378
+ currentNode = currentNode.nextSibling;
6379
+ }
6380
+ if (isFirstContent) {
6381
+ isAtParagraphStart = true;
6382
+ cursorBeforeContent = container;
6383
+ }
6384
+ } else if (container === currentParagraph && offset > 0) {
6385
+ let hasContentBefore = false;
6386
+ for (let i = 0; i < offset; i++) {
6387
+ const node = currentParagraph.childNodes[i];
6388
+ if (node.nodeType === Node.TEXT_NODE && node.textContent.trim() !== "") {
6389
+ hasContentBefore = true;
6390
+ break;
6391
+ } else if (node.nodeType === Node.ELEMENT_NODE) {
6392
+ hasContentBefore = true;
6393
+ break;
6394
+ }
6395
+ }
6396
+ if (!hasContentBefore && offset < currentParagraph.childNodes.length) {
6397
+ isAtParagraphStart = true;
6398
+ cursorBeforeContent = currentParagraph.childNodes[offset];
6399
+ }
6400
+ }
6401
+ if (isAtParagraphStart) {
6402
+ const prevParagraph = currentParagraph.previousElementSibling;
6403
+ if (prevParagraph && prevParagraph.classList.contains("halo-paragraph")) {
6404
+ const prevContent = prevParagraph.innerHTML.trim();
6405
+ if (prevContent === "<br>" || prevContent === "") {
6406
+ prevParagraph.remove();
6407
+ event.preventDefault();
6408
+ me2.updateData(true);
6409
+ return;
6410
+ } else {
6411
+ const mergePoint = prevParagraph.childNodes.length;
6412
+ if (prevParagraph.lastChild && prevParagraph.lastChild.tagName === "BR") {
6413
+ prevParagraph.removeChild(prevParagraph.lastChild);
6414
+ }
6415
+ const nodesToMove = Array.from(currentParagraph.childNodes);
6416
+ nodesToMove.forEach((node) => {
6417
+ prevParagraph.appendChild(node);
6418
+ });
6419
+ currentParagraph.remove();
6420
+ const newRange = document.createRange();
6421
+ if (cursorBeforeContent && prevParagraph.contains(cursorBeforeContent)) {
6422
+ newRange.setStartBefore(cursorBeforeContent);
6423
+ } else {
6424
+ if (mergePoint < prevParagraph.childNodes.length) {
6425
+ newRange.setStartBefore(prevParagraph.childNodes[mergePoint]);
6426
+ } else {
6427
+ newRange.setStart(prevParagraph, prevParagraph.childNodes.length);
6428
+ }
6429
+ }
6430
+ newRange.collapse(true);
6431
+ const selection2 = window.getSelection();
6432
+ selection2.removeAllRanges();
6433
+ selection2.addRange(newRange);
6434
+ event.preventDefault();
6435
+ me2.updateData(true);
6436
+ return;
6437
+ }
6438
+ }
6439
+ }
6440
+ }
6441
+ }
6442
+ }
6443
+ if (event.key === "Enter") {
6444
+ const selection = window.getSelection();
6445
+ if (selection.rangeCount > 0) {
6446
+ const range = selection.getRangeAt(0);
6447
+ const startContainer = range.startContainer;
6448
+ let currentParagraph = startContainer;
6449
+ while (currentParagraph && currentParagraph.nodeType !== Node.ELEMENT_NODE) {
6450
+ currentParagraph = currentParagraph.parentNode;
6451
+ }
6452
+ while (currentParagraph && !((_b = currentParagraph.classList) == null ? void 0 : _b.contains("halo-paragraph"))) {
6453
+ currentParagraph = currentParagraph.parentNode;
6454
+ }
6455
+ if (!(currentParagraph == null ? void 0 : currentParagraph.querySelector("mdd-topic"))) {
6456
+ return;
6457
+ }
6458
+ if (me2.isBetweenTwoTopics(range)) {
6459
+ event.preventDefault();
6460
+ me2.handleEnterBetweenTopics(range);
6461
+ return;
6462
+ }
6463
+ if (me2.wouldCreateNestedParagraph(range)) {
6464
+ event.preventDefault();
6465
+ me2.handleEnterKeyInParagraphWithTopic(range);
6466
+ return;
6467
+ }
6468
+ if (currentParagraph && currentParagraph.querySelector("mdd-topic")) {
6469
+ event.preventDefault();
6470
+ me2.handleEnterKeyInParagraphWithTopic(range);
6471
+ return;
6472
+ }
6473
+ }
6474
+ }
6475
+ if ((event.metaKey || event.ctrlKey) && event.key === "ArrowLeft") {
6476
+ const selection = window.getSelection();
6477
+ if (selection.rangeCount > 0) {
6478
+ const range = selection.getRangeAt(0);
6479
+ const container = range.startContainer;
6480
+ let currentParagraph = container;
6481
+ while (currentParagraph && currentParagraph.nodeType !== Node.ELEMENT_NODE) {
6482
+ currentParagraph = currentParagraph.parentNode;
6483
+ }
6484
+ while (currentParagraph && !((_c = currentParagraph.classList) == null ? void 0 : _c.contains("halo-paragraph"))) {
6485
+ currentParagraph = currentParagraph.parentNode;
6486
+ }
6487
+ if (currentParagraph) {
6488
+ const firstTopic = currentParagraph.querySelector("mdd-topic");
6489
+ if (firstTopic) {
6490
+ let hasTextBeforeTopic = false;
6491
+ let currentNode = currentParagraph.firstChild;
6492
+ while (currentNode && currentNode !== firstTopic) {
6493
+ if (currentNode.nodeType === Node.TEXT_NODE && currentNode.textContent.trim() !== "") {
6494
+ hasTextBeforeTopic = true;
6495
+ break;
6496
+ }
6497
+ currentNode = currentNode.nextSibling;
6498
+ }
6499
+ if (hasTextBeforeTopic) {
6500
+ if (container === currentParagraph && range.startOffset === 0) {
6501
+ return;
6502
+ }
6503
+ let shouldMoveToStart = false;
6504
+ const offset2 = range.startOffset;
6505
+ if (container.nodeType === Node.TEXT_NODE && container.parentNode === firstTopic) {
6506
+ shouldMoveToStart = true;
6507
+ } else if (container === firstTopic) {
6508
+ shouldMoveToStart = true;
6509
+ } else if (container.nodeType === Node.TEXT_NODE) {
6510
+ let prevSibling = container.previousSibling;
6511
+ while (prevSibling) {
6512
+ if (prevSibling === firstTopic) {
6513
+ shouldMoveToStart = true;
6514
+ break;
6515
+ }
6516
+ prevSibling = prevSibling.previousSibling;
6517
+ }
6518
+ } else if (container === currentParagraph) {
6519
+ const topicRange = document.createRange();
6520
+ topicRange.selectNode(firstTopic);
6521
+ const cursorRange = document.createRange();
6522
+ cursorRange.setStart(container, offset2);
6523
+ cursorRange.collapse(true);
6524
+ if (cursorRange.compareBoundaryPoints(Range.START_TO_END, topicRange) > 0) {
6525
+ shouldMoveToStart = true;
6526
+ }
6527
+ }
6528
+ if (shouldMoveToStart) {
6529
+ event.preventDefault();
6530
+ event.stopPropagation();
6531
+ const newRange = document.createRange();
6532
+ newRange.setStart(currentParagraph, 0);
6533
+ newRange.collapse(true);
6534
+ const selection2 = window.getSelection();
6535
+ selection2.removeAllRanges();
6536
+ selection2.addRange(newRange);
6537
+ return false;
6538
+ }
6539
+ return;
6540
+ }
6541
+ let shouldMoveToTopicStart = false;
6542
+ const offset = range.startOffset;
6543
+ if (container.nodeType === Node.TEXT_NODE && container.parentNode === firstTopic) {
6544
+ shouldMoveToTopicStart = true;
6545
+ } else if (container === firstTopic) {
6546
+ shouldMoveToTopicStart = true;
6547
+ } else if (container.nodeType === Node.TEXT_NODE) {
6548
+ let prevSibling = container.previousSibling;
6549
+ while (prevSibling) {
6550
+ if (prevSibling === firstTopic) {
6551
+ shouldMoveToTopicStart = true;
6552
+ break;
6553
+ }
6554
+ prevSibling = prevSibling.previousSibling;
6555
+ }
6556
+ } else if (container === currentParagraph) {
6557
+ const topicRange = document.createRange();
6558
+ topicRange.selectNode(firstTopic);
6559
+ const cursorRange = document.createRange();
6560
+ cursorRange.setStart(container, offset);
6561
+ cursorRange.collapse(true);
6562
+ if (cursorRange.compareBoundaryPoints(Range.START_TO_END, topicRange) > 0) {
6563
+ shouldMoveToTopicStart = true;
6564
+ }
6565
+ }
6566
+ if (shouldMoveToTopicStart) {
6567
+ event.preventDefault();
6568
+ event.stopPropagation();
6569
+ me2.setCursorBeforeElement(firstTopic);
6570
+ return false;
6571
+ }
6572
+ }
6573
+ }
5662
6574
  }
5663
6575
  }
5664
6576
  });
@@ -5721,7 +6633,6 @@
5721
6633
  this.insertElement(p);
5722
6634
  };
5723
6635
  window.Squire.prototype.makeHeader = function(content, config = { makeHeader: {} }) {
5724
- console.log(content);
5725
6636
  if (content) {
5726
6637
  const h2 = this.createElement("h2", {
5727
6638
  class: "halo-paragraph-title"
@@ -5755,7 +6666,6 @@
5755
6666
  });
5756
6667
  const selection = window.getSelection();
5757
6668
  const range = document.createRange();
5758
- console.log(container);
5759
6669
  range.setStart(container, 1);
5760
6670
  range.collapse(true);
5761
6671
  selection.removeAllRanges();
@@ -5870,7 +6780,6 @@
5870
6780
  e.stopPropagation();
5871
6781
  }
5872
6782
  });
5873
- console.log(delBtn);
5874
6783
  const posterBtn = me2.insertVideoBtns(this, video);
5875
6784
  var p = this.createElement(
5876
6785
  "DIV",
@@ -6418,6 +7327,408 @@
6418
7327
  }).then(() => {
6419
7328
  }).catch(() => {
6420
7329
  });
7330
+ },
7331
+ // 检查是否会创建嵌套的halo-paragraph
7332
+ wouldCreateNestedParagraph(range) {
7333
+ let container = range.startContainer;
7334
+ while (container && container !== this.editorDom) {
7335
+ if (container.nodeType === Node.ELEMENT_NODE && container.classList && container.classList.contains("halo-paragraph")) {
7336
+ return true;
7337
+ }
7338
+ container = container.parentNode;
7339
+ }
7340
+ return false;
7341
+ },
7342
+ // 检查光标是否在两个连续的mdd-topic之间
7343
+ isBetweenTwoTopics(range) {
7344
+ const container = range.startContainer;
7345
+ const offset = range.startOffset;
7346
+ if (container.nodeType === Node.ELEMENT_NODE) {
7347
+ const prevElement = container.childNodes[offset - 1];
7348
+ const nextElement = container.childNodes[offset];
7349
+ return prevElement && prevElement.tagName === "MDD-TOPIC" && (nextElement && nextElement.tagName === "MDD-TOPIC");
7350
+ }
7351
+ if (container.nodeType === Node.TEXT_NODE && container.textContent.trim() === "") {
7352
+ const prevSibling = container.previousSibling;
7353
+ const nextSibling = container.nextSibling;
7354
+ return prevSibling && prevSibling.tagName === "MDD-TOPIC" && (nextSibling && nextSibling.tagName === "MDD-TOPIC");
7355
+ }
7356
+ return false;
7357
+ },
7358
+ // 处理两个话题之间的回车或话题前面的回车
7359
+ handleEnterBetweenTopics(range) {
7360
+ var _a;
7361
+ const me2 = this;
7362
+ let currentParagraph = range.startContainer;
7363
+ while (currentParagraph && currentParagraph.nodeType !== Node.ELEMENT_NODE) {
7364
+ currentParagraph = currentParagraph.parentNode;
7365
+ }
7366
+ while (currentParagraph && !((_a = currentParagraph.classList) == null ? void 0 : _a.contains("halo-paragraph"))) {
7367
+ currentParagraph = currentParagraph.parentNode;
7368
+ }
7369
+ if (!currentParagraph)
7370
+ return;
7371
+ const newParagraph = document.createElement("p");
7372
+ newParagraph.className = "halo-paragraph";
7373
+ const afterContent = me2.extractContentAfterCursorPrecise(range, currentParagraph);
7374
+ if (afterContent && afterContent.childNodes.length > 0) {
7375
+ while (afterContent.firstChild) {
7376
+ newParagraph.appendChild(afterContent.firstChild);
7377
+ }
7378
+ } else {
7379
+ newParagraph.innerHTML = "<br>";
7380
+ }
7381
+ currentParagraph.parentNode.insertBefore(newParagraph, currentParagraph.nextSibling);
7382
+ const newRange = document.createRange();
7383
+ if (newParagraph.firstChild && newParagraph.firstChild.nodeType === Node.TEXT_NODE) {
7384
+ newRange.setStart(newParagraph.firstChild, 0);
7385
+ } else if (newParagraph.firstChild && newParagraph.firstChild.nodeType === Node.ELEMENT_NODE) {
7386
+ newRange.setStart(newParagraph, 0);
7387
+ } else {
7388
+ newRange.setStart(newParagraph, 0);
7389
+ }
7390
+ newRange.collapse(true);
7391
+ const selection = window.getSelection();
7392
+ selection.removeAllRanges();
7393
+ selection.addRange(newRange);
7394
+ me2.updateData(true);
7395
+ },
7396
+ // 更精确地提取光标后的内容(专门用于话题分割)
7397
+ extractContentAfterCursorPrecise(range, paragraph) {
7398
+ const fragment = document.createDocumentFragment();
7399
+ const container = range.startContainer;
7400
+ const offset = range.startOffset;
7401
+ if (container.nodeType === Node.ELEMENT_NODE) {
7402
+ const childNodes = Array.from(container.childNodes);
7403
+ for (let i = offset; i < childNodes.length; i++) {
7404
+ fragment.appendChild(childNodes[i]);
7405
+ }
7406
+ } else if (container.nodeType === Node.TEXT_NODE) {
7407
+ if (offset < container.textContent.length) {
7408
+ const afterText = container.textContent.slice(offset);
7409
+ container.textContent = container.textContent.slice(0, offset);
7410
+ const textNode = document.createTextNode(afterText);
7411
+ fragment.appendChild(textNode);
7412
+ }
7413
+ let nextSibling = container.nextSibling;
7414
+ while (nextSibling) {
7415
+ const nodeToMove = nextSibling;
7416
+ nextSibling = nextSibling.nextSibling;
7417
+ fragment.appendChild(nodeToMove);
7418
+ }
7419
+ }
7420
+ return fragment;
7421
+ },
7422
+ // 处理包含话题的段落中的回车键
7423
+ handleEnterKeyInParagraphWithTopic(range) {
7424
+ var _a;
7425
+ const me2 = this;
7426
+ let currentParagraph = range.startContainer;
7427
+ while (currentParagraph && currentParagraph.nodeType !== Node.ELEMENT_NODE) {
7428
+ currentParagraph = currentParagraph.parentNode;
7429
+ }
7430
+ while (currentParagraph && !((_a = currentParagraph.classList) == null ? void 0 : _a.contains("halo-paragraph"))) {
7431
+ currentParagraph = currentParagraph.parentNode;
7432
+ }
7433
+ if (!currentParagraph)
7434
+ return;
7435
+ const newParagraph = document.createElement("p");
7436
+ newParagraph.className = "halo-paragraph";
7437
+ const isAtTopicStart = me2.isCursorBeforeFirstTopic(range, currentParagraph);
7438
+ const isAtEnd = me2.isCursorAtEndOfParagraph(range, currentParagraph);
7439
+ if (isAtTopicStart) {
7440
+ const afterContent = me2.extractContentAfterCursor(range, currentParagraph);
7441
+ if (afterContent && afterContent.childNodes.length > 0) {
7442
+ while (afterContent.firstChild) {
7443
+ newParagraph.appendChild(afterContent.firstChild);
7444
+ }
7445
+ } else {
7446
+ newParagraph.innerHTML = "<br>";
7447
+ }
7448
+ if (currentParagraph.innerHTML.trim() === "" || currentParagraph.childNodes.length === 0) {
7449
+ currentParagraph.innerHTML = "<br>";
7450
+ }
7451
+ currentParagraph.parentNode.insertBefore(newParagraph, currentParagraph.nextSibling);
7452
+ } else if (isAtEnd) {
7453
+ newParagraph.innerHTML = "<br>";
7454
+ currentParagraph.parentNode.insertBefore(newParagraph, currentParagraph.nextSibling);
7455
+ } else {
7456
+ const afterContent = me2.extractContentAfterCursor(range, currentParagraph);
7457
+ if (afterContent && afterContent.childNodes.length > 0) {
7458
+ let hasValidContent = false;
7459
+ for (let i = 0; i < afterContent.childNodes.length; i++) {
7460
+ const node = afterContent.childNodes[i];
7461
+ if (node.nodeType === Node.TEXT_NODE) {
7462
+ if (node.textContent.trim() !== "") {
7463
+ hasValidContent = true;
7464
+ break;
7465
+ }
7466
+ } else {
7467
+ hasValidContent = true;
7468
+ break;
7469
+ }
7470
+ }
7471
+ if (hasValidContent) {
7472
+ while (afterContent.firstChild) {
7473
+ newParagraph.appendChild(afterContent.firstChild);
7474
+ }
7475
+ } else {
7476
+ newParagraph.innerHTML = "<br>";
7477
+ }
7478
+ } else {
7479
+ newParagraph.innerHTML = "<br>";
7480
+ }
7481
+ currentParagraph.parentNode.insertBefore(newParagraph, currentParagraph.nextSibling);
7482
+ }
7483
+ const newRange = document.createRange();
7484
+ if (newParagraph.firstChild && newParagraph.firstChild.nodeType === Node.TEXT_NODE) {
7485
+ newRange.setStart(newParagraph.firstChild, 0);
7486
+ } else if (newParagraph.firstChild) {
7487
+ newRange.setStart(newParagraph, 0);
7488
+ } else {
7489
+ newRange.setStart(newParagraph, 0);
7490
+ }
7491
+ newRange.collapse(true);
7492
+ const selection = window.getSelection();
7493
+ selection.removeAllRanges();
7494
+ selection.addRange(newRange);
7495
+ me2.updateData(true);
7496
+ },
7497
+ // 检查光标是否在第一个话题前面
7498
+ isCursorBeforeFirstTopic(range, paragraph) {
7499
+ const container = range.startContainer;
7500
+ const offset = range.startOffset;
7501
+ const firstTopic = paragraph.querySelector("mdd-topic");
7502
+ if (!firstTopic) {
7503
+ return false;
7504
+ }
7505
+ if (container === paragraph && offset === 0) {
7506
+ return true;
7507
+ }
7508
+ if (container === paragraph && offset > 0 && offset <= paragraph.childNodes.length) {
7509
+ if (offset < paragraph.childNodes.length) {
7510
+ const nodeAtOffset = paragraph.childNodes[offset];
7511
+ if (nodeAtOffset === firstTopic) {
7512
+ return true;
7513
+ }
7514
+ }
7515
+ let nextNonEmptyNode = null;
7516
+ for (let i = offset; i < paragraph.childNodes.length; i++) {
7517
+ const node = paragraph.childNodes[i];
7518
+ if (node.nodeType === Node.ELEMENT_NODE && node.tagName === "MDD-TOPIC") {
7519
+ nextNonEmptyNode = node;
7520
+ break;
7521
+ } else if (node.nodeType === Node.TEXT_NODE && node.textContent.trim() !== "") {
7522
+ break;
7523
+ }
7524
+ }
7525
+ if (nextNonEmptyNode === firstTopic) {
7526
+ return true;
7527
+ }
7528
+ }
7529
+ try {
7530
+ const topicRange = document.createRange();
7531
+ topicRange.setStartBefore(firstTopic);
7532
+ const comparison = topicRange.comparePoint(container, offset);
7533
+ if (comparison < 0) {
7534
+ return true;
7535
+ }
7536
+ } catch (e) {
7537
+ if (container.nodeType === Node.TEXT_NODE) {
7538
+ const tempRange = document.createRange();
7539
+ tempRange.setStart(container, offset);
7540
+ tempRange.collapse(true);
7541
+ const topicRange = document.createRange();
7542
+ topicRange.setStartBefore(firstTopic);
7543
+ if (tempRange.compareBoundaryPoints(Range.START_TO_START, topicRange) < 0) {
7544
+ return true;
7545
+ }
7546
+ }
7547
+ if (container === paragraph) {
7548
+ const testRange = document.createRange();
7549
+ testRange.setStart(paragraph, 0);
7550
+ testRange.setEnd(paragraph, offset);
7551
+ const containsTopic = testRange.intersectsNode(firstTopic);
7552
+ if (!containsTopic) {
7553
+ return true;
7554
+ }
7555
+ }
7556
+ }
7557
+ return false;
7558
+ },
7559
+ // 获取不包含mdd-topic内部文本的段落文本
7560
+ getParagraphTextExcludingTopics(paragraph, range) {
7561
+ let textContent = "";
7562
+ let cursorPosition = 0;
7563
+ let foundCursor = false;
7564
+ const walker = document.createTreeWalker(
7565
+ paragraph,
7566
+ NodeFilter.SHOW_ALL,
7567
+ {
7568
+ acceptNode: function(node2) {
7569
+ if (node2.nodeType === Node.ELEMENT_NODE && node2.tagName === "MDD-TOPIC") {
7570
+ return NodeFilter.FILTER_REJECT;
7571
+ }
7572
+ return NodeFilter.FILTER_ACCEPT;
7573
+ }
7574
+ },
7575
+ false
7576
+ );
7577
+ let node;
7578
+ while (node = walker.nextNode()) {
7579
+ if (node.nodeType === Node.TEXT_NODE) {
7580
+ const nodeText = node.textContent;
7581
+ if (!foundCursor && node === range.startContainer) {
7582
+ cursorPosition = textContent.length + range.startOffset;
7583
+ foundCursor = true;
7584
+ }
7585
+ textContent += nodeText;
7586
+ }
7587
+ }
7588
+ return { textContent, cursorPosition };
7589
+ },
7590
+ // 检查光标是否在段落开头
7591
+ isCursorAtStartOfParagraph(range, paragraph) {
7592
+ const { cursorPosition } = this.getParagraphTextExcludingTopics(paragraph, range);
7593
+ return cursorPosition === 0;
7594
+ },
7595
+ // 检查光标是否在段落末尾
7596
+ isCursorAtEndOfParagraph(range, paragraph) {
7597
+ const walker = document.createTreeWalker(
7598
+ paragraph,
7599
+ NodeFilter.SHOW_TEXT,
7600
+ {
7601
+ acceptNode: function(node2) {
7602
+ let parent = node2.parentNode;
7603
+ while (parent && parent !== paragraph) {
7604
+ if (parent.tagName === "MDD-TOPIC") {
7605
+ return NodeFilter.FILTER_REJECT;
7606
+ }
7607
+ parent = parent.parentNode;
7608
+ }
7609
+ return NodeFilter.FILTER_ACCEPT;
7610
+ }
7611
+ },
7612
+ false
7613
+ );
7614
+ let totalLength = 0;
7615
+ let node;
7616
+ while (node = walker.nextNode()) {
7617
+ totalLength += node.textContent.length;
7618
+ }
7619
+ const { cursorPosition } = this.getParagraphTextExcludingTopics(paragraph, range);
7620
+ return cursorPosition >= totalLength;
7621
+ },
7622
+ // 获取当前段落
7623
+ getCurrentParagraph(range) {
7624
+ let container = range.startContainer;
7625
+ while (container && container !== this.editorDom) {
7626
+ if (container.nodeType === Node.ELEMENT_NODE && container.classList && container.classList.contains("halo-paragraph")) {
7627
+ return container;
7628
+ }
7629
+ container = container.parentNode;
7630
+ }
7631
+ return null;
7632
+ },
7633
+ // 提取光标后的内容
7634
+ extractContentAfterCursor(range, paragraph) {
7635
+ const fragment = document.createDocumentFragment();
7636
+ const container = range.startContainer;
7637
+ const offset = range.startOffset;
7638
+ let topicSpaceNode = null;
7639
+ if (container.nodeType === Node.TEXT_NODE && container.textContent === " " && container.previousSibling && container.previousSibling.tagName === "MDD-TOPIC") {
7640
+ topicSpaceNode = container;
7641
+ }
7642
+ const extractRange = document.createRange();
7643
+ let startNode = null;
7644
+ let hasContentToExtract = false;
7645
+ if (topicSpaceNode) {
7646
+ if (topicSpaceNode.nextSibling) {
7647
+ startNode = topicSpaceNode.nextSibling;
7648
+ hasContentToExtract = true;
7649
+ }
7650
+ } else if (container.nodeType === Node.TEXT_NODE) {
7651
+ if (container.textContent === "" && offset === 0) {
7652
+ if (container.nextSibling) {
7653
+ startNode = container.nextSibling;
7654
+ hasContentToExtract = true;
7655
+ }
7656
+ } else if (offset < container.textContent.length) {
7657
+ const afterText = container.textContent.slice(offset);
7658
+ container.textContent = container.textContent.slice(0, offset);
7659
+ if (afterText.trim()) {
7660
+ const newTextNode = document.createTextNode(afterText);
7661
+ container.parentNode.insertBefore(newTextNode, container.nextSibling);
7662
+ startNode = newTextNode;
7663
+ hasContentToExtract = true;
7664
+ } else if (container.nextSibling) {
7665
+ startNode = container.nextSibling;
7666
+ hasContentToExtract = true;
7667
+ }
7668
+ } else {
7669
+ if (container.nextSibling) {
7670
+ startNode = container.nextSibling;
7671
+ hasContentToExtract = true;
7672
+ }
7673
+ }
7674
+ } else if (container.nodeType === Node.ELEMENT_NODE) {
7675
+ if (offset < container.childNodes.length) {
7676
+ startNode = container.childNodes[offset];
7677
+ hasContentToExtract = true;
7678
+ } else if (offset === 0 && container === paragraph) {
7679
+ if (paragraph.firstChild) {
7680
+ startNode = paragraph.firstChild;
7681
+ hasContentToExtract = true;
7682
+ }
7683
+ }
7684
+ }
7685
+ if (!hasContentToExtract || !startNode) {
7686
+ return fragment;
7687
+ }
7688
+ if (!paragraph.contains(startNode)) {
7689
+ return fragment;
7690
+ }
7691
+ try {
7692
+ extractRange.setStartBefore(startNode);
7693
+ let lastNode = paragraph.lastChild;
7694
+ while (lastNode && lastNode.nodeType === Node.TEXT_NODE && lastNode.textContent === "" && // 只跳过完全空的文本节点
7695
+ lastNode !== startNode) {
7696
+ lastNode = lastNode.previousSibling;
7697
+ }
7698
+ if (lastNode) {
7699
+ extractRange.setEndAfter(lastNode);
7700
+ } else {
7701
+ extractRange.setEnd(paragraph, paragraph.childNodes.length);
7702
+ }
7703
+ const extractedContent = extractRange.extractContents();
7704
+ fragment.appendChild(extractedContent);
7705
+ } catch (e) {
7706
+ let currentNode = startNode;
7707
+ while (currentNode && currentNode.parentNode === paragraph) {
7708
+ const nextNode = currentNode.nextSibling;
7709
+ fragment.appendChild(currentNode);
7710
+ currentNode = nextNode;
7711
+ }
7712
+ }
7713
+ return fragment;
7714
+ },
7715
+ // 统一的光标设置方法 - 设置光标到元素后面
7716
+ setCursorAfterElement(element) {
7717
+ const newRange = document.createRange();
7718
+ newRange.setStartAfter(element);
7719
+ newRange.collapse(true);
7720
+ const selection = window.getSelection();
7721
+ selection.removeAllRanges();
7722
+ selection.addRange(newRange);
7723
+ },
7724
+ // 统一的光标设置方法 - 设置光标到元素前面
7725
+ setCursorBeforeElement(element) {
7726
+ const newRange = document.createRange();
7727
+ newRange.setStartBefore(element);
7728
+ newRange.collapse(true);
7729
+ const selection = window.getSelection();
7730
+ selection.removeAllRanges();
7731
+ selection.addRange(newRange);
6421
7732
  }
6422
7733
  },
6423
7734
  beforeRouteLeave(to, from, next) {
@@ -6440,11 +7751,12 @@
6440
7751
  const _component_ImgUpload = vue.resolveComponent("ImgUpload");
6441
7752
  const _component_VideoUpload = vue.resolveComponent("VideoUpload");
6442
7753
  const _component_CollectArticle = vue.resolveComponent("CollectArticle");
7754
+ const _component_TopicManager = vue.resolveComponent("TopicManager");
6443
7755
  return vue.openBlock(), vue.createElementBlock("div", _hoisted_1, [
6444
7756
  vue.withDirectives(vue.createElementVNode("div", {
6445
7757
  style: vue.normalizeStyle({ textAlign: $options.align }),
6446
7758
  class: "placeholder"
6447
- }, " 请输入正文 ", 4), [
7759
+ }, vue.toDisplayString($props.placeholder || "请输入正文"), 5), [
6448
7760
  [vue.vShow, !$options.isInputing && !$data.titleCount && !$data.hasArticleCard]
6449
7761
  ]),
6450
7762
  $data.overLine ? (vue.openBlock(), vue.createElementBlock("div", {
@@ -6570,7 +7882,14 @@
6570
7882
  class: "replace-poster hide",
6571
7883
  accept: "image/*",
6572
7884
  onChange: _cache[13] || (_cache[13] = (...args) => $options.replacePoster && $options.replacePoster(...args))
6573
- }, null, 32)
7885
+ }, null, 32),
7886
+ vue.createVNode(_component_TopicManager, {
7887
+ ref: "topicManager",
7888
+ "editor-dom": $data.editorDom,
7889
+ request: $props.request,
7890
+ onTopicInserted: $options.onTopicInserted,
7891
+ onUpdateTopicPosition: $options.updateTopicPosition
7892
+ }, null, 8, ["editor-dom", "request", "onTopicInserted", "onUpdateTopicPosition"])
6574
7893
  ]);
6575
7894
  }
6576
7895
  const Editor = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
@@ -6981,17 +8300,6 @@
6981
8300
  child = children[i];
6982
8301
  isBR = child.nodeName === "BR";
6983
8302
  if (!isBR && isInline(child)) {
6984
- if (child.classList && child.classList.contains("halo-picture-area")) {
6985
- return;
6986
- }
6987
- if (!wrapper) {
6988
- wrapper = createElement(
6989
- doc2,
6990
- config.blockTag,
6991
- config.blockAttributes
6992
- );
6993
- }
6994
- wrapper.appendChild(child);
6995
8303
  i -= 1;
6996
8304
  l -= 1;
6997
8305
  } else if (isBR || wrapper) {