常用函数

常用函数

// 等待元素存在,带超时
function whenElementExist(selector, node, timeout = 5000) {
    return new Promise((resolve, reject) => {
        let isResolved = false;
        const check = () => {
            const el = typeof selector==='function'?selector():(node||document).querySelector(selector);
            if (el) {isResolved = true; resolve(el);} else if(!isResolved) requestAnimationFrame(check);
        };
        check();
        setTimeout(() => {
            if (!isResolved) {
                reject(new Error(`Timeout: Element not found for selector "${selector}" within ${timeout}ms`));
            }
        }, timeout);
    });
}

// 等待元素或变量存在
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元素添加到<head>中
    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, type = 'text') {
    return fetch("/api/file/getFile", {
        method: "POST",
        headers: {
            "Content-Type": "application/json",
        },
        body: JSON.stringify({
            path,
        }),
    }).then((response) => {
        if (response.ok) {
            if(type==='json') return response.json();
            else if(type==='blob') return response.blob();
            else 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 = `<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;
}

// 延迟执行
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})
    });
}

本地存储

see https://github.com/siyuan-note/siyuan/blob/1317020c1791edf440da7f836d366567e03dd843/app/src/protyle/util/compatibility.ts#L409

export const setStorageVal = (key: string, val: any, cb?: () => void) => {
    if (window.siyuan.config.readonly) {
        return;
    }
    fetchPost("/api/storage/setLocalStorageVal", {
        app: Constants.SIYUAN_APPID,
        key,
        val,
    }, () => {
        if (cb) {
            cb();
        }
    });
};
image.png

留下你的脚步
推荐阅读