Wilson@思源

目 录

把用户自定义属性显示到块的右侧

js
// 思源把用户自定义属性显示到块的右上侧 // see https://ld246.com/article/1732940163490 // version: 0.0.2 // 更新记录 // 0.0.2 可自定义是否显示提示,可自定义属性白名单和黑名单 // 注意,打开属性面板通过模拟按键实现,如果修改了打开属性快捷键请修改openCustomAttrsPage函数的按键映射,否则可能无法模拟按键 (()=>{ // 鼠标移上去是否显示提示 const isShowTips = false; // 属性白名单 // 下面的自定义属性们显示到右侧,不设置保持空即可。 // 不需要带custom-前缀,白名单和黑名单有任意一个生效即生效 let onlyTheseAttrs = [ //'', ]; // 属性黑名单 // 下面的自定义属性们不显示到右侧,不设置保持空即可。 // 不需要带custom-前缀,白名单和黑名单有任意一个生效即生效 let notTheseAttrs = [ 'avs', // 默认过滤数据库的自定义属性 ]; // 自定义属性的svg const attrSvg = ``; // 格式化白名单和黑名单 if(onlyTheseAttrs.length > 0) onlyTheseAttrs = onlyTheseAttrs.map(item => item.replace(/^custom\-/i, '')); if(notTheseAttrs.length > 0) notTheseAttrs = notTheseAttrs.map(item => item.replace(/^custom\-/i, '')); // 监听自定义属性被添加 let lastAttrWrap = null; observeCustomAttributes('custom-', (element, attrName, attrValue, type) => { // 过滤白名单和黑名单,有任意一个生效即生效 if(onlyTheseAttrs.length > 0 && !onlyTheseAttrs.includes(attrName.replace(/^custom\-/i, ''))) return; if(notTheseAttrs.length > 0 && notTheseAttrs.includes(attrName.replace(/^custom\-/i, ''))) return; // 把自定义属性显示到右侧 const protyleAttr = element.querySelector('.protyle-attr'); if(!protyleAttr) return; // 创建wrap let customAttrsWrap = element.querySelector('.protyle-attr--custom'); if(!customAttrsWrap){ customAttrsWrap = document.createElement('div'); customAttrsWrap.className = 'protyle-attr--custom'; customAttrsWrap.innerHTML = attrSvg; customAttrsWrap.addEventListener('click', (event) => { openCustomAttrsPage(element); }); protyleAttr.appendChild(customAttrsWrap); } // 创建属性 let attrEl = customAttrsWrap.querySelector('.' + attrName); if(!attrEl){ attrEl = document.createElement('span'); attrEl.className = 'custom-attr-item ' + attrName; customAttrsWrap.appendChild(attrEl); } attrEl.textContent = attrValue; // 添加标题 if (isShowTips) { if(lastAttrWrap !== customAttrsWrap) { lastAttrWrap = customAttrsWrap; customAttrsWrap.title = ''; setTimeout(() => { lastAttrWrap = null; customAttrsWrap.title = customAttrsWrap.title.replace(/\n$/, ''); }, 1000); } customAttrsWrap.title += attrName + ' : ' + attrValue + "\n"; } }); // 添加样式 addStyle(`.protyle-attr--custom { .custom-attr-item:not(:last-child) {margin-right: 4px;} svg {fill: currentColor;} }`); // 添加style标签 function addStyle(css) { // 创建一个新的style元素 const style = document.createElement('style'); // 设置CSS规则 style.innerHTML = css; // 将style元素添加到中 document.head.appendChild(style); } // 打开属性面板,并切换到自定义属性选项卡 function openCustomAttrsPage(node) { // 模拟按键 let keyInit = { ctrlKey: !isMac(), altKey: true, metaKey: isMac(), shiftKey: false, key: 'A', keyCode: 65 } keyInit["bubbles"] = true; let keydownEvent = new KeyboardEvent('keydown', keyInit); (node || document.getElementsByTagName("body")[0]).dispatchEvent(keydownEvent); let keyUpEvent = new KeyboardEvent('keyup', keyInit); (node || document.getElementsByTagName("body")[0]).dispatchEvent(keyUpEvent); // 模拟点击 whenElementExist('div.b3-dialog--open[data-key="dialog-attr"]').then((dialog) => { dialog.querySelector('.layout-tab-bar .item--full[data-type="custom"]').click(); }); } // 判断是否Mac function isMac() { return navigator.platform.indexOf("Mac") > -1; } // 等待元素渲染完成后执行 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 observeCustomAttributes(prefix = 'custom-', callback, targetNode = document.body) { let lastAttrNames = [], lastAttrNamesTimer = null; // 观察器的配置 const config = { childList: true, attributes: true, subtree: true }; // 创建一个观察器实例并传入回调函数 const observer = new MutationObserver((mutationsList) => { for (let mutation of mutationsList) { // 监听元素加载 if (mutation.type === 'childList') { // 检查新增的节点 for (const node of mutation.addedNodes) { if(node.nodeType === Node.ELEMENT_NODE) { // 获取所有以'custom-'开头的属性 const customAttrs = Array.from(node.attributes).filter(attr => attr.name.startsWith(prefix)); if (customAttrs.length > 0) { customAttrs.forEach(attr => { callback(node, attr.name, attr.value, 'load'); }); } } } } // 监听属性变化 if (mutation.type === 'attributes') { const attributeName = mutation.attributeName; // 检查属性名是否以指定前缀开头 if (attributeName.startsWith(prefix)) { // 防止多次重复触发 if(lastAttrNames.includes(attributeName)) continue; lastAttrNames.push(attributeName); if(!lastAttrNamesTimer) lastAttrNamesTimer = setTimeout(() => { lastAttrNames = []; lastAttrNamesTimer = null; }, 1000); // 如果提供了回调函数,则调用它 if (typeof callback === 'function') { callback(mutation.target, attributeName, mutation.target.getAttribute(attributeName), 'add'); } } } } }); // 开始观察目标节点 observer.observe(targetNode, config); // 返回一个断开连接的方法 return () => observer.disconnect(); } })();
see https://ld246.com/article/1732940163490