generated at
html2sb
HTMLをscrapbox記法に変換するUserScript

使い方
js
import {parse} from '/api/code/customize/html2sb/script.js'; const html = 'html形式のテキスト'; const text = parse({html: html});
引数
html : 変換対象のhtmlテキスト
config (optional): htmlの変換方法
書式はこう
ts
type Config = { selector: string; text?: (textContent: string, element: HTMLElement) => string; processor?: (element: HTMLElement) => void; }[];
selector で指定したhtml要素を processor で変換する
単純に textContent だけ変更すればいい場合は text を使う
いずれの変換も指定されていない場合は、 selector に該当する要素を空にする

実装
/scrasobox/WebからコピペしたらSB記法に変換するをベースに、いくつか修正を加えている
forEach 内の不要な中括弧を削除
DOMParser を使用しない

既知の問題
code string みたいなやつを変換するとscrapbox記法がcodeの中に入ってしまう
config をいい感じに変えてやればなんとかなるかもしれない
箇条書きの変換に失敗している

hr


Utilities
script.js
const format = text => text.split(/\n/).map(l => l.trim()).join(''); const ng = text => text.trim().replace(/[\[\]\n]/g, ' ');

defaultのparsing設定
script.js
const defaultConfig = [ { selector: 'pre', text: code => 'code:code.*\n' + code.split('\n').map(l => ` ${l}`).join('\n'), }, { selector: 'h3', text: headline => `[** ${format(headline)}]`, }, { selector: 'h2', text: headline => `[*** ${format(headline)}]`, }, { selector: 'h1', text: headline => `[**** ${format(headline)}]`, }, { selector: 'table', processor: table => { const title = table.getElementsByTagName('caption')?.[0]?.textContent ?? '*'; const body = [...table.getElementsByTagName('tr')] .map(row => ` ${[...row.querySelectorAll('th, td')] .map(column => column.textContent).join('\t')}`) .join('\n'); table.outerHTML = `<pre>table:${title}\n${body}</pre>`; }, }, { selector: 'em, i', text: text => `[/ ${format(text)}]`, }, { selector: 'strong, b', text: text => `[* ${format(text)}]`, }, { selector: 'a[href] img[src]', processor: img => { const a = img.closest('a'); a.outerHTML = `[${img.src.trim()}#.png ${decodeURIComponent(a.href)}]`; }, }, { selector: 'a[href]', text: (_, a) => `[${decodeURIComponent(a.href)} ${ng(a.text).trim()}]`, }, { selector: 'img[src]', processor: img => img.outerHTML = `[${img.src.trim()}#.png]`, }, { selector: 'iframe[src*="//www.youtube.com/embed/"]', processor: iframe => iframe.outerHTML = `[https://www.youtube.com/watch?v=${iframe.src.split('/embed/')[1].split('?')[0]}]`, }, { selector: 'code', text: code => `\`${code}\``, }, ];

script.js
function parse({html, config = defaultConfig} = {}) { const dom = document.createElement('div'); dom.insertAdjacentHTML('beforeend', html); // configに基づいてHTMLを変換する for (const {selector,text,processor} of config) { if (processor) { dom.querySelectorAll(selector).forEach(element => processor(element)); continue; } if (text) { dom.querySelectorAll(selector) .forEach(element => element.textContent = text(element.textContent, element)); continue; } dom.querySelectorAll(selector).forEach(element => element.textContent = ''); } // 箇条書きを変換する let depth = -1; const li = node => { depth++; node.querySelectorAll('li').forEach(n => li(n)); return node.innerHTML = '@sp@'.repeat(depth--) + node.innerHTML; }; li(dom); // DOMを実体化して、テキスト形式でコピペする document.body.appendChild(dom); const range = document.createRange(); range.selectNode(dom); const text = dom.innerText; document.body.removeChild(dom); // 後始末 return text.replace(/(\s*\n){3,}/g, '\n\n') .replace(/@sp@/gi, ' '); // ここで箇条書きのインデントを復元している } export {defaultConfig, parse};

UserScript