<!-- 标引操作页面 -->
<template>
  <div>
    <el-button type="primary" @click="backAction" link>返回</el-button>
    <div class="container">
      <!-- 新增 -->
      <div class="h-flex">
        <!--左侧知识结构-->
        <ul class="h-flex width200 mr-10">
          <li v-for="(item, index) in obj.knowledge" :key="item.uuid" :data-uuid="item.uuid">
            <span @click="checkListFn(item)">{{ index + 1 }}. {{ item.content }}</span>
            <el-icon v-if="item.content" @click="deleteLabelBlock(item)"><Delete /></el-icon>
          </li>
        </ul>
        <TreeFilter
          style="opacity: 0"
          ref="treeFilterRef"
          title="日志列表"
          :request-api="getUserDepartment"
          :default-value="initParam.deptId"
          @change="changeTreeFilter"
          :multiple="true"
        />
      </div>
      <div>
        <div
          ref="articleBody"
          :style="{ fontSize: getBodyFontSize + 'px' }"
          class="article"
          @mousedown="startSelection"
          v-html="showHtml"
        ></div>
        <section>
          <el-button type="primary" @click="endSelection('中医理论', 'red', '八宝串')" class="mr-10"> 中医理论 </el-button>
          <el-button @click="endSelection('方剂', 'blue', '八宝')" class="mr-10"> 方剂 </el-button>
          <el-button @click="copySelectedCon" class="mr-10"> 选中文本复制到右侧 </el-button>
          <br />
          <el-button @click="modifyArticle" class="mr-10"> 修改原文 </el-button>
          <el-button @click="saveRightCon" class="mr-10"> 保存修改的文字1 </el-button>
        </section>
      </div>
      <div v-if="copySelectedConHtml" v-html="copySelectedConHtml" class="width300"></div>
      <div contenteditable="true" class="editable-div" v-text="modifyArticleHtml" id="editContent"></div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted, provide, computed } from "vue";
import { ElMessage } from "element-plus";
import { useRouter } from "vue-router";
import { usePageLeave } from "@/hooks/usePageLeave";
import { getUserDepartment } from "@/api/modules/system/user";
// import { ProTableInstance } from "@/components/ProTable/interface";
import TreeFilter from "@/components/TreeFilter/index.vue";
import { useGlobalStore } from "@/stores/modules/global";

// hooks
usePageLeave("TaskIndexData");

const globalStore = useGlobalStore();
const getBodyFontSize = computed(() => globalStore.getBodyFontSize);
// ProTable 实例
// const proTable = ref<ProTableInstance>();
const treeFilterRef = ref<typeof TreeFilter>();
provide("getDeptTree", () => {
  return treeFilterRef.value?.treeAllData.filter((item: any) => item.id > 0);
});
const initParam = reactive({ deptId: "" });

// 树形筛选切换
const changeTreeFilter = (val: string) => {
  // proTable.value!.pageable.pageNum = 1;
  initParam.deptId = val;
};

const obj = reactive({
  // 选中区域文本
  text: "html",
  // 目录
  directory: [
    {
      // 自身 id
      id: "",
      // 内容
      content: "",
      // 上级 id 如果为 0 则是顶层 id
      proId: "",
      // 类型 章/书/卷/序
      type: "",
      // 目录名称
      name: "xxxx",
      // 上级 name
      proName: "",
      // 子集
      children: []
    }
  ],
  // 知识体
  knowledge: [
    {
      uuid: "5FA9EAD1075B7325",
      // 自身 id
      id: "",
      // 内容
      content: "xxx",
      // 方剂
      type: "",
      // 目录名称
      name: "xxxx",
      // 标签
      tag: [
        {
          // 八宝串
          content: "",
          // 八宝串
          type: "",
          // 方名
          name: "",
          // 多选标签
          checkbox: []
        }
      ],
      // 关联 后端定义
      association: []
    }
  ]
});
const showHtml = ref(
  "<p>洒满星星的河流我已经远离了你的河流，《绝不是》疏远，我已是身居异土。远远地，依然听得到你翻山越岭、日夜兼程的脚步声，依然无比清晰地看得到你的那条洒满星星的清澈的河流。只要，也只有想起你——故乡，就是异域的那条河流也会洒满故乡的星星。无论醒着还是沉睡，都会重复着那个让人心旌摇曳的画面，星星都在你的河流里百媚地眨眼。因为那条洒满星星的河流途经我无猜的孩童，无知的少年，迷茫的青春，还要经过可知的未来，是不是今后还要交付给大海了呢？那样，大海的那些星星一定是故乡送给他们的馈赠，没乡的孕育，大海也会失去灵气，因为大海的源头就在故乡的这头……</p>"
);
// const selectedText = ref("");
const copySelectedConHtml = ref(""); // 选中文字复制展示
const modifyArticleHtml = ref(""); // 修改文章
// const modifyArticleTag = ref("");
const currentText = ref(""); // 记录当前选中的文字
const rangeObj = ref(null);

function startSelection() {
  console.log("startSelection");
}
// useHooks
const router = useRouter();
// 返回
function backAction() {
  router.back();
}
// 监听文本选择变化
function handleSelectionChange() {
  const selection = window.getSelection();
  console.log("监听文本选择变化-selection", selection);
  console.log("监听文本选择变化-selection.rangeCount", selection.rangeCount);
  if (selection.rangeCount > 0) {
    // console.log('selection.anchorNode', selection.anchorNode);
    // 属性和定于与extentNode完全一致
    // console.log('selection.focusNode', selection.focusNode);
    // :获取指定的选取范围。
    const range = selection.getRangeAt(0); // 把选中的文字转化为range对象，可以进行操作。接受一个参数，一般填写为0，表示从selection对象的0开是进行转化;
    // 选中的文本
    return range.toString();
  }
}

/**
 * 选中文字添加标签
 * @param itemText
 * @param colorVal
 * @param alias 别名
 */
function endSelection(itemText, colorVal, alias) {
  // 同样，这里可能也不需要特定操作
  // 但我们可以调用handleSelectionChange来检查是否有文本被选中
  // 获取当前选中的文本范围
  const selection = window.getSelection();
  const text = handleSelectionChange();
  // 生成ID 内容no-select
  const addData = {
    uuid: uuid(),
    content: text
  };
  if (!text) {
    ElMessage.warning("未选中文字!");
    return;
  }
  console.log("selection", selection);
  // 如果没有选中的文本，则直接返回
  if (selection.rangeCount === 0) return;

  // 判断复制文字正确性
  if (!checkPairedBrackets(text)) {
    ElMessage.warning("选中的内容不对");
    return;
  }

  const range = selection.getRangeAt(0); // 获取第一个范围
  const selectedTextNode = range.cloneContents(); // 克隆选中的内容

  // 创建前置标签和后置标签
  const beforeTag = document.createElement("i");
  const afterTag = document.createElement("i");

  const tag = "span";
  // 使用DOM操作将选中的内容移动到新创建的元素中
  const span = document.createElement(tag);

  // 正常标签/开放标签[中间用空格间隔开] <中医理论></中医理论> <中医理论 ABCD></中医理论>
  // beforeTag.textContent = `<${itemText} ${alias}>`;
  beforeTag.innerHTML = `<<span class="no-select">${itemText} ${alias}</span>>`;

  // 用于标签使用
  const tagClassName = `i-${addData.uuid}`;
  beforeTag.classList.add(tagClassName);
  afterTag.classList.add(tagClassName);

  span.appendChild(beforeTag);
  span.appendChild(selectedTextNode);
  span.appendChild(document.createTextNode(" ")); // 添加空格，避免连续的标签
  // afterTag.textContent = `</${itemText}>`;
  afterTag.innerHTML = `&lt;/<span class="no-select">${itemText}</span>>`;

  span.appendChild(afterTag);

  // 使用DOM操作将原来的选区内容（range）替换为我们创建的span元素
  range.deleteContents(); // 删除原来的选中内容
  range.insertNode(span); // 插入新的span元素

  // 因为我们已经修改了DOM，需要将当前选区清除
  selection.removeAllRanges();

  span.setAttribute("data-uuid", addData.uuid);
  span.setAttribute("id", `type-${addData.uuid}`);
  // 使用querySelectorAll方法获取所有符合条件的i标签
  const iElements = document.getElementsByClassName(tagClassName);
  const getColor = getRandomColor();
  for (let i = 0; i < iElements.length; i++) {
    addRandomColor(iElements[i], getColor);
    // addRandomColor(iElements[i], colorVal);
  }
  obj.knowledge.push({ ...addData });
}

// 知识结构选择
function checkListFn(item) {
  // 去赋值右侧内容选中
  const { uuid } = item;
  const tagIdName = `#type-${uuid}`;
  const selectAll = document.querySelector(tagIdName);
  const selObj = window.getSelection();
  selObj.selectAllChildren(selectAll);
}

// 删除已添加的标签包裹
function deleteLabelBlock(item) {
  // 获取标签
  const tagIdName = `type-${item.uuid}`;
  const elementToReplace = document.getElementById(tagIdName);
  if (elementToReplace) {
    // 选择父元素
    const parentElement = elementToReplace.parentNode;
    // 将要替换元素的子元素克隆以避免在转移过程中丢失
    const children = Array.from(elementToReplace.childNodes);

    // 在元素位置逐个插入子元素
    children.forEach((child, index) => {
      if (index === 0 || children.length === index + 1) return;
      parentElement.insertBefore(child, elementToReplace);
    });
    // 删除原来的元素
    parentElement.removeChild(elementToReplace);
  }
  const index = obj.knowledge.findIndex(i => i.uuid === item.uuid);
  if (index !== -1) {
    obj.knowledge.splice(index, 1);
  }
}

// 复制文本到新的窗口展示
function copySelectedCon() {
  const resultText = getSelectedText(); // 获取选中的文本
  // 检查文本是否为空且标签是否成对出现
  if (!resultText || !checkPairedBrackets(resultText)) {
    ElMessage.warning(resultText ? "复制的内容不对" : "复制的内容为空");
    return;
  }
  copySelectedConHtml.value = getSelectedTextHTML();
}
// 修改原文，判断需选中最小标签节点
async function modifyArticle() {
  // <中医理论 八宝串>无论醒着还是沉睡 </中医理论>
  const resultText = await getSelectedText();
  console.log("resultText", resultText);
  if (!resultText) {
    ElMessage.warning("选中的内容为空");
  }
  let left = "<";
  let right = ">";
  let rightStart = "</";
  if (resultText.indexOf(`${left}`) > -1 || resultText.indexOf(`${right}`) > -1 || resultText.indexOf(`${rightStart}`) > -1) {
    ElMessage.warning("选中的内容不符合特定规则");

    return false;
  }
  rangeObj.value = window.getSelection().getRangeAt(0);
  modifyArticleHtml.value = resultText;

  // 截取中间内容展示 eg：<方剂 八宝>孩童，无知的少年 </方剂>
  // modifyArticleHtml.value = resultText.substring(resultText.indexOf(">") + 1, resultText.indexOf("</"));

  currentText.value = resultText;
  // js 获取字符串里面包含的标签属性
  // <i class="i-8085E119EA7D8015" style="color: rgb(198, 9, 195);">&lt;中医理论 八宝串&gt;</i>为大海的源头就在故 <i class="i-8085E119EA7D8015" style="color: rgb(198, 9, 195);">&lt;/中医理论&gt;</i>
  // const tagHtml = getSelectedTextHTML();
  // console.log("tagHtml", tagHtml);

  // // 处理类名
  // // 使用正则表达式匹配<i>标签的class属性值
  // const regex = /<i\s+[^>]*?class\s*=\s*['"]([^'"]*)['"]/gi;
  // let match;
  // let classValues = [];
  // console.log("regex.exec(getSelectedTextHTML())", regex.exec(tagHtml));

  // while ((match = regex.exec(tagHtml)) !== null) {
  //   // match[1]是捕获组中的内容，即class属性的值
  //   classValues.push(match[1]);
  // }
  // console.log(classValues);
  // // const classValues = Array.from(firstElement.classList).map(cls => cls.trim());
  // if (classValues.length > 0) {
  //   modifyArticleTag.value = classValues[0];
  // } else {
  //   modifyArticleTag.value = null; // 或其他默认值
  // }

  // // 查找最近的父级元素及其 ID（这里假设有特定的 ID 格式）
  // const tagIdName = `type-${modifyArticleTag.value.split("-")[1]}`;
  // const elementToReplace = document.getElementById(tagIdName);
  // if (elementToReplace) {
  //   console.log("parentNode", elementToReplace.parentNode);
  //   console.log("parentNode-getAttribute", elementToReplace.parentNode.getAttribute("data-uuid"));
  // } else {
  //   console.log("未找到对应的父级元素");
  // }
}
// 修改文字保存
function saveRightCon() {
  console.log("rangeObj", rangeObj);
  // 获取当前编辑框的文本内容

  const textNode = document.getElementById("editContent").textContent;

  // 检查文本是否发生变化
  console.log("currentText", currentText.value);
  console.log("textNode", textNode);

  if (currentText.value === textNode) {
    ElMessage.warning("内容未变化！");
    return;
  }
  rangeObj.value.deleteContents(); // 删除选中的文本
  // const newTextNode = document.createTextNode(textNode); // 创建新的文本节点
  const span = document.createElement("span");
  span.className = "highlight";
  span.textContent = textNode; // 这里可以替换为你想要的任何文本

  rangeObj.value.insertNode(span); // 将新文本插入到选区

  // // 提取标签ID
  // const tagIdName = `type-${modifyArticleTag.value?.split("i-")[1]}`;
  // // 获取需要替换的DOM元素
  // const elementToReplace = document.getElementById(tagIdName);

  // if (elementToReplace) {
  //   // 假设我们只需要更新elementToReplace的某个特定子元素（例如第二个子元素）的文本
  //   // 这里假设第二个子元素是我们需要更新的（index = 1）
  //   const children = elementToReplace.childNodes;
  //   if (children.length > 1) {
  //     // 直接设置第二个子元素的文本内容
  //     children[1].textContent = textNode;
  //   } else {
  //     // 如果子元素不足两个，可能需要添加新的元素或进行其他处理
  //     console.log("元素子节点不足两个，可能需要添加新元素");
  //   }
  // } else {
  //   console.log("未找到对应的DOM元素");
  // }
}
// 检验复制的内容是否是标签包含正确
function checkPairedBrackets(text) {
  let left = "<";
  let right = ">";
  // /<|>/g 识别标签
  let regIdentifyTags = new RegExp(`${left}|${right}`, "g"); // 匹配文本中的所有尖括号
  // /<(.*?)>/g 识别内容
  let regIdentifyContent = new RegExp(`${left}(.*?)${right}`, "g");
  let str = "";
  text.replace(regIdentifyTags, x => (str += x));
  console.log("str", str);
  // 校验 << >> 标签错的情况， 校验是否存在连续的尖括号，存在返回false
  if (
    str.indexOf(`${left}${left}`) > -1 ||
    str.indexOf(`${right}${right}`) > -1 ||
    str[0] === right ||
    str[str.length - 1] === left
  ) {
    return false;
  }
  // 判断标签 栈
  let tagList = [];
  for (let i = 0; i < str.length; i++) {
    // 判断匹配left
    if (str[i] === left) tagList.push(tagList[i]);
    // 判断匹配right
    if (str[i] === right) {
      const tag = tagList.pop();
      if (tag === right) return false;
    }
  }
  // 最后栈里还有值，则是未匹配完成
  if (tagList.length) return false;

  // 判断内容
  // 校验是否闭合
  let show = true;
  // 栈
  let stack = [];
  text.replace(regIdentifyContent, (x, y) => {
    if (!show) return;
    // 闭合标签
    if (y.indexOf("/") === 0) {
      let v = stack.pop(); // 抛出最后一个
      if (`/${v}` !== y) {
        show = false;
      }
    } else {
      // 开放标签 <中医理论 ABCD></中医理论>
      if (y.indexOf(" ") > -1) {
        stack.push(y.split(" ")[0]);
        return;
      }
      stack.push(y);
    }
  });
  console.log("stack", stack);
  // 如果栈为空，则所有《都有对应的》
  return show && stack.length === 0;
}
// 优化后
// 优化说明：
// 正则表达式：我使用了一个更复杂的正则表达式来匹配标签，它可以处理自闭合标签（如 <img />）、带属性的标签（如 <div class="test">），并捕获标签名以进行后续比较。
// 栈的使用：使用栈来跟踪未闭合的标签。每当遇到一个打开标签时，将其标签名推入栈中；每当遇到一个闭合标签时，从栈中弹出一个标签名并进行比较。
// 直接处理：直接对文本进行遍历和处理，而不是先提取所有标签到一个字符串中。这样做可以更高效地处理文本，并避免不必要的字符串操作。
// 错误处理：如果栈为空但遇到了闭合标签，或者栈顶标签与闭合标签不匹配，则返回 false。
// 性能：由于只遍历文本一次，并且使用高效的栈操作，该函数的性能应该相当不错。
// function checkPairedBrackets(text) {
//   const left = "<";
//   const right = ">";
//   // 栈用于跟踪未闭合的标签
//   let stack = [];

//   // 正则表达式匹配标签（包括可能的自闭合标签和带属性的标签）
//   const regIdentifyTags = new RegExp(`(${left}(?:\\/?[a-zA-Z0-9]+(?:\\s+[a-zA-Z0-9-]+="[^"]*")*)?${right})`, "g");

//   let match;
//   while ((match = regIdentifyTags.exec(text)) !== null) {
//     const tag = match[0];
//     const isClosing = tag.startsWith('</');
//     const tagName = tag.slice(isClosing ? 2 : 1, tag.indexOf(' ', isClosing ? -1 : tag.indexOf('>')));

//     // 处理打开标签
//     if (!isClosing) {
//       stack.push(tagName);
//     } else {
//       // 处理闭合标签
//       if (stack.length === 0) return false; // 没有对应的打开标签
//       if (stack.pop() !== tagName) return false; // 标签不匹配
//     }
//   }

//   // 检查栈是否为空，如果为空则所有标签都已正确闭合
//   return stack.length === 0;
// }

// // 示例
// console.log(checkPairedBrackets("<html><head><title>Test</title></head><body></body></html>")); // true
// console.log(checkPairedBrackets("<div><p>Hello</div>")); // false, 因为 <p> 没有闭合
// console.log(checkPairedBrackets("<div><p>Hello</p></div>")); // true
// console.log(checkPairedBrackets("<div></p>")); // false, 因为 <div> 和 </p> 不匹配

// 是否前后标签匹配111
// function checkPairedBrackets1(text) {
//   const left = "<";
//   const right = ">";
//   // /<|>/g 识别标签
//   const regIdentifyTags = new RegExp(`${left}|${right}`, "g"); // 匹配文本中的所有尖括号
//   // /<(.*?)>/g 识别内容
//   const regIdentifyContent = new RegExp(`${left}(.*?)${right}`, "g");
//   let str = "";
//   text.replace(regIdentifyTags, x => (str += x));
//   console.log("str", str);
//   // 校验 << >> 标签错的情况， 校验是否存在连续的尖括号，存在返回false
//   if (
//     str.indexOf(`${left}${left}`) > -1 ||
//     str.indexOf(`${right}${right}`) > -1 ||
//     str[0] === right ||
//     str[str.length - 1] === left
//   ) {
//     return {
//       type: 1,
//       message: "标签错误",
//       state: "error"
//     };
//   }
//   // 判断标签 栈
//   const tagList = [];
//   for (let i = 0; i < str.length; i++) {
//     // 判断匹配left
//     if (str[i] === left) tagList.push(tagList[i]);
//     // 判断匹配right
//     if (str[i] === right) {
//       const tag = tagList.pop();
//       if (tag === right) {
//         return {
//           type: 1,
//           message: "标签错误",
//           state: "error"
//         };
//       }
//     }
//   }
//   // 最后栈里还有值，则是未匹配完成
//   if (tagList.length) {
//     return {
//       type: 1,
//       message: "标签错误",
//       state: "error"
//     };
//   }

//   // 判断内容
//   // 校验是否闭合
//   let show = true;
//   // 栈
//   const stack = [];
//   // 消了多少个标签
//   let stackIndex = 0;
//   text.replace(regIdentifyContent, (x, y) => {
//     // 闭合标签
//     if (y.indexOf("/") === 0) {
//       const v = stack.pop(); // 抛出最后一个
//       stackIndex++;
//       if (`/${v}` !== y && !show) {
//         show = false;
//       }
//     } else {
//       // 开放标签 <中医理论 ABCD></中医理论>
//       if (y.indexOf(" ") > -1) {
//         stack.push(y.split(" ")[0]);
//         return;
//       }
//       stack.push(y);
//     }
//   });
//   // 如果栈为空，则所有《都有对应的》
//   if (!show) {
//     return {
//       type: 2,
//       message: "标签闭合性错误",
//       state: "error",
//       stackIndex: stackIndex + stack.length
//     };
//   }
//   if (stack.length > 0) {
//     return {
//       type: 2,
//       message: "多个标签问题",
//       state: "error",
//       stackIndex: stackIndex + stack.length
//     };
//   }
//   return {
//     type: 3,
//     message: "校验成功！",
//     state: "success"
//   };
// }
onMounted(() => {
  // console.log("你的河<方剂 八宝>流里 </方剂>百", checkPairedBrackets1("你的河<方剂 八宝>流里 </方剂>百"));
  // console.log("你的河<方剂 八宝>", checkPairedBrackets1("你的河<方剂 八宝>"));
  // console.log("<方剂 八宝>流里 </方剂>百", checkPairedBrackets1("<方剂 八宝>流里 </方剂>百"));
  // console.log("12<方剂 八宝>流里 </方剂>百", checkPairedBrackets1("12<方剂 八宝>流里 </方剂>百"));
  // console.log(
  //   "<中医理论 八宝串>你的河<方剂 八宝>流里 </方剂>百媚地 </中医理论>",
  //   checkPairedBrackets1("<中医理论 八宝串>你的河<方剂 八宝>流里 </方剂>百媚地 </中医理论>")
  // );
  // console.log(
  //   "<中医理论 八宝串>你的河<方剂 八宝>流里 </方剂>百媚地 </中医理论>222",
  //   checkPairedBrackets1("<中医理论 八宝串>你的河<方剂 八宝>流里 </方剂>百媚地 </中医理论>222")
  // );
});

// function checkCustomTagConsistency(text) {
//   console.log("是否前后标签匹配text", text);
//   let left = "<";
//   let right = ">";
//   // /<|>/g 识别标签
//   let regIdentifyTags = new RegExp(`${left}|${right}`, "g");
//   // /<(.*?)>/g 识别内容
//   let regIdentifyContent = new RegExp(`${left}(.*?)${right}`, "g");
//   let str = "";
//   text.replace(regIdentifyTags, x => (str += x));
//   console.log("checkCustomTagConsistency-str", str);
//   // 校验 << >> 标签错的情况， 校验是否存在连续的尖括号，存在返回false
//   if (
//     str.indexOf(`${left}${left}`) > -1 ||
//     str.indexOf(`${right}${right}`) > -1 ||
//     str[0] === right ||
//     str[str.length - 1] === left ||
//     str[str.length - 1] !== right
//   ) {
//     return false;
//   }
//   // 判断标签 栈
//   let tagList = [];
//   for (let i = 0; i < str.length; i++) {
//     // 判断匹配left
//     if (str[i] === left) tagList.push(tagList[i]);
//     // 判断匹配right
//     if (str[i] === right) {
//       const tag = tagList.pop();
//       if (tag === right) return false;
//     }
//   }
//   // 最后栈里还有值，则是未匹配完成
//   if (tagList.length) return false;

//   // 校验是否闭合
//   let show = true;
//   // 栈
//   let stack = [];
//   text.replace(regIdentifyContent, (x, y) => {
//     if (!show) return;
//     // 闭合标签
//     if (y.indexOf("/") === 0) {
//       let v = stack[stack.length - 1];
//       if (`/${v}` !== y) {
//         show = false;
//       }
//       stack.push(y);
//     } else {
//       // 开放标签 <中医理论 ABCD></中医理论>
//       if (y.indexOf(" ") > -1) {
//         stack.push(y.split(" ")[0]);
//         return;
//       }
//       stack.push(y);
//     }
//   });
//   console.log("stack", stack);
//   console.log("`/${stack[0]}` === stack[1]", `/${stack[0]}` === stack[1]);
//   return show && `/${stack[0]}` === stack[1];
// }

/**
 * 获取选中内容的处理结果
 * @param {Function} transformer - 转换函数，接受一个 DOM 元素并返回所需的结果
 * @returns {string}
 */
function getSelectedContent(transformer) {
  const selection = window.getSelection();
  if (selection.rangeCount > 0) {
    const container = document.createElement("div");
    for (let i = 0; i < selection.rangeCount; i++) {
      container.appendChild(selection.getRangeAt(i).cloneContents());
    }
    // 可选：清除选取
    // selection.removeAllRanges();
    return transformer(container);
  }
  return "";
}

/**
 * 获取选中文字的 HTML
 * @returns {string}
 */
function getSelectedTextHTML() {
  return getSelectedContent(container => container.innerHTML);
}

/**
 * 获取选中文字的纯文本
 * @returns {string}
 */
function getSelectedText() {
  return getSelectedContent(container => container.innerText);
}
// 指定长度和基数
const uuid = (length = 16, radix = 16) => {
  const chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".slice(0, radix);
  let uuid = "";
  const bytes = Math.ceil((length * Math.log(radix)) / Math.log(256)) - 1;
  for (let i = 0; i < bytes; i++) {
    uuid += chars[Math.floor(Math.random() * radix)];
  }

  // 如果长度不是字节长度的整数倍，我们需要补充额外的字符以满足长度要求
  while (uuid.length < length) {
    uuid += chars[Math.floor(Math.random() * radix)];
  }

  return uuid;
};

/**
 * 随机颜色
 * @param element
 */
function addRandomColor(element, color) {
  element.style.color = color;
}

function getRandomColor() {
  const letters = "0123456789ABCDEF";
  let color = "#";
  for (let i = 0; i < 6; i++) {
    color += letters[Math.floor(Math.random() * 16)];
  }
  return color;
}
</script>
<style>
.no-select {
  user-select: none;
}
.highlight {
  color: red; /* 选中文本的颜色 */
}
</style>
<style scoped lang="scss">
ul,
li {
  list-style: none; /* 移除列表的默认项目符号 */
}
.container {
  display: flex;
  padding: 20px;
  margin: 0;
  .article {
    width: 400px;
    height: 440px;
    overflow-y: scroll;
    white-space: pre-wrap;
  }
}

/* 样式 */
// :root {
//   --global-text-selection-color: #ffffff; /* 文字选中颜色 */
//   --global-text-selection-bg: lightblue; /* 文字选中背景色 */
// }
p::selection {
  color: #ffffff;
  background: lightblue;
}
.article {
  font-size: 14px;
  cursor: text; /* 表明这个区域是可选择的 */
  user-select: text; /* 允许文本被选择 */
}
.h-flex {
  display: flex;
  flex-direction: column;
}
.width200 {
  width: 200px;
  word-break: break-all;
}
.width300 {
  width: 300px;
  word-break: break-all;
  border: 1px solid;
}
.mt-10 {
  margin-top: 10px;
}
.mr-10 {
  margin-right: 10px;
}
li {
  display: flex;
  align-items: center;
  cursor: pointer;
}
.editable-div {
  min-height: 50px;
  padding: 10px;
  border: 1px solid #000000;
}
</style>
