scrapboxのページカードを作成するscript
説明文の実装
1行づつ <p>
で囲む
各種構文
無視するもの
テーブル
コードブロック
数式
画像
DOMじゃなくて element.insertAdjacentHTML()
に入れられるtext形式で返したほうがいいな
textならWebWorkerでも計算できる
script.jsimport {ScrapboxParser} from '/api/code/takker/scrapbox-parser.min.js/parser.js';
export function createPageCard({project, title, description, imageUrl=undefined} = {}) {
//console.log(`project: ${project}`);
//console.log(`description: ${description}`);
//console.log(`imageUrl: ${imageUrl}`);
const content = imageUrl ?
`<div class="icon">
<img loading="lazy" src="${imageUrl}">
</div>` :
`<div class="description">${parse(description, project)}</div>`;
return `
<li class="page-list-item grid-style-itme">
<a href="/${project}/${encodeURIComponent(title)}" rel="route">
<div class="hover"></div>
<div class="content">
<div class="header">
<div class="title">${title}</div>
</div>
${content}
</div>
</a>
</li>`;
}
function parse(text, project) {
const blocks = ScrapboxParser.parse(text, {hasTitle: false});
return blocks.map(block => convertSb2HTML(block, project)).join('\n');
}
function convertSb2HTML(block, project) {
switch (block.type) {
case 'title':
return ''; // タイトルは選択範囲に入らないので無視
case 'codeBlock':
case 'table':
return '';
case 'line':
if (block.nodes.length === 0) return '';
if(block.nodes.length === 1) {
const node = block.nodes[0];
if (node.type === 'blank') return '';
if (node.type === 'plain') return `<p>${node.text}</p>`;
}
return `<p>${block.nodes.map(node => '<span>' + convertNode(node, project) +'</span>').join('')}</p>`;
}
}
function convertNode(node, project) {
switch (node.type) {
case 'quote':
case 'image':
case 'strongImage':
case 'formula':
case 'googleMap':
return '';
case 'icon':
case 'strongIcon':
if (node.pathType ==='relative') {
return `<img class="inline-icon" src="https://scrapbox.io/api/pages/${project}/${node.path}/icon" />`;
}
return `<img class="inline-icon" src="https://scrapbox.io/api/pages${node.path}/icon" />`;
case 'strong':
return `<strong>${node.text}</strong>`;
case 'decoration':
let result = node.nodes.map(node => convertNode(node)).join('');
if (node.decos.includes('/')) result = `<i>${result}</i>`;
if (node.decos.some(deco => /\*-/.test(deco[0]))) result = `<strong>${result}</strong>`;
if (node.decos.some(deco => deco[0] === '~')) result = `<strike>${result}</strike>`;
return result;
case 'helpfeel':
return `<code>? ${node.text}</code>`;
case 'code':
return `<code>${node.text}</code>`;
case 'commandLine':
return `<code>${node.symbol} ${node.text}</code>`;
case 'link':
switch(node.pathType) {
case 'root':
return `<span class="page-link">${node.href}<span>`;
case 'relative':
return `<span class="page-link">${node.href}</span>`;
case 'absolute':
return `<span class="link">${node.content ?? node.href}</span>`;
}
case 'hashTag':
return `<span class="page-link">${node.href}<span>`;
case 'blank':
case 'plain':
return node.text;
}
}