Table-Copy

Select the data in each column of the table to merge and copy to the pasteboard

คุณจะต้องติดตั้งส่วนขยาย เช่น Tampermonkey, Greasemonkey หรือ Violentmonkey เพื่อติดตั้งสคริปต์นี้

คุณจะต้องติดตั้งส่วนขยาย เช่น Tampermonkey หรือ Violentmonkey เพื่อติดตั้งสคริปต์นี้

คุณจะต้องติดตั้งส่วนขยาย เช่น Tampermonkey หรือ Violentmonkey เพื่อติดตั้งสคริปต์นี้

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name:zh-CN   复制表格数据
// @name         Table-Copy
// @namespace    https://github.com/denglijuan/TamperMonkey
// @version      1.3.1
// @description:zh-CN 选择表格每列数据合并并复制到粘贴板上
// @description  Select the data in each column of the table to merge and copy to the pasteboard
// @author       Denglijuan
// @match        https://wiki.qianxin-inc.cn/*
// @grant        GM_addStyle
// @grant        GM_setClipboard
// @license      MIT
// ==/UserScript==

(function () {
  'use strict';

  let isFrist = true;
  let cols = []; // 选择复制列
  let tabelElement = null;
  let isCopyLeave = true;
  let isTheadLeave = true;
  let timer = null;

  // 复制到粘贴板
  function copy(data) {
    GM_setClipboard(data);

    // 原生写法
    // const textarea = document.createElement('textarea');
    // document.body.appendChild(textarea);
    // textarea.value = data;
    // textarea.setAttribute('style', 'display:node');
    // textarea.select();
    // document.execCommand('copy');
    // document.body.removeChild(textarea);
  }

  // 处理数据
  function handleData(data) {
    const newData = data
      .map((item) => {
        const newItem = item.filter(
          (element, index) => element.trim() !== '' && cols.includes(index + 1)
        );

        return [...new Set(newItem)].join('-');
      })
      .join('\r\n');

    copy(newData);
  }

  // 获取 tbody 元素,获取元素文本
  function handlerTbody() {
    const tbody = tabelElement.querySelector('tbody');
    const trs = tbody.childNodes;
    const trsLen = trs.length;
    const max = Math.max(...cols);
    const data = new Array(trsLen)
      .fill(0)
      .map(() => new Array(max).fill(undefined));

    // 遍历 tr
    for (let i = 0; i < trsLen; i++) {
      const tds = trs[i].childNodes;
      let colsIndex = 0; // cols 下标

      // 遍历 td
      for (let j = 0; colsIndex < max; j++) {
        let colspan = +(tds[j].getAttribute('colspan') || 1);
        let rowspan = +(tds[j].getAttribute('rowspan') || 1);
        const text = tds[j].innerText;
        const newText = text.replace(/\n/g, '');

        while (data[i][colsIndex] !== undefined) {
          colsIndex++;
        }

        for (let p = i; p < i + rowspan; p++) {
          data[p].fill(newText, colsIndex, colsIndex + colspan);
        }

        colsIndex += colspan;
      }
    }

    handleData(data);
  }

  // 校验输入框数据
  function validatorCloumns(value) {
    const reg = /^(\d*[,|,]?)*$/;
    cols = [];

    if (value === '') {
      return;
    }

    if (!reg.test(value)) {
      window.alert('请输入合法的参数');
      return;
    }

    value.split(/,|,/).forEach((item) => {
      cols.push(Number(item));
    });

    cols = [...new Set(cols)]; // 去重
    return true;
  }

  function handlerCopyIcon(event) {
    const target = event.target;
    let svgElement = target;

    if (svgElement.nodeName === 'path') {
      svgElement = svgElement.parentElement;
    }

    const input = svgElement.previousElementSibling;
    const result = validatorCloumns(input.value);
    result && handlerTbody();
  }

  // 给图标创建事件
  function createIconEventListener() {
    const copyIcon = document.querySelector('.d-copy-table__icon');
    copyIcon.addEventListener('click', handlerCopyIcon);
  }

  // 展示复制列元素
  function showCopyElement(top, left) {
    const copy = document.querySelector('.d-copy-table__copy');
    copy.style.display = 'block';

    // 减去元素高度
    copy.style.top = top - 35 + 'px';
    copy.style.left = left - 134 + 'px';
  }

  // 隐藏复制列元素
  function hideCopyElement() {
    const copy = document.querySelector('.d-copy-table__copy');
    copy.style.display = 'none';
  }

  // 判断是否要隐藏复制列元素
  function checkHide() {
    setTimeout(function () {
      if (isTheadLeave && isCopyLeave) {
        hideCopyElement();
      }
    }, 1);
  }

  // 处理表头移除事件
  function handlerTheadMouseleave() {
    isTheadLeave = true;
    checkHide();
  }

  // 处理表头移入事件
  function handlerTheadMouseenter(event) {
    const target = event.target;
    const position = target.getBoundingClientRect();
    const top = position.top;
    const left = position.right;
    isTheadLeave = false;
    tabelElement = target.parentElement;
    showCopyElement(top, left);
  }

  // 添加表格悬浮事件
  function createTheadEventListener() {
    const theads = document.querySelectorAll('thead');
    for (let i = 0; i < theads.length; i++) {
      theads[i].addEventListener('mouseenter', handlerTheadMouseenter);
      theads[i].addEventListener('mouseleave', handlerTheadMouseleave);
    }
  }

  //复制移出事件
  function handleCopyLeave() {
    isCopyLeave = true;
    checkHide();
  }

  // 复制移入事件
  function handleCopyEnter() {
    isCopyLeave = false;
  }

  // 添加复制列悬浮事件
  function createCopyEventListener() {
    const copy = document.querySelector('.d-copy-table__copy');
    copy.addEventListener('mouseenter', handleCopyEnter);
    copy.addEventListener('mouseleave', handleCopyLeave);
  }

  // checkbox 处理事件
  function handlerCheckBox(event) {
    const target = event.target;
    const value = target.checked;
    if (value) {
      if (isFrist) {
        // 初始化表头鼠标移入移出事件
        createTheadEventListener();
        isFrist = false;
      }
    } else {
      hideCopyElement();
    }
  }

  // 创建复选框 change 事件
  function createCheckBoxChangeEventListener() {
    const checkBox = document.querySelector('.d-copy-table__checkbox');
    checkBox.addEventListener('change', handlerCheckBox);
  }

  // 创建启动复制元素
  function createCheckBoxElement() {
    const checkBox = document.createElement('input');
    checkBox.setAttribute('type', 'checkbox');
    checkBox.setAttribute('class', 'd-copy-table__checkbox');
    return checkBox;
  }

  // 创建复制表格元素
  function createCopyTableElement() {
    const div = document.createElement('div');
    const template = `<input type="text" value="1,2,3" class="d-copy-table__input" />
    <svg t="1670157694323" class="d-copy-table__icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2684" width="20" height="20"><path d="M672 832 224 832c-52.928 0-96-43.072-96-96L128 160c0-52.928 43.072-96 96-96l448 0c52.928 0 96 43.072 96 96l0 576C768 788.928 724.928 832 672 832zM224 128C206.368 128 192 142.368 192 160l0 576c0 17.664 14.368 32 32 32l448 0c17.664 0 32-14.336 32-32L704 160c0-17.632-14.336-32-32-32L224 128z" p-id="2685" fill="#cdcdcd"></path><path d="M800 960 320 960c-17.664 0-32-14.304-32-32s14.336-32 32-32l480 0c17.664 0 32-14.336 32-32L832 256c0-17.664 14.304-32 32-32s32 14.336 32 32l0 608C896 916.928 852.928 960 800 960z" p-id="2686" fill="#cdcdcd"></path><path d="M544 320 288 320c-17.664 0-32-14.336-32-32s14.336-32 32-32l256 0c17.696 0 32 14.336 32 32S561.696 320 544 320z" p-id="2687" fill="#cdcdcd"></path><path d="M608 480 288.032 480c-17.664 0-32-14.336-32-32s14.336-32 32-32L608 416c17.696 0 32 14.336 32 32S625.696 480 608 480z" p-id="2688" fill="#cdcdcd"></path><path d="M608 640 288 640c-17.664 0-32-14.304-32-32s14.336-32 32-32l320 0c17.696 0 32 14.304 32 32S625.696 640 608 640z" p-id="2689" fill="#cdcdcd"></path></svg>`;
    div.classList.add('d-copy-table__copy');
    div.innerHTML = template;
    return div;
  }

  function createEditEventListener() {
    const edit = document.querySelector('#editPageLink');
    const handler = function () {
      const copy = document.querySelector('.d-copy-table__checkbox');
      copy.style.display = 'none';
    };
    edit.addEventListener('click', handler);
  }

  // 初始元素
  function initElement() {
    const copyElement = createCopyTableElement();
    const checkBoxElement = createCheckBoxElement();
    document.body.appendChild(copyElement);
    document.body.appendChild(checkBoxElement);
  }

  // 加载样式
  function loadStyle() {
    const css = `
          .d-copy-table__copy{
            position: fixed;
            z-index: 999;
            display: none;
            padding: 5px;
            border-radius: 4px;
            border: 1px solid #C1C7D0;
            background-color: white;
          }
          .d-copy-table__input{
            width: 80px;
            height: 20px;
            padding: 0 8px;
            border-radius: 3px;
            border: 1px solid #ccc;
            color: #333;
          }
          .d-copy-table__icon{
            vertical-align: middle;
            cursor: pointer;
          }
          .d-copy-table__checkbox{
            position: fixed;
            bottom: 16px;
            right: 16px;
          }
        `;
    GM_addStyle(css);
  }

  timer = setInterval(function () {
    const tableWrap = document.querySelector('.table-wrap');
    if (tableWrap) {
      clearInterval(timer);
      loadStyle();
      initElement();
      createEditEventListener();
      createCopyEventListener();
      createCheckBoxChangeEventListener();
      createIconEventListener();
    }
  }, 500);

  setTimeout(function () {
    clearInterval(timer);
  }, 6000);
})();