🏠 Home 

我帮你加上空格嗷~

在英文和其他文字之间,添加一个空格,让排版变得更舒适,也更利于阅读,


Install this script?
// ==UserScript==
// @name        我帮你加上空格嗷~
// @namespace   Maybe you forgot a space.
// @match       *://*/*
// @grant       none
// @author      稻米鼠
// @version     0.0.5
// @author      -
// @description 在英文和其他文字之间,添加一个空格,让排版变得更舒适,也更利于阅读,
// ==/UserScript==
window.addEventListener('load', async function(){
/**
* observer 配置
* @property { boolean } childList - 观察目标子节点的变化,比如添加或者删除目标子节点,不包括修改子节点以及子节点后代的变化
* @property { boolean } subtree - 目标以及目标的后代改变都会观察
* @property { boolean } attributes - 观察目标属性的改变
* @property { boolean } characterData - 观察目标数据的改变
* @property { boolean } attributeOldValue - 默认为 true,表示需要记录改变前的目标属性值,设置了 attributeOldValue 可以省略 attributes 设置
* @property { boolean } characterDataOldValue - 默认为 true,表示需要记录改变前的目标数据值,设置了 characterDataOldValue 可以省略 characterData 设置
* @property { array } attributeFilter - 如果不是所有的属性改变都需要被观察,并且 attributes 设置为 true 或者被忽略,那么设置一个需要观察的属性本地名称(不需要命名空间)的列表
*/
const config = {
attributeOldValue: false,
characterData: true,
childList: true,
subtree: true,
};
/**
* 遍历元素的全部祖先元素,判断是否应该对此元素进行进一步处理
* @param {*} el 要测试段元素
*/
const nodeTester = el=>{
if(/^body$/i.test(el.tagName)){
return true
}else if(
/^(style|script|pre|code)$/i.test(el.tagName)
|| /^true$/i.test(el.contentEditable)
){
return false
}else{
return nodeTester(el.parentNode)
}
}
/**
* 递归处理元素和子元素
*
* @param { object } el 页面元素
* @returns
*/
const addSpace = async el=>{
// 如果 这是一个文本节点,则对内容进行替换
// [英文 和 标点]与其他内容之间,加上空格
if( el.nodeType === Node.TEXT_NODE ){
el.textContent = el.textContent
.replace(/([^\s\w\p{P}])([\w\p{P}]+)/gu, (match, p1, p2) =>
/[a-zA-Z0-9]/.test(p2) ? p1 + ' ' + p2 : match
)
.replace(/([\w\p{P}]+)([^\s\w\p{P}])/gu, (match, p1, p2) =>
/[a-zA-Z0-9]/.test(p1) ? p1 + ' ' + p2 : match
);
}else if(
el.nodeType === Node.ELEMENT_NODE
&& nodeTester(el)
){
// 如果这是一个元素节点,并且不是特殊元素,则对它的子元素进行遍历
for await (e of el.childNodes){
await addSpace(e)
}
}
return Promise.resolve()
}
// 页面加载完成后处理整个页面
await addSpace(document.body)
// 声明用以监控页面的 observer 对象
let observer
/**
* 当页面发生变化时,处理记录元素变化的数组
*
* @param { array } record MutationRecord
* @returns
*/
const pageChangeWatcher = async record =>{
// 先停止对页面变化的监控,避免陷入死循环
observer.disconnect()
// 发生变化的元素合集
const els = record
// 改变的类型为 characterData,并且不是 body 元素的话
.filter(
(e) =>
/^characterData$/i.test(e.type) && !/^body$/i.test(e.target.tagName)
)
.map((e) => e.target) // 把发生改变的元素放入合集
// 改变的类型为 childList,则把新增的元素放入合集
record.filter( e=>/^childList$/i.test(e.type)).forEach(e=>{
e.addedNodes.forEach(node=>els.push(node))
})
// 遍历合集中所有元素
for await (e of els){
if(nodeTester(e)) await addSpace(e)
}
// 页面处理完成之后重新监控页面变化
if(observer) observer.observe(document.body, config);
}
// 监控页面变化
observer = new MutationObserver(pageChangeWatcher);
observer.observe(document.body, config);
})