// ==UserScript== // @name WorkFlowy - Inline Code Formatting [ARCHIVED] // @description Adds inline code formatting to WorkFlowy (e.g. `code`). // @author Gavin Elster // @version 2023.04.24 // @license MIT // // @namespace https://github.com/elstgav // @homepageURL https://github.com/elstgav/workflowy // @supportURL https://github.com/elstgav/workflowy/issues // // @downloadURL https://raw.githubusercontent.com/elstgav/workflowy/main/dist/scripts/archive/inline-code-style/workflowy.inline-code-style.user.js // @updateURL https://raw.githubusercontent.com/elstgav/workflowy/main/dist/scripts/archive/inline-code-style/workflowy.inline-code-style.user.js // // @match https://workflowy.com/* // // @grant none // @run-at document-end // ==/UserScript== //#region src/scripts/archive/inline-code-style/inline-code-style.ts let currentBullet = null let page = null const INLINE_CODE = /`([^`]+)`/g const MANGLED_BACKTICK_ANCHOR_TAGS = /<\/a>]+ href="([^"]+)">`<\/a>]+ href="(\1)">/g const createElementFromHTML = (html) => { const template = document.createElement('template') template.innerHTML = html.trim() return template.content.firstChild } const style = createElementFromHTML( ``.replaceAll(/[\s\n]+/g, ' '), ) const highlight = (container) => { if (!container) return if (document.getElementById('srch-input')?.value?.includes('`')) return container.querySelectorAll('.content[contenteditable] .innerContentContainer').forEach((item) => { if (!(item instanceof HTMLElement)) return requestAnimationFrame(() => { if ( !item.textContent || item.innerHTML.includes('') || !item.textContent.match(INLINE_CODE) ) return if ((item.innerHTML.match(MANGLED_BACKTICK_ANCHOR_TAGS)?.length ?? 0) >= 2) item.innerHTML = item.innerHTML.replaceAll(MANGLED_BACKTICK_ANCHOR_TAGS, '`') item.innerHTML = item.innerHTML.replaceAll( INLINE_CODE, '`$1`', ) }) }) } const currentBulletRoot = () => currentBullet?.closest('.project.root > .children > .project') ?? null const currentFocusRoot = () => document.querySelector('.project.root > .children > .project:focus-within') const currentBulletObserver = new MutationObserver((mutationList) => { const firstMutation = mutationList[0] if (!firstMutation || !(firstMutation.target instanceof Element)) return if ( (firstMutation.oldValue?.includes('open') ?? false) !== firstMutation.target.classList.contains('open') ) highlight(currentFocusRoot()) }) const onFocusIn = (event) => { if (currentBullet) { currentBulletObserver.disconnect() highlight(currentBulletRoot()) } currentBullet = event.target instanceof Element ? event.target.closest('.project') : null if (!currentBullet) return currentBulletObserver.observe(currentBullet, { attributes: true, attributeFilter: ['class'], attributeOldValue: true, }) } const existingListeners = window.WFEventListener const onWFEvent = (event) => { existingListeners?.(event) switch (event) { case 'indent': case 'outdent': case 'operation--bulk_create': case 'operation--bulk_move': case 'operation--delete': { const focusRoot = currentFocusRoot() if (currentBullet === focusRoot) highlight(page) else { highlight(currentFocusRoot()) if (!focusRoot?.contains(currentBullet)) highlight(currentBulletRoot()) } highlight(page) break } case 'locationChanged': highlight(page) break default: break } } const appObserver = new MutationObserver(() => { page = document.querySelector('.page.active') if (!page) return appObserver.disconnect() highlight(page) page.addEventListener('focusin', onFocusIn) window.WFEventListener = onWFEvent }) if (style) document.head.appendChild(style) appObserver.observe(document.body, { subtree: true, childList: true, }) //#endregion