(async ()=>{
const defaultCodeLang = "";
const recentlyCodeLangLength = 10;
let topCodeLang = [];
const storagePath = "/data/storage/recently_code_lang.json";
let recentlyCodeLang = await getFile(storagePath);
topCodeLang.reverse();
let codeTimer = null;
whenElementExist(".layout__center").then((element)=>{
const layoutCenter = element;
const observer = observeDomChange(layoutCenter, (mutation) => {
if(mutation.target.classList.contains("protyle-util")) {
const codeList = mutation.target.querySelector(".b3-list--background");
if(codeList){
const firstChild = codeList.firstElementChild;
sortLangList([...recentlyCodeLang, ...topCodeLang], codeList, firstChild);
}
}
if(mutation.target.classList.contains("code-block") || mutation.target.classList.contains("hljs")) {
if(codeTimer) clearTimeout(codeTimer);
codeTimer = setTimeout(() => {
const codeBlock = mutation.target.closest(".code-block");
const langText = codeBlock?.querySelector(".protyle-action__language")?.textContent;
addLanguage(langText);
setDefaultLang();
}, 40);
}
});
addLanguage(getLastLang());
setDefaultLang();
});
function sortLangList(topCodeLang, listContainer, clearItem) {
topCodeLang.forEach(lang => {
const item = Array.from(listContainer.querySelectorAll('.b3-list-item')).find(item => item.textContent.trim() === lang);
if (item) {
listContainer.insertBefore(item, clearItem.nextSibling);
} else {
const newElement = document.createElement('div');
newElement.className = 'b3-list-item';
newElement.textContent = lang;
listContainer.insertBefore(newElement, clearItem.nextSibling);
}
});
listContainer.querySelector(".b3-list-item--focus").classList.remove("b3-list-item--focus");
listContainer.children[1].classList.add("b3-list-item--focus");
}
async function addLanguage(language) {
if(!language) return;
language = getLastLang();
if(!language) return;
if(recentlyCodeLang[recentlyCodeLang.length-1] === language) {
return;
}
const index = recentlyCodeLang.indexOf(language);
if (index !== -1) {
recentlyCodeLang.splice(index, 1);
}
recentlyCodeLang.push(language);
while (recentlyCodeLang.length > recentlyCodeLangLength) {
recentlyCodeLang.shift();
}
putFile(storagePath, recentlyCodeLang);
}
function setDefaultLang() {
if(defaultCodeLang) window.siyuan.storage["local-codelang"] = defaultCodeLang;
}
function getLastLang() {
return window.siyuan.storage["local-codelang"];
}
async function getLastLangFromDb() {
const sql = `SELECT markdown FROM blocks WHERE type = 'c' ORDER by updated DESC limit 1`;
const result = await fetchSyncPost('/api/query/sql', {"stmt": sql});
if(result.data[0]?.markdown){
return result.data[0].markdown.split("\n")[0].replace('```', '');
}
return "";
}
async function getFile(storagePath) {
if(!storagePath) return [];
const data = await fetchSyncPost('/api/file/getFile', {"path":`${storagePath}`});
if(data.code && data.code !== 0) return [];
return data;
}
function putFile(storagePath, data) {
const formData = new FormData();
formData.append("path", storagePath);
formData.append("file", new Blob([JSON.stringify(data)]));
return fetch("/api/file/putFile", {
method: "POST",
body: formData,
}).then((response) => {
if (response.ok) {
}
else {
throw new Error("Failed to save file");
}
}).catch((error) => {
console.error(error);
});
}
async function fetchSyncPost (url, data) {
const init = {
method: "POST",
};
if (data) {
if (data instanceof FormData) {
init.body = data;
} else {
init.body = JSON.stringify(data);
}
}
try {
const res = await fetch(url, init);
const res2 = await res.json();
return res2;
} catch(e) {
console.log(e)
return [];
}
}
function observeDomChange(targetNode, callback) {
const config = { childList: true, subtree: true };
const observer = new MutationObserver((mutationsList) => {
for (const mutation of mutationsList) {
if (mutation.type === 'childList') {
callback(mutation);
}
}
});
observer.observe(targetNode, config);
return observer;
}
function whenElementExist(selector) {
return new Promise(resolve => {
const checkForElement = () => {
let element = null;
if (typeof selector === 'function') {
element = selector();
} else {
element = document.querySelector(selector);
}
if (element) {
resolve(element);
} else {
requestAnimationFrame(checkForElement);
}
};
checkForElement();
});
}
})();