// 等待元素或变量存在
function whenExist(selector, parentNode = null, timeout = 5000, errorMsg = '') {
return new Promise((resolve, reject) => {
let timeoutId;
let isResolved = false;
const check = () => {
let element = null;
if (typeof selector === 'function') {
element = selector();
} else {
element = (parentNode||document).querySelector(selector);
}
if (element) {
isResolved = true;
if(timeoutId) clearTimeout(timeoutId);
resolve(element);
} else {
requestAnimationFrame(check);
}
};
check();
// 设置超时兜底
if(timeout > 0) timeoutId = setTimeout(() => {
if(isResolved) return;
console.error(errorMsg||`Element not found within ${timeout}ms`);
reject(new Error(errorMsg||`Element not found within ${timeout}ms`));
}, timeout);
});
}
// 请求api 简版
// 调用 await requestApi('/api/block/getChildBlocks', {id: '20241208033813-onlvfmp'});
async function requestApi(url, data, method = 'POST') {
return await (await fetch(url, {method: method, body: JSON.stringify(data||{})})).json();
}
// 请求api
async function fetchSyncPost(url, data, returnType = 'json') {
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 = returnType === 'json' ? await res.json() : await res.text();
return res2;
} catch(e) {
console.log(e);
return returnType === 'json' ? {code:e.code||1, msg: e.message||"", data: null} : "";
}
}
// 等待元素出现(简版)
function whenElementExist(selector, node) {
return new Promise(resolve => {
const check = () => {
const el = typeof selector==='function'?selector():(node||document).querySelector(selector);
if (el) resolve(el); else requestAnimationFrame(check);
};
check();
});
}
// 等待元素渲染完成后执行
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();
});
}
// 等待多个元素渲染完成
function whenElementsExist(selector) {
return new Promise(resolve => {
const checkForElement = () => {
let elements = null;
if (typeof selector === 'function') {
elements = selector();
} else {
elements = document.querySelectorAll(selector);
}
if (elements && elements.length > 0) {
resolve(elements);
} else {
requestAnimationFrame(checkForElement);
}
};
checkForElement();
});
}
// 等待元素渲染完成后执行(delay版)
function whenElementExist(selector, bySetTimeout = false, delay = 40, maxTime = 5000) {
return new Promise(resolve => {
let usedTime = 0;
const checkForElement = () => {
console.log('checkForElement', usedTime);
let element = null;
if (typeof selector === 'function') {
element = selector();
} else {
element = document.querySelector(selector);
}
if (element) {
resolve(element);
} else {
if (bySetTimeout) {
setTimeout(()=>{
usedTime += delay;
if(maxTime > usedTime) checkForElement();
}, delay);
} else {
requestAnimationFrame(checkForElement);
}
}
};
checkForElement();
});
}
// 查询SQL函数
async function query(sql) {
const result = await fetchSyncPost('/api/query/sql', { "stmt": sql });
if (result.code !== 0) {
console.error("查询数据库出错", result.msg);
return [];
}
return result.data;
}
// 添加style标签
function addStyle(css) {
// 创建一个新的style元素
const style = document.createElement('style');
// 设置CSS规则
style.innerHTML = css;
// 将style元素添加到中
document.head.appendChild(style);
}
// 支持创建文件夹,当isDir true时创建文件夹,忽略文件
async function putFile(path, content = '', isDir = false) {
const formData = new FormData();
formData.append("path", path);
formData.append("isDir", isDir)
formData.append("file", new Blob([content]));
const result = await fetch("/api/file/putFile", { // 写入js到本地
method: "POST",
body: formData,
});
const json = await result.json();
return json;
}
// 存储文件
function putFile(storagePath, data) {
const formData = new FormData();
formData.append("path", storagePath);
formData.append("file", new Blob([data]));
return fetch("/api/file/putFile", {
method: "POST",
body: formData,
}).then((response) => {
if (response.ok) {
//console.log("File saved successfully");
}
else {
throw new Error("Failed to save file");
}
}).catch((error) => {
console.error(error);
});
}
// 获取文件
async function getFile(path) {
return fetch("/api/file/getFile", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
path,
}),
}).then((response) => {
if (response.ok) {
return response.text();
} else {
throw new Error("Failed to get file content");
}
}).catch((error) => {
console.error(error);
});
}
// 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 = `
![]()
`;
} 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 = `
${emoji}`;
}
} catch (e) {
// 自定义表情搜索报错 https://github.com/siyuan-note/siyuan/issues/5883
// 这里忽略错误不做处理
}
}
return emoji;
}
// 延迟执行
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// 发送消息
function showMessage(message, isError = false, delay = 7000) {
return fetch('/api/notification/' + (isError ? 'pushErrMsg' : 'pushMsg'), {
"method": "POST",
"body": JSON.stringify({"msg": message, "timeout": delay})
});
}