WorkFlowy - Inline Code Formatting [ARCHIVED]

Adds inline code formatting to WorkFlowy (e.g. `code`).

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Для установки этого скрипта вам необходимо установить расширение, такое как Tampermonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Advertisement:

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

Advertisement:

// ==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
//
//
// @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><a [^>]+ href="([^"]+)">`<\/a><a [^>]+ href="(\1)">/g
const createElementFromHTML = (html) => {
  const template = document.createElement('template')
  template.innerHTML = html.trim()
  return template.content.firstChild
}
const style = createElementFromHTML(
  `<style>
      span.gavin-backtick {
        font-size: 0;
        line-height: 0;
      }

      code.gavin-inline-code {
        padding: .2em .4em;
        background-color: rgba(0,0,0,.25);
        border-radius: 6px;
        margin: 0;
        font-size: 85%;
        line-height: 1;
      }
    </style>`.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('</code>') ||
        !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,
        '<span class="gavin-backtick">`</span><code class="gavin-inline-code">$1</code><span class="gavin-backtick">`</span>',
      )
    })
  })
}
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