Greasy Fork is available in English.

WF ToolBox

Workflowy 插件集成

// ==UserScript==
// @name WF ToolBox
// @description Workflowy 插件集成
// @namespace https://github.com/bekafka/WorkflowyToolBox
// @version 20241129V0.6
// @author YYYYang
// @license MIT
// @match http://workflowy.com/*
// @match https://workflowy.com/*
// @match http://*.workflowy.com/*
// @match https://*.workflowy.com/*
// @icon  https://www.google.com/s2/favicons?sz=64&domain=workflowy.com
// @grant GM_setClipboard
// @grant GM_notification
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// @noframes
// ==/UserScript==

// 整体工具箱菜单代码来自 @稻米鼠(https://greasyfork.org/zh-CN/users/36055)的【洗白白插件】

/* 弹出通知 */
// const dmsCLNotification = function (text) {
//   GM_notification(text, 'Success! ', 'data:image/png;base64,iVxxxxxxxxxxxxxxxCYII=');
// };

/** 获取是否显示页面工具栏 **/
// SHow_page_bar 为外置插件变量
let isShowPageBar = GM_getValue('SHow_page_bar', true);

GM_registerMenuCommand('显示/隐藏页面工具条', () => {
  GM_setValue('SHow_page_bar', !isShowPageBar);
  isShowPageBar = GM_getValue('SHow_page_bar', true);
  alert(
    '页面工具条已被设置为【' +
    (isShowPageBar ? '显示' : '隐藏') +
    '】,仅在此后新打开页面中生效。'
  );
});


// ————————————————————————————


const Find_Replace = () => {
  // alert("查找与替换");

  (function FR_2_4() {
    function toastMsg(str, sec, err) {
      WF.showMessage(str, err);
      setTimeout(WF.hideMessage, (sec || 3) * 1000);
    }
    function applyToEachItem(functionToApply, parent) {
      functionToApply(parent);
      for (let child of parent.getChildren()) {
        applyToEachItem(functionToApply, child);
      }
    }
    function findMatchingItems(itemPredicate, parent) {
      const matches = [];
      function addIfMatch(item) {
        if (itemPredicate(item)) {
          matches.push(item);
        }
      }
      applyToEachItem(addIfMatch, parent);
      return matches;
    }
    function editableItemWithVisibleMatch(item) {
      const isVisible = WF.completedVisible() || !item.isWithinCompleted();
      return item.data.search_result && item.data.search_result.matches && isVisible && !item.isReadOnly()
    }
    const escapeForRegExp = str => str.replace(/[-\[\]{}()*+?.,\\^$|#]/g, "\\$&");
    function countMatches(items, rgx) {
      let matchCount = 0;
      items.forEach(item => {
        let result = item.data.search_result;
        if (result.nameMatches) {
          let nameMatch = item.getName().match(rgx);
          if (nameMatch) matchCount += nameMatch.length;
        }
        if (result.noteMatches) {
          let noteMatch = item.getNote().match(rgx);
          if (noteMatch) matchCount += noteMatch.length;
        }
      });
      return matchCount;
    }
    const htmlEscTextForContent = str => str.replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/\u00A0/g, "&nbsp;");
    function replaceMatches(items, rgx, r) {
      WF.editGroup(function () {
        items.forEach(item => {
          let result = item.data.search_result;
          if (result.nameMatches) WF.setItemName(item, item.getName().replace(rgx, htmlEscTextForContent(r)));
          if (result.noteMatches) WF.setItemNote(item, item.getNote().replace(rgx, htmlEscTextForContent(r)));
        });
      });
      r === "" ? WF.clearSearch() : WF.search(tQuery.replace(find, r));
    }
    const htmlEscText = str => str.replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
    function getColors() {
      const p = document.querySelector(".page.active");
      return p ? `color:${getComputedStyle(p).color};background:${getComputedStyle(p).backgroundColor};` : "";
    }
    function showFindReplaceDialog(BODY, TITLE, aCount, cCount, searchValue) {
      const addButton = (num, name) => `<button type="button" class="btnX" id="btn${num.toString()}">${name}</button>`;
      const boxStyle = `#inputBx{${getColors()}width:95%;height:20px;display:block;margin-top:5px;border:1px solid #ccc;border-radius:4px;padding:4px}`;
      const btnStyle = `.btnX{font-size:18px;background-color:gray;border:2px solid;border-radius:20px;color:#fff;padding:5px 15px;margin-top:16px;margin-right:16px}.btnX:focus,.btnX:hover{border-color:#c4c4c4;background-color:steelblue}`;
      const box = `<div><b>替换文本:</b><input value="${htmlEscText(searchValue)}" id="inputBx" type="text" spellcheck="false"></div>`;
      const buttons = addButton(1, `替换: 全部 (${aCount})`) + addButton(2, `替换: 区分大小写 (${cCount})`);
      WF.showAlertDialog(`<style>${boxStyle + btnStyle}</style><div>${BODY}</div>${box}<div>${buttons}</div>`, TITLE);
      const intervalId = setInterval(function () {
        let inputBx = document.getElementById("inputBx");
        if (inputBx) {
          clearInterval(intervalId);
          let userInput;
          const btn1 = document.getElementById("btn1");
          const btn2 = document.getElementById("btn2");
          inputBx.select();
          inputBx.addEventListener("keyup", function (event) {
            if (event.key === "Enter") {
              btn1.click();
            }
          });
          btn1.onclick = function () {
            userInput = inputBx.value;
            WF.hideDialog();
            setTimeout(function () {
              replaceMatches(Matches, rgx_gi, userInput)
            }, 50);
          };
          btn2.onclick = function () {
            userInput = inputBx.value;
            WF.hideDialog();
            setTimeout(function () {
              replaceMatches(Matches, rgx_g, userInput)
            }, 50);
          };
        }
      }, 50);
    }
    if (!WF.currentSearchQuery()) {
      return void toastMsg('请先使用搜索框键入关键词  ⇒  <a href="https://workflowy.com/s/findreplace-bookmark/ynKNSb5dA77p2siT" target="_blank">更多信息请查看</a>', 4, true);
    }
    const tQuery = WF.currentSearchQuery().trim();
    const Matches = findMatchingItems(editableItemWithVisibleMatch, WF.currentItem());
    const isQuoted = tQuery.match(/(")(.+)(")/);
    const find = isQuoted ? isQuoted[2] : tQuery.includes(" ") ? false : tQuery;
    if (find === false) {
      if (confirm('The search contains at least one space.\n\n1. Press OK to convert your search to "exact match".\n\n2. Activate Find/Replace again.')) {
        WF.search('"' + tQuery + '"');
      }
      return;
    }
    const title = "查找与替换 / Find&Replace";
    const modeTxt = isQuoted ? "Exact Match, " : "Single Word/Tag, ";
    const compTxt = `Completed: ${WF.completedVisible() ? "Included" : "Excluded"}`;
    const findTxt = isQuoted ? isQuoted[0] : tQuery;
    const body = `<p><b>模式 / Mode:</b><br>${modeTxt + compTxt}</p><p><b>匹配关键词 / Find:</b><br>${htmlEscText(findTxt)}</p>`;
    const findRgx = escapeForRegExp(htmlEscTextForContent(find));
    const rgx_gi = new RegExp(findRgx, "gi");
    const rgx_g = new RegExp(findRgx, "g");
    const allCount = countMatches(Matches, rgx_gi);
    const caseCount = countMatches(Matches, rgx_g);
    if (allCount > 0) {
      showFindReplaceDialog(body, title, allCount, caseCount, find);
    } else {
      WF.showAlertDialog(`${body}<br><br><i>😞 没有匹配的搜索结果。 / No matches found.</i>`, title);
    }
  })();

};

const WF_Sort = () => {
  // alert("WF节点排序");

  (function sortWF_4_0(maxChildren = 1000) {
    function toastMsg(str, sec, err) {
      WF.showMessage(str, err);
      setTimeout(WF.hideMessage, (sec || 2) * 1000);
    }

    function sortAndMove(items, reverse) {
      WF.hideDialog();
      setTimeout(() => {
        items.sort((a, b) => reverse ? b.getNameInPlainText().localeCompare(a.getNameInPlainText()) : a.getNameInPlainText().localeCompare(b.getNameInPlainText()));
        WF.editGroup(() => {
          items.forEach((item, i) => {
            if (item.getPriority() !== i) WF.moveItems([item], parent, i);
          });
        });
        // set focus to parent after sort
        WF.editItemName(parent);
        toastMsg(`已按 ${reverse ? "倒序(Z-A)" : "正序(A-Z)"} 进行重新排列`, 3)
      }, 50);
    }

    const htmlEscText = str => str.replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");

    function showSortDialog(bodyHtml, title) {
      const addButton = (num, name) => `<button type="button" class="btnX" id="btn${num.toString()}">${name}</button>`;
      const style = '.btnX{font-size:18px;background-color:gray;border:2px solid;border-radius:20px;color:#fff;padding:5px 15px;margin-top:16px;margin-right:16px}.btnX:focus,.btnX:hover{border-color:#c4c4c4;background-color:steelblue}';
      const buttons = addButton(1, "正序 A-Z") + addButton(2, "倒序 Z-A");

      WF.showAlertDialog(`<style>${htmlEscText(style)}</style><div>${bodyHtml}</div><div>${buttons}</div>`, title);

      const intervalId = setInterval(
        function () {
          let btn1 = document.getElementById("btn1");
          if (btn1) {
            clearInterval(intervalId);
            const btn2 = document.getElementById("btn2");
            // btn1.focus();
            btn1.onclick = function () { sortAndMove(children) };
            btn2.onclick = function () { sortAndMove(children, true) };
          }
        }, 50);
    }

    if (WF.currentSearchQuery()) return void toastMsg("Sorting is disabled when search is active.", 4, true);
    const parent = WF.currentItem();
    if (parent.isReadOnly()) return void toastMsg("Parent 是只读的,不能被排序。", 4, true);
    const children = parent.getChildren();
    if (children.length < 2) return void toastMsg("Nothing to sort.", 4, true);
    if (children.length > maxChildren) return void toastMsg(`Sorting more than ${maxChildren} children upsets the WorkFlowy gods, and has been disabled.`, 5, true);
    const sortInfo = `当前页面有 <b>${children.length}</b> 个子节点,你要如何排序它们?`;

    showSortDialog(sortInfo, parent.getNameInPlainText());

  })();

};

const NodeWord_Count = () => {
  // alert("节点与字数统计");

  function e(a) {
    let b = a.getName().trim().length, c = a.getNote().trim().length;
    // console.log(b, c, a.getName());
    for (
      let f of a.getChildren()
    )
      a = e(f), b += a[0], c += a[1];
    return [b, c]
  }

  let d = WF.currentItem(), [g, h] = e(d);

  WF.showMessage(
    `🔘【本页节点总数 <b>${d.getNumDescendants()}</b>
      ,本页根节点个数 <b>${d.getChildren().length}</b>】
      &nbsp;&nbsp;&nbsp;&nbsp;🅰️【文本字数 <b>${g}</b>
      ,注释字数 <b>${h}</b>】`
  )

};

const FlatFlowy = () => {
  // alert("扁平展示搜索结果");

  (function flatFlowy_3_2() {

    function toastMsg(str, sec, err) {
      WF.showMessage(str, err);
      setTimeout(WF.hideMessage, (sec || 3) * 1000);
    }
    function getNameForBreadcrumb(item) {
      const plainName = item.getNameInPlainText().trim();
      var replaceName = "Untitled";
      // if image/file has no title use uploaded filename 
      if (plainName.length === 0 && item.data.metadata.s3File && item.data.metadata.s3File.fileName) replaceName = item.data.metadata.s3File.fileName;
      return plainName.length === 0 ? replaceName : plainName
    }
    function getBreadcrumbsAsString(item) {
      const ancestors = item.getAncestors().reverse();
      return ancestors.length > 1 ? ancestors.splice(1).map(ancestor => getNameForBreadcrumb(ancestor)).join(" > ") : "Home";
    }
    function addBreadcrumbsToMatches() {
      const matches = document.querySelectorAll('.project.matches,.project.metaMatches');
      matches.forEach(match => {
        const pID = match.getAttribute("projectid");
        const item = WF.getItemById(pID);
        match.firstChild.title = getBreadcrumbsAsString(item) // .name node gets titled
      });
    }
    const css = `.page.searching .project>.name,.page.searching .project>.notes{height:0;opacity:0}.page.searching .project.matches .name.matches,.page.searching .project.matches.noted .name,.page.searching .project.metaMatches .name{height:100%;opacity:1}.page.searching .children{margin:0;padding:0;border:0}.page.searching .addSiblingButton,.page.searching .expand{display:none}.done .fullMatch .content .contentMatch,.fullMatch .content .contentMatch,.project.metaMatches>.name.with-updates.annotationAdded>.content>.innerContentContainer,.project.metaMatches>.name>.content>.innerContentContainer{background-color:transparent}`;
    const ID = "FlatFlowy";
    const ff = document.getElementById(ID);
    const NO_SEARCH = WF.currentSearchQuery() === null;
    if (ff) {
      NO_SEARCH ? toastMsg(`FlatFlowy 功能状态: ${ff.disabled ? "ON" : "OFF"}`) : addBreadcrumbsToMatches();
      return void (ff.disabled = !ff.disabled);
    }
    const s = document.createElement('style');
    s.innerText = css;
    s.id = ID;
    document.head.appendChild(s);
    NO_SEARCH ? toastMsg("FlatFlowy 功能状态: ON") : addBreadcrumbsToMatches();

  })();


};

const TagIndex = () => {
  // alert("标签统计与索引生成");

  (function tagCounter_1_7(

    sortByCount = false, showCompleted = true) {
    if (typeof sortByCount !== "boolean") sortByCount = false;
    if (typeof showCompleted !== "boolean") showCompleted = true;

    function toastMsg(str, sec, err) {
      WF.showMessage(str.bold(), err);
      setTimeout(() => WF.hideMessage(), (sec || 2) * 1e3)
    }
    function applyToEachItem(functionToApply, parent) {
      functionToApply(parent);
      for (let child of parent.getChildren()) {
        applyToEachItem(functionToApply, child)
      }
    }
    function findMatchingItems(itemPredicate, parent) {
      const matches = [];
      function addIfMatch(item) {
        if (itemPredicate(item)) {
          matches.push(item)
        }
      } applyToEachItem(addIfMatch, parent);
      return matches
    }
    function isVisibleSearchResult(item) {
      const isVisible = WF.completedVisible() || !item.isWithinCompleted();
      return item.data.search_result && isVisible
    }
    function getWfTagsList(item) {
      const tagCounts = item.isMainDocumentRoot() ? getRootDescendantTagCounts() : item.getTagManager().descendantTagCounts;
      const tagsList = tagCounts ? tagCounts.getTagList() : [];
      return tagsList.sort((a, b) => a.tag.localeCompare(b.tag))
    }
    function getItemTags(item) {
      return WF.getItemNameTags(item).concat(WF.getItemNoteTags(item)).map(t => t.tag.toLowerCase())
    }
    function getAllTags(items) {
      const tags = [];
      items.forEach(item => {
        tags.push(...getItemTags(item))
      });
      return tags
    }
    function getVisibleTagsList(item) {
      const visibleItems = findMatchingItems(isVisibleSearchResult, item), tags = getAllTags(visibleItems), uniqueTags = new Set(tags), tagList = [];
      uniqueTags.forEach(uTag => {
        let uCount = tags.filter(t => t === uTag).length;
        tagList.push({
          tag: uTag, count: uCount
        })
      });
      return tagList.sort((a, b) => a.tag.localeCompare(b.tag))
    }
    if (!WF.completedVisible() && showCompleted) WF.toggleCompletedVisible();
    const current = WF.currentItem();
    const tagCounts = WF.currentSearchQuery() ? getVisibleTagsList(current) : getWfTagsList(current);
    if (tagCounts.length === 0) {
      return void toastMsg("未找到任何标签", 3, true)
    }
    if (sortByCount) tagCounts.sort((a, b) => b.count - a.count);

    const addButton = (num, name) => `<button type="button" class="btnX" id="btn${num.toString()}">${name}</button>`;
    const btnXstyle = '.btnX{font-size:18px;background-color:gray;border:2px solid;border-radius:20px;color:#fff;padding:5px 15px;margin-top:16px;margin-right:16px}.btnX:focus,.btnX:hover{border-color:#c4c4c4;background-color:steelblue}';
    const button1 = addButton(1, "创建标签索引?");


    const url = `${current.getUrl()}${current.isMainDocumentRoot() ? "#" : ""}`;
    const total = tagCounts.reduce((sum, t) => t.count + sum, 0), padMax = total.toString().length, search = WF.currentSearchQuery() ? WF.currentSearchQuery() + " : " : "";
    const tagPre = tagCounts.map(t => `${t.count.toString().padStart(padMax, " ")}\t<a class="tagLinks" href="${url}?q=${encodeURIComponent(t.tag)}">${t.tag}</a>`);
    WF.showAlertDialog(`<style>${btnXstyle}</style><pre><br>${tagPre.join('<br>')}<br><br><b>${total}\t总 计</b></pre><div>${button1}</div>`, search + current.getNameInPlainText());


    const intervalId = setInterval((
      function () {
        let tagLinks = document.getElementsByClassName("tagLinks");
        if (tagLinks) {
          clearInterval(intervalId);
          for (let tagLink of tagLinks) {
            tagLink.addEventListener('click', (function () {
              WF.hideDialog()
            }), false)
          }
        }
      }
    ), 50);



    const intervalId2 = setInterval(
      function () {
        let btn1 = document.getElementById("btn1");
        if (btn1) {
          clearInterval(intervalId2);

          btn1.onclick = function () {

            // ————————  并生成索引目录  ————————
            (function tagIndex_3_8(separator = '"_separator_"') {

              if (separator === '"_separator_"') separator = " ";

              function toastMsg(str, sec, err) {
                WF.showMessage(str, err);
                setTimeout(WF.hideMessage, (sec || 3) * 1000);
              }
              function getDescendantTags(item) {
                const tagCounts = item.isMainDocumentRoot() ? getRootDescendantTagCounts() : item.getTagManager().descendantTagCounts;
                const tagList = tagCounts ? tagCounts.getTagList() : [];
                const tagArr = tagList.map(Tag => Tag.tag);
                // Filter out template tags
                return tagArr.filter(tag => tag.toLowerCase() !== "#template" && !tag.toLowerCase().startsWith("#use-template"));
              }
              const htmlEscTextForContent = str => str.replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/\u00A0/g, " ");
              function newTopBullet(str) {
                WF.editGroup(() => {
                  const newBullet = WF.createItem(WF.currentItem(), 0);
                  WF.setItemName(newBullet, htmlEscTextForContent(str));
                });
              }
              const current = WF.currentItem();
              const tagNames = getDescendantTags(current);
              if (tagNames.length === 0) return void toastMsg("No tags found.", 2, true);
              if (current.isEmbedded()) return void toastMsg("Tag Index is disabled for added shares.", 5, true);
              tagNames.sort((a, b) => a.localeCompare(b));
              newTopBullet(tagNames.join(separator));
            })();

          };

          btn1.addEventListener('click', (function () {
            WF.hideDialog()
          }), false)
        }

      }, 50);

  })();


};


const TextMosaic = () => {
  // alert("文字马赛克");

  // const TMstyle = '.innerContentContainer, .innerContentContainer .contentTag, .innerContentContainer span, .contentLink { color: transparent !important; background: none !important; text-shadow: #A5A1A1 0 0 6px; }';

  // GM_addStyle(`${TMstyle}`);


  // const intervalStyle = setInterval(
  //   function () {

  //     document.head.appendChild(TMstyle);
  //   }, 5000);


  // clearInterval(intervalStyle);
}




if (isShowPageBar) {

  /** 添加样式 **/
  GM_addStyle(`
#dms-link-cleaner {
  width: 100%;
  position: fixed;
  left: 0;
  bottom: 0;
  z-index: 99999999;
  pointer-events: none;
}
#dms-link-cleaner * {
  pointer-events: auto;
}
#dms-lc-button {
  position: relative;
  margin: 0 auto;
  width: 44px;
  height: 20px;
  color: rgba(0, 0, 0, .4);
  font-size: 20px;
  line-height: 13px;
  cursor: pointer;
  text-align: center;
  border: 1px solid #AAA;
  border-radius: 16px 16px 0 0;
  background-color: rgba(255, 255, 255, .3);
  box-shadow: 0 0 5px rgba(0, 0, 0, .1);
}
#dms-lc-button:hover {
  color: rgba(0, 0, 0, .8);
  box-shadow: 0 0 5px rgba(0, 0, 0, .5);
}
#dms-lc-panel {
  display: none;
  border-top: 5px solid #65adff;
  box-shadow: 0 0 5px rgba(0, 0, 0, .1);
}
body._theme-default #dms-lc-panel{
  background-color: #FFF;
}
body._theme-dark #dms-lc-panel{
  background-color: rgb(24 25 28 / 90%);
}
#dms-lc-panel > #dms-lc-panel-content {
  display: flex;
  justify-content: center;
  align-items: center;
  flex: 1 1 none;
  flex-wrap: wrap;
  width: 100%;
  max-width: 800px;
  margin: 0 auto;
  padding: 16px 0;
  text-align: center;
  position: relative;
}
#dms-lc-panel > #dms-lc-panel-content > .dms-lc-button {
  position: relative;
  padding: 8px 16px;
  margin: 0 8px 0 0;
  font-size: 16px;
  line-height: 1.2em;
  font-weight: lighter;
  border: 1px solid #65adff;
  border-radius: 8px;
  cursor: pointer;
}
#dms-lc-panel > #dms-lc-panel-content > .dms-lc-button:hover {
  border: 1px solid #0062d1;
  background-color: #0062d1;
  color: #FFF;
  font-weight: normal;
}
#dms-lc-panel > #dms-lc-panel-content > .dms-lc-button:hover::before {
  content: attr(data-tip);
  background-color: rgba(0, 0, 0, .9);
  border-radius:3px;
  color: #fff;
  padding: 10px;
  position: absolute;
  width: calc(100% + 20px);
  left: 50%;
  bottom: calc(100% + 10px);
  margin-left: calc(-50% - 20px);
  white-space: pre;
}
#dms-lc-panel > #dms-lc-panel-content > .dms-lc-button:hover::after {
  content: "";
  position: absolute;
  width: 0;
  height: 0;
  left: calc(50% - 8px);
  top: -10px;
  border-top: 8px solid rgba(0, 0, 0, .8);
  border-right: 8px solid transparent;
  border-left: 8px solid transparent;
}
#dms-lc-panel > #dms-lc-panel-content > .dms-lc-hr {
  width: 100%;
  margin: 5px 0;
}
#dms-lc-panel > #dms-lc-panel-content > #dmsCLButtonCoffee {
  padding: 0;
  margin: 0;
}
#dms-lc-panel > #dms-lc-panel-content > #dmsCLButtonCoffee > svg {
  width: 35px;
  height: 35px;
}
#dms-lc-panel > #dms-lc-panel-content > #dms-lc-qrcode {
  display: none;
  width: 100%;

  position: absolute;
  left: 0;
  bottom: calc(100% + 24px);
  padding: 16px;
  color: #333;
  font-size: 18px;
  line-height: 1.2em;
  border: 1px solid #CCC;
  border-radius: 12px 12px 0 0;
  background-color: #FFF;
  box-shadow: 0 6px 36px 5px rgba(0, 0, 0, .16);
}
#dms-lc-panel > #dms-lc-panel-content > #dms-lc-qrcode > img {
  width: 30%;
  max-width: 180px;
}
  `);

  /** 添加界面 **/
  const dmsLCPopPanel = document.createElement('div');
  dmsLCPopPanel.id = 'dms-link-cleaner';
  dmsLCPopPanel.innerHTML = `<div id="dms-lc-button">
  ︽
</div>
<div id="dms-lc-panel">
  <div id="dms-lc-panel-content">
    <div class="dms-lc-button" id="dmsCLFR" data-tip="查找与替换">
      查找与替换
    </div>
    <div class="dms-lc-button" id="dmsCLST" data-tip="节点排序">
      节点排序
    </div>
    <div class="dms-lc-button" id="dmsCLNWC" data-tip="节点与字数统计">
      节点与字数统计
    </div> 
    <div class="dms-lc-hr"></div>
    <div class="dms-lc-button" id="dmsCLFF" data-tip="扁平展示搜索结果">
      扁平展示搜索结果
    </div>
    <div class="dms-lc-button" id="dmsCLTI" data-tip="标签统计与索引生成">
      标签统计与索引生成
    </div>
    <div class="dms-lc-button" id="dmsCLButtonCopyTitle" data-tip="预留功能">
      预留功能
    </div>
    <div class="dms-lc-button" id="dmsCLTM" data-tip="文字马赛克">
      文字马赛克
    </div>
    <div class="dms-lc-hr"></div>
    <div class="dms-lc-button" id="dmsCLButtonCleanAll" data-tip="预留功能">
      预留功能
    </div>
    <div class="dms-lc-button" id="dmsCLButtonLink" data-tip="联系作者">Issues</div>
    <div class="dms-lc-button" id="dmsCLButtonCoffee" data-tip="Coffee">
      <svg t="1539507279741" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1618" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M237.717333 320L277.333333 597.333333h469.333334l39.616-277.333333z" fill="#FFC107" p-id="1619"></path><path d="M832 320v-53.333333a32 32 0 0 0-32-32h-576A32 32 0 0 0 192 266.666667V320h640z" fill="#795548" p-id="1620"></path><path d="M280.384 618.666667L320 896h384l39.616-277.333333z" fill="#77574F" p-id="1621"></path><path d="M512 597.333333m-106.666667 0a106.666667 106.666667 0 1 0 213.333334 0 106.666667 106.666667 0 1 0-213.333334 0Z" fill="#77574F" p-id="1622"></path><path d="M426.666667 597.333333c0-15.616 4.501333-30.058667 11.84-42.666666h-167.253334l15.232 106.666666h169.621334A84.778667 84.778667 0 0 1 426.666667 597.333333zM585.493333 554.666667c7.338667 12.608 11.84 27.050667 11.84 42.666666a84.778667 84.778667 0 0 1-29.44 64h169.621334l15.232-106.666666h-167.253334zM768 128H256l-21.333333 106.666667h554.666666z" fill="#4E342E" p-id="1623"></path><path d="M512 448a149.333333 149.333333 0 1 1 0 298.666667 149.333333 149.333333 0 0 1 0-298.666667m0-21.333333c-94.101333 0-170.666667 76.565333-170.666667 170.666666s76.565333 170.666667 170.666667 170.666667 170.666667-76.565333 170.666667-170.666667-76.565333-170.666667-170.666667-170.666666z" fill="#5D4037" p-id="1624"></path><path d="M512 448a149.333333 149.333333 0 1 0 0 298.666667 149.333333 149.333333 0 0 0 0-298.666667z m0 234.666667a85.333333 85.333333 0 1 1 0-170.666667 85.333333 85.333333 0 0 1 0 170.666667z" fill="#FFF3E0" p-id="1625"></path></svg>
    </div>
    <div id="dms-lc-qrcode">
      Workflowy ToolBox<br />
      (Demo)
      <hr />
      敬请期待……
    </div>
  </div>
</div>`;

  document.body.insertBefore(
    dmsLCPopPanel,
    document.body.lastChild.nextSibling
  );

  /** 事件响应函数 **/

  /* 定义元素 */

  const FR = document.getElementById('dmsCLFR');
  const ST = document.getElementById('dmsCLST');
  const NWC = document.getElementById('dmsCLNWC');
  const FF = document.getElementById('dmsCLFF');
  const TI = document.getElementById('dmsCLTI');
  const TM = document.getElementById('dmsCLTM');



  const button = document.getElementById('dms-lc-button');
  const panel = document.getElementById('dms-lc-panel');
  const qrcode = document.getElementById('dms-lc-qrcode');
  const buttonTitle = document.getElementById('dmsCLButtonTitle');
  const buttonPure = document.getElementById('dmsCLButtonPure');
  const buttonCopyT = document.getElementById('dmsCLButtonCopyTitle');
  const buttonCopyL = document.getElementById('dmsCLButtonCopyLink');
  const buttonCleanLink = document.getElementById('dmsCLButtonCleanAll');
  const buttonLink = document.getElementById('dmsCLButtonLink');
  const buttonCoffee = document.getElementById('dmsCLButtonCoffee');

  /**
   * 面板切换
   */
  const dmsLCToggleEl = function (el) {
    const elStyle = getComputedStyle(el, '');
    if (elStyle.display === 'none') {
      el.style.display = 'block';
    } else {
      el.style.display = '';
    }
  };

  /** 添加监听器 **/
  /* 面板切换按钮 */
  button.addEventListener(
    'click',
    () => {
      dmsLCToggleEl(panel);
    },
    false
  );
  /* 买咖啡 */
  buttonCoffee.addEventListener(
    'click',
    () => {
      dmsLCToggleEl(qrcode);
    },
    false
  );



  // 查找与替换 https://rawbytz.github.io/find-replace/
  FR.addEventListener('click', Find_Replace, false);

  // 节点排序 https://rawbytz.github.io/sort/
  ST.addEventListener('click', WF_Sort, false);

  // 节点与字数统计 @rawbytz @seyee
  NWC.addEventListener('click', NodeWord_Count, false);

  // 扁平展示搜索结果 https://rawbytz.github.io/flatflowy/
  FF.addEventListener('click', FlatFlowy, false);

  // 标签统计与索引生成 https://rawbytz.github.io/tag-index/
  TI.addEventListener('click', TagIndex, false);

  // 文字马赛克
  TM.addEventListener('click', TextMosaic, false);



  /* 支持链接 */
  buttonLink.addEventListener('click', goToSupport, false);
  /* 净化并复制标题和链接 */
  buttonTitle.addEventListener('click', getCleanUrlAndTitle, false);
  /* 净化并复制链接 */
  buttonPure.addEventListener('click', getCleanUrl, false);
  /* 复制当前链接和标题 */
  buttonCopyT.addEventListener('click', getUrlAndTitle, false);
  /* 复制当前链接 */
  buttonCopyL.addEventListener('click', getUrlOnly, false);
  /* 清理整个页面 */
  buttonCleanLink.addEventListener('click', cleanAllPage, false);


  /* 全屏隐藏按钮 */
  document.addEventListener('fullscreenchange', function (event) {
    if (document.fullscreenElement) {
      button.style.display = 'none';
    } else {
      button.style.display = '';
    }
  });


}