Greasy Fork

Greasy Fork is available in English.

Microsoft To-Do Markdown Preview Support - mstodo-md-preview

Microsoft To-Do Markdown Preview Support

当前为 2024-08-30 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Microsoft To-Do Markdown Preview Support - mstodo-md-preview
// @namespace    https://github.com/joisun
// @version      1.0.5
// @author       Zhongyi Sun
// @description  Microsoft To-Do Markdown Preview Support
// @license      MIT
// @icon         https://t2.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=https://to-do.live.com/&size=64
// @match        https://to-do.live.com/*
// @require      https://cdn.jsdelivr.net/npm/@highlightjs/[email protected]/highlight.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/markdown-it.min.js
// @resource     highlight.js/styles/tokyo-night-dark.min.css  https://cdn.jsdelivr.net/npm/@highlightjs/[email protected]/styles/tokyo-night-dark.min.css
// @grant        GM_addStyle
// @grant        GM_getResourceText
// ==/UserScript==

(o=>{if(typeof GM_addStyle=="function"){GM_addStyle(o);return}const e=document.createElement("style");e.textContent=o,document.head.append(e)})(' .markdown-body{color:#fffffff1;font-size:1em;font-weight:lighter;line-height:1.75;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji"}.markdown-body u{text-underline-offset:6px}.markdown-body hr{border:none;height:1px;background-color:#ffffff0a;margin:2.5em 0}.markdown-body abbr:where([title]){text-decoration:underline dotted}.markdown-body a{color:var(--fg-deeper);text-decoration:none;font-weight:500}.markdown-body b,.markdown-body code,.markdown-body kbd,.markdown-body samp,.markdown-body pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}.markdown-body sub{bottom:-.25em}.markdown-body sup{top:-.5em}.markdown-body blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}.markdown-body fieldset{margin:0;padding:0}.markdown-body legend{padding:0}.markdown-body ol,.markdown-body ul,.markdown-body menu{list-style:none;margin:0;padding:0}.markdown-body dialog{padding:0}.markdown-body textarea{resize:vertical}.markdown-body button,.markdown-body [role=button]{cursor:pointer}:disabled{cursor:default}.markdown-body [class~=lead]{color:#4b5563;font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.markdown-body strong{font-weight:600;margin:0 .2em;color:#ffffffda}.markdown-body i{padding:0 .4em;color:inherit;font-style:italic;background-color:transparent}.markdown-body em{padding:0 .4em;background-color:#00f73685;font-style:normal}.markdown-body u{font-weight:600;font-weight:400;margin:0 .2em;border-radius:4px;padding:.1em .4em;text-underline-offset:.4em;text-decoration:underline 1px dashed;text-decoration-color:#f44}.markdown-body ol>li,.markdown-body ul>li{position:relative;padding-left:1.75em}.markdown-body ol>li:before{content:counter(list-item,var(--list-counter-style, decimal)) ".";position:absolute;font-weight:400;color:#6b7280;left:0}.markdown-body ul>li:before{content:"";position:absolute;background-color:#d1d5db;border-radius:50%;width:.375em;height:.375em;top:.6875em;left:.25em}.markdown-body blockquote{font-weight:500;font-style:italic;color:inherit;font-size:.9em;opacity:.8;border-left:solid #444;background-color:#4444444a;border-left-width:.4rem;quotes:"\u201C" "\u201D" "\u2018" "\u2019";margin-top:.6em;margin-bottom:.6em;margin-left:auto;padding:.5em .5em .5em 1em}.markdown-body blockquote p:first-of-type:before{content:open-quote}.markdown-body blockquote p:last-of-type:after{content:close-quote}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{color:#ffffffd0;font-family:ui-serif,Georgia,Cambria,Times New Roman,Times,serif;letter-spacing:.1em;margin:0}.markdown-body h1{font-weight:800;font-size:3rem;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.markdown-body h2{font-weight:700;font-size:2.25rem;line-height:2.5rem;margin-top:2em;margin-bottom:1em}.markdown-body h3{font-weight:700;font-size:1.875rem;line-height:2.25rem;margin-top:1.6em;margin-bottom:.6em}.markdown-body h4{font-weight:700;font-size:1.5rem;line-height:2rem;margin-top:1.5em;margin-bottom:.5em}.markdown-body h5{font-weight:700;font-size:1.25rem;line-height:1.75rem;margin-top:1.5em;margin-bottom:.5em}.markdown-body h6{font-weight:700;font-size:1.125rem;line-height:1.75rem;margin-top:1.5em;opacity:.7;margin-bottom:.5em}.markdown-body h2+*{margin-top:0}.markdown-body figure figcaption{color:#6b7280;font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.markdown-body code{color:inherit;font-weight:600;font-size:.875em}.markdown-body p code{font-weight:700;margin:0 .5em;font-size:1.1em}.markdown-body p code:before{content:"`"}.markdown-body p code:after{content:"`"}.markdown-body a code{color:#111827}.markdown-body pre code:before,.markdown-body pre code:after{content:none}.markdown-body table{width:100%;table-layout:auto;text-align:left;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.markdown-body thead{color:inherit;font-weight:600;border-bottom-width:1px;border-bottom-color:#d1d5db}.markdown-body thead th{vertical-align:bottom;padding-right:.5714286em;padding-bottom:.5714286em;padding-left:.5714286em}.markdown-body tbody tr{border-bottom-width:1px;border-bottom-color:#e5e7eb}.markdown-body tbody tr:last-child{border-bottom-width:0}.markdown-body tbody td{vertical-align:top;padding:.5714286em}.markdown-body p{margin-top:.25em;margin-bottom:.25em}.markdown-body img{width:100%;height:auto;margin-top:2em;margin-bottom:2em}.markdown-body video{margin-top:2em;margin-bottom:2em}.markdown-body figure{margin-top:2em;margin-bottom:2em}.markdown-body figure>*{margin-top:0;margin-bottom:0}.markdown-body h2 code{font-size:.875em}.markdown-body h3 code{font-size:.9em}.markdown-body ol,.markdown-body ul{margin-top:1.25em;margin-bottom:1.25em;list-style-type:none}.markdown-body li{margin-top:.5em;margin-bottom:.5em}.markdown-body pre{border-radius:.375em;border-width:1px;overflow:auto;padding:1.25em;background-color:#00000073;margin:.2em .4em}.markdown-body pre code{color:inherit;background:none;font-size:.975em;font-weight:400;overflow:visible;white-space:pre-wrap} ');

(function (markdownit, hljs) {
  'use strict';

  function behindDebounce(func, duration) {
    let timer = null;
    return () => {
      timer && clearTimeout(timer);
      timer = setTimeout(() => {
        func();
      }, duration);
    };
  }
  function waitForElement(selector) {
    return new Promise((resolve) => {
      if (document.querySelector(selector)) {
        return resolve(document.querySelector(selector));
      }
      const observer2 = new MutationObserver(() => {
        if (document.querySelector(selector)) {
          resolve(document.querySelector(selector));
          observer2.disconnect();
        }
      });
      observer2.observe(document.body, {
        childList: true,
        subtree: true
      });
    });
  }
  const cssLoader = (e) => {
    const t = GM_getResourceText(e);
    return GM_addStyle(t), t;
  };
  cssLoader("highlight.js/styles/tokyo-night-dark.min.css");
  const createBtnWithIcon = function(id, icon) {
    const btn = document.createElement("button");
    btn.id = id;
    btn.innerHTML = icon;
    btn.style.width = "auto";
    btn.style.height = "auto";
    btn.style.color = "inherit";
    btn.style.padding = ".2em .5em";
    btn.style.backgroundColor = "#555";
    btn.style.border = "none";
    btn.style.borderRadius = "4px";
    btn.style.display = "inline-flex";
    btn.style.alignItems = "center";
    btn.style.justifyContent = "center";
    btn.style.cursor = "pointer";
    btn.style.transition = "background-color 0.3s ease";
    btn.addEventListener("mouseenter", () => {
      btn.style.backgroundColor = "#444";
    });
    btn.addEventListener("mouseleave", () => {
      btn.style.backgroundColor = "#555";
    });
    return btn;
  };
  const md = markdownit({
    // Enable HTML tags in source
    html: true,
    // Use '/' to close single tags (<br />)
    xhtmlOut: false,
    // Convert '\n' in paragraphs into <br>
    breaks: false,
    // CSS language prefix for fenced blocks
    langPrefix: "language-",
    // autoconvert URL-like texts to links
    linkify: true,
    // Enable smartypants and other sweet transforms
    typographer: true,
    highlight: function(str, lang) {
      if (lang && hljs.getLanguage(lang)) {
        try {
          return hljs.highlight(str, { language: lang }).value;
        } catch (__) {
        }
      }
      return "";
    }
  });
  const EDIT_BTN_ID = "mstodo:editBtn";
  const VIEW_BTN_ID = "mstodo:viewBtn";
  waitForElement(".ql-editor").then(() => {
    observerHandler();
    hideEditor();
    observe();
    clickListen();
  });
  let isEdit = false;
  function hideEditor() {
    if (isEdit) return;
    const editor = document.querySelector(".ql-editor");
    editor && (editor.style.height = "0px");
    const viewer = document.getElementById("tstodo:mdViewer");
    viewer && (viewer.style.height = "auto");
  }
  function showEditor() {
    isEdit = true;
    const editor = document.querySelector(".ql-editor");
    editor && (editor.style.height = "auto");
    const viewer = document.getElementById("tstodo:mdViewer");
    viewer && (viewer.style.height = "0px");
  }
  const initBtns = () => {
    var _a;
    if (document.getElementById("mstodo:btns")) return;
    const detailNote = document.querySelector(".detailNote");
    if (!detailNote) return;
    const edit = createBtnWithIcon(
      EDIT_BTN_ID,
      `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><path fill="currentColor" d="M6 22q-.825 0-1.412-.587T4 20V4q0-.825.588-1.412T6 2h7.175q.4 0 .763.15t.637.425l4.85 4.85q.275.275.425.638t.15.762V10.4q0 .275-.162.475t-.413.3q-.4.15-.763.388T18 12.1l-5.4 5.4q-.275.275-.437.638T12 18.9V21q0 .425-.288.713T11 22zm8-1v-1.65q0-.2.075-.387t.225-.338l5.225-5.2q.225-.225.5-.325t.55-.1q.3 0 .575.113t.5.337l.925.925q.2.225.313.5t.112.55t-.1.563t-.325.512l-5.2 5.2q-.15.15-.337.225T16.65 22H15q-.425 0-.712-.287T14 21m6.575-4.6l.925-.975l-.925-.925l-.95.95zM14 9h4l-5-5l5 5l-5-5v4q0 .425.288.713T14 9"/></svg>`
    );
    const view = createBtnWithIcon(
      VIEW_BTN_ID,
      `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 1024 1024"><path fill="currentColor" d="M854.6 288.7c6 6 9.4 14.1 9.4 22.6V928c0 17.7-14.3 32-32 32H192c-17.7 0-32-14.3-32-32V96c0-17.7 14.3-32 32-32h424.7c8.5 0 16.7 3.4 22.7 9.4zM790.2 326L602 137.8V326zM426.13 600.93l59.11 132.97a16 16 0 0 0 14.62 9.5h24.06a16 16 0 0 0 14.63-9.51l59.1-133.35V758a16 16 0 0 0 16.01 16H641a16 16 0 0 0 16-16V486a16 16 0 0 0-16-16h-34.75a16 16 0 0 0-14.67 9.62L512.1 662.2l-79.48-182.59a16 16 0 0 0-14.67-9.61H383a16 16 0 0 0-16 16v272a16 16 0 0 0 16 16h27.13a16 16 0 0 0 16-16z"/></svg>`
    );
    const btns = document.createElement("div");
    btns.id = "mstodo:btns";
    btns.style.display = "flex";
    btns.style.gap = ".5em";
    btns.style.justifyContent = "flex-end";
    btns.style.padding = "0.5em 1em";
    btns.appendChild(edit);
    btns.appendChild(view);
    detailNote.parentElement && ((_a = detailNote.parentElement) == null ? void 0 : _a.insertBefore(btns, detailNote));
    edit.addEventListener("click", () => {
      showEditor();
    });
    view.addEventListener("click", () => {
      isEdit = false;
      hideEditor();
    });
  };
  const createContainer = (qlEditor) => {
    var _a;
    if (!qlEditor) return;
    const container = document.createElement("div");
    container.id = "tstodo:mdViewer";
    container.classList.add("markdown-body");
    container.style = `
    overflow: hidden;
    background-color: inherit;
  `;
    container.addEventListener("click", (event) => {
      event.stopPropagation();
      event.preventDefault();
    });
    qlEditor.parentElement && ((_a = qlEditor.parentElement) == null ? void 0 : _a.insertBefore(container, qlEditor));
    return container;
  };
  const observerHandler = behindDebounce(function() {
    const qlEditor = document.querySelector(".ql-editor");
    console.log("mstodo:editor existed: ", !!qlEditor);
    const mdViewer = document.getElementById("tstodo:mdViewer") || createContainer(qlEditor);
    console.log("mstodo:mdviewer existed: ", !!mdViewer);
    initBtns();
    if (!qlEditor) return;
    const mdContent = qlEditor.innerText;
    try {
      console.log("mstodo:parsing....");
      let result = md.render(mdContent.replace(/\u00A0/g, "  "));
      mdViewer.innerHTML = result;
      if (!isEdit) hideEditor();
    } catch (err) {
      console.error(err);
    }
  }, 100);
  const observer = new MutationObserver(observerHandler);
  function disconnect() {
    observer.disconnect();
  }
  function observe() {
    disconnect();
    observer.observe(document.querySelector(".ql-editor"), {
      characterData: true,
      // 观察目标节点内文本内容的变化
      childList: true,
      // 观察目标节点中直接子节点的增删
      subtree: true,
      // 观察所有后代节点
      characterDataOldValue: true
      // 记录文本内容的变化前信息
    });
  }
  function clickListen() {
    document.addEventListener("click", function(e) {
      const target = e.target;
      const parent = document.querySelector(".tasks") || document.querySelector(".grid-body");
      if (target.className === "taskItem-titleWrapper" || (parent == null ? void 0 : parent.contains(target))) {
        console.log("mstodo: click listener triggered");
        observerHandler();
        observe();
      }
    });
  }

})(markdownit, hljs);