生成文档树列表项
see https://ld246.com/article/1741359650489
pc端
// 第一步 调用 listDocsByPath获取文档树文档信息
//fetchSyncPost('/api/filetree/listDocsByPath', {notebook:'20240723175050-336994k',path:'/20240728220858-adaleye'})
// 第二步 调用genFileHTML函数生成li项
// see https://github.com/siyuan-note/siyuan/blob/1317020c1791edf440da7f836d366567e03dd843/app/src/layout/dock/Files.ts#L1224
function genFileHTML(item) {
let countHTML = "";
if (item.count && item.count > 0) {
countHTML = `<span class="popover__block counter b3-tooltips b3-tooltips__nw" aria-label="${window.siyuan.languages.ref}">${item.count}</span>`;
}
const ariaLabel = genDocAriaLabel(item, escapeAriaLabel);
const paddingLeft = (item.path.split("/").length - 1) * 18;
return `<li data-node-id="${item.id}" data-name="${Lute.EscapeHTMLStr(item.name)}" draggable="true" data-count="${item.subFileCount}"
data-type="navigation-file"
style="--file-toggle-width:${paddingLeft + 18}px"
class="b3-list-item b3-list-item--hide-action" data-path="${item.path}">
<span style="padding-left: ${paddingLeft}px" class="b3-list-item__toggle b3-list-item__toggle--hl${item.subFileCount === 0 ? " fn__hidden" : ""}">
<svg class="b3-list-item__arrow"><use xlink:href="#iconRight"></use></svg>
</span>
<span class="b3-list-item__icon b3-tooltips b3-tooltips__n popover__block" data-id="${item.id}" aria-label="${window.siyuan.languages.changeIcon}">${unicode2Emoji(item.icon || (item.subFileCount === 0 ? (window.siyuan.storage['local-images']?.file||'1f4c4') : (window.siyuan.storage['local-images']?.folder||'1f4d1')))}</span>
<span class="b3-list-item__text ariaLabel" data-position="parentE"
aria-label="${ariaLabel}">${getDisplayName(item.name, true, true)}</span>
<span data-type="more-file" class="b3-list-item__action b3-tooltips b3-tooltips__nw" aria-label="${window.siyuan.languages.more}">
<svg><use xlink:href="#iconMore"></use></svg>
</span>
<span data-type="new" class="b3-list-item__action b3-tooltips b3-tooltips__nw${window.siyuan.config.readonly ? " fn__none" : ""}" aria-label="${window.siyuan.languages.newSubDoc}">
<svg><use xlink:href="#iconAdd"></use></svg>
</span>
${countHTML}
</li>`;
}
function genDocAriaLabel(item, escapeMethod) {
return `${escapeMethod(getDisplayName(item.name, true, true))} <small class='ft__on-surface'>${item.hSize}</small>${item.bookmark ? "<br>" + window.siyuan.languages.bookmark + " " + escapeMethod(item.bookmark) : ""}${item.name1 ? "<br>" + window.siyuan.languages.name + " " + escapeMethod(item.name1) : ""}${item.alias ? "<br>" + window.siyuan.languages.alias + " " + escapeMethod(item.alias) : ""}${item.memo ? "<br>" + window.siyuan.languages.memo + " " + escapeMethod(item.memo) : ""}${item.subFileCount !== 0 ? window.siyuan.languages.includeSubFile.replace("x", item.subFileCount) : ""}<br>${window.siyuan.languages.modifiedAt} ${item.hMtime}<br>${window.siyuan.languages.createdAt} ${item.hCtime}`;
}
function escapeAriaLabel(html) {
if (!html) {
return html;
}
return html.replace(/"/g, """).replace(/'/g, "'")
.replace(/</g, "&lt;").replace(/</g, "&lt;");
}
function getDisplayName(filePath, basename = true, removeSY = false) {
let name = filePath;
if (basename) {
name = pathPosix().basename(filePath);
}
if (removeSY && name.endsWith(".sy")) {
name = name.substr(0, name.length - 3);
}
return name;
}
function pathPosix() {
if (require && require('path').posix) {
return require('path').posix;
}
return path;
}
// unicode转emoji
// 使用示例:unicode2Emoji('1f4c4');
// see https://ld246.com/article/1726920727424
function unicode2Emoji(unicode, className = "", needSpan = false, lazy = false) {
if (!unicode) {
return "";
}
let emoji = "";
if (unicode.indexOf(".") > -1) {
emoji = `<img class="${className}" ${lazy ? "data-" : ""}src="/emojis/${unicode}"/>`;
} else {
try {
unicode.split("-").forEach(item => {
if (item.length < 5) {
emoji += String.fromCodePoint(parseInt("0" + item, 16));
} else {
emoji += String.fromCodePoint(parseInt(item, 16));
}
});
if (needSpan) {
emoji = `<span class="${className}">${emoji}</span>`;
}
} catch (e) {
// 自定义表情搜索报错 https://github.com/siyuan-note/siyuan/issues/5883
// 这里忽略错误不做处理
}
}
return emoji;
}
手机端
// see https://github.com/siyuan-note/siyuan/blob/1317020c1791edf440da7f836d366567e03dd843/app/src/mobile/dock/MobileFiles.ts#L725
function genMobileFileHTML(item) {
let countHTML = "";
if (item.count && item.count > 0) {
countHTML = `<span class="counter">${item.count}</span>`;
}
return `<li data-node-id="${item.id}" data-name="${Lute.EscapeHTMLStr(item.name)}" data-type="navigation-file"
class="b3-list-item" data-path="${item.path}">
<span style="padding-left: ${(item.path.split("/").length - 1) * 20}px" class="b3-list-item__toggle${item.subFileCount === 0 ? " fn__hidden" : ""}">
<svg class="b3-list-item__arrow"><use xlink:href="#iconRight"></use></svg>
</span>
<span class="b3-list-item__icon">${unicode2Emoji(item.icon || (item.subFileCount === 0 ? (window.siyuan.storage['local-images']?.file||'1f4c4') : (window.siyuan.storage['local-images']?.folder||'1f4d1')))}</span>
<span class="b3-list-item__text">${getDisplayName(item.name, true, true)}</span>
<span data-type="more-file" class="b3-list-item__action b3-tooltips b3-tooltips__nw" aria-label="${window.siyuan.languages.more}">
<svg><use xlink:href="#iconMore"></use></svg>
</span>
<span data-type="new" class="b3-list-item__action b3-tooltips b3-tooltips__nw${window.siyuan.config.readonly ? " fn__none" : ""}" aria-label="${window.siyuan.languages.newSubDoc}">
<svg><use xlink:href="#iconAdd"></use></svg>
</span>
${countHTML}
</li>`;
};
封装通过文档id生成li项
async function getTreeDocById(id, box, path) {
if(!box || path) {
const doc = await fetchSyncPost('/api/filetree/getDoc', {id:id});
box = doc?.data?.box;
path = doc?.data?.path;
if(!box || !path) return;
}
if(path.toLocaleLowerCase().endsWith('.sy')) {
const pathArr = path.split('/');
pathArr.pop();
path = pathArr.join('/');
path = path === '' ? '/' : path;
}
let list = await fetchSyncPost('/api/filetree/listDocsByPath', {notebook:box, path:path});
list = list.data?.files?.filter(item=>item.id === id) || [];
return list[0];
}
