Greasy Fork

Greasy Fork is available in English.

KaTeXFlowy

Supports formula rendering in WorkFlowy with KaTeX

当前为 2022-02-13 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         KaTeXFlowy
// @namespace    https://github.com/BettyJJ
// @version      0.2.3
// @description  Supports formula rendering in WorkFlowy with KaTeX
// @author       Betty
// @match        https://workflowy.com/*
// @match        https://*.workflowy.com/*
// @run-at       document-idle
// @grant        GM.addStyle
// @grant        GM_getResourceText
// @resource     KATEX_CSS https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/contrib/auto-render.min.js
// ==/UserScript==

(function () {
	'use strict';


	init();


	/**
	 * initialize
	 */
	function init() {
		watch_page();

		load_css();

		hide_raw();

	}


	/**
	 * watch the page
	 */
	function watch_page() {

		// wathe the page, so that the rendering is updated when new contents come in as the user edits or navigates
		const observer = new MutationObserver(function (mutationlist) {
			for (const { addedNodes } of mutationlist) {
				for (const node of addedNodes) {
					if (!node.tagName) continue; // not an element

					if (node.classList.contains('innerContentContainer')) {
						handle_node(node);
					}

				}
			}
		});
		observer.observe(document.body, { childList: true, subtree: true });

	}


	/**
	 * insert a container after the node with formula to contain the rendered result
	 * @param {Node} node Dom Node
	 */
	function handle_node(node) {
		// sometimes there is a dummy node without parent. don't know why, but we need to check and exclude it first
		const parent = node.parentElement;
		if (!parent) {
			return;
		}

		// if a container already exists, remove it first to avoid duplication
		if (parent.nextSibling && parent.nextSibling.classList.contains('rendered-latex')) {
			parent.nextSibling.remove();

			// also remove the class name we added previously
			parent.classList.remove('has-latex');
		}

		// check if the node contains anything that should be rendered
		if (!should_render(node)) {
			return;
		}

		// give the parent a class name so we can handle it later
		parent.classList.add('has-latex');

		// add an element to contain the rendered latex
		const container = document.createElement('div');
		container.innerHTML = node.innerHTML;
		container.className = 'rendered-latex';
		parent.insertAdjacentElement('afterend', container);

		// replicate this class name of the parent so that the rendered block can preserve WF's original style
		container.classList.add(parent.classList[1]);

		// render it
		const options = {
			delimiters: [
				{ left: '$$', right: '$$', display: true },
				{ left: '$', right: '$', display: false }
			]
		};
		renderMathInElement(container, options);

		// when the element is clicked, make the focus in the corresponding node so that the user can begin typing
		container.addEventListener('click', () => {
			parent.focus();
		});

	}


	/**
	 * check if the node contains anything that should be rendered
	 * @param {Node} node Dom Node
	 * @returns {boolean}
	 */
	function should_render(node) {
		// use $ or $$ as delimiters
		const text = node.textContent;
		const regex = /\$(\$)?(.+?)\$(\$)?/s;
		const match = text.match(regex);
		if (match !== null) {
			return true;
		}

		return false;
	}


	/**
	 * hide the raw content with LaTeX. only shows it when it has focus
	 */
	function hide_raw() {
		GM.addStyle('.name .has-latex .innerContentContainer { display:none } ');
		GM.addStyle('.name .has-latex.content { height: 0; min-height: 0 } ');

		GM.addStyle('.name--focused .has-latex .innerContentContainer { display:inline} ');
		GM.addStyle('.name--focused .has-latex.content { height: auto} ');

		// add a background to make the raw part look clearer
		GM.addStyle('.name--focused .has-latex { background: #eee } ');

		// preserve line breaks in notes
		GM.addStyle('.notes .rendered-latex { white-space: pre-wrap } ');
	}


	/**
	 * load KaTeX css
	 */
	function load_css() {
		let css = GM_getResourceText("KATEX_CSS");

		// the font path in the css file is relative, we need to change it to absolute
		css = css.replace(
			/fonts\//g,
			'https://cdn.jsdelivr.net/npm/[email protected]/dist/fonts/'
		);

		GM.addStyle(css);
	}


})();