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