<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh">
	<id>https://test.zybkcn.com/w/index.php?action=history&amp;feed=atom&amp;title=MediaWiki%3AGadget-TextSpacing.js</id>
	<title>MediaWiki:Gadget-TextSpacing.js - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://test.zybkcn.com/w/index.php?action=history&amp;feed=atom&amp;title=MediaWiki%3AGadget-TextSpacing.js"/>
	<link rel="alternate" type="text/html" href="https://test.zybkcn.com/w/index.php?title=MediaWiki:Gadget-TextSpacing.js&amp;action=history"/>
	<updated>2026-07-18T01:57:13Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.43.8</generator>
	<entry>
		<id>https://test.zybkcn.com/w/index.php?title=MediaWiki:Gadget-TextSpacing.js&amp;diff=274&amp;oldid=prev</id>
		<title>2026年6月14日 (日) 04:43 鹿野耕云</title>
		<link rel="alternate" type="text/html" href="https://test.zybkcn.com/w/index.php?title=MediaWiki:Gadget-TextSpacing.js&amp;diff=274&amp;oldid=prev"/>
		<updated>2026-06-14T04:43:35Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;a href=&quot;https://test.zybkcn.com/w/index.php?title=MediaWiki:Gadget-TextSpacing.js&amp;amp;diff=274&amp;amp;oldid=273&quot;&gt;显示更改&lt;/a&gt;</summary>
		<author><name>鹿野耕云</name></author>
	</entry>
	<entry>
		<id>https://test.zybkcn.com/w/index.php?title=MediaWiki:Gadget-TextSpacing.js&amp;diff=273&amp;oldid=prev</id>
		<title>鹿野耕云：​鹿野耕云移动页面MediaWiki:Gadget-text-spacing.js至MediaWiki:Gadget-TextSpacing.js，不留重定向</title>
		<link rel="alternate" type="text/html" href="https://test.zybkcn.com/w/index.php?title=MediaWiki:Gadget-TextSpacing.js&amp;diff=273&amp;oldid=prev"/>
		<updated>2026-06-14T04:42:43Z</updated>

		<summary type="html">&lt;p&gt;鹿野耕云移动页面&lt;a href=&quot;/w/index.php?title=MediaWiki:Gadget-text-spacing.js&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;MediaWiki:Gadget-text-spacing.js（页面不存在）&quot;&gt;MediaWiki:Gadget-text-spacing.js&lt;/a&gt;至&lt;a href=&quot;/wiki/MediaWiki:Gadget-TextSpacing.js&quot; title=&quot;MediaWiki:Gadget-TextSpacing.js&quot;&gt;MediaWiki:Gadget-TextSpacing.js&lt;/a&gt;，不留重定向&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;zh-Hans&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;←上一版本&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2026年6月14日 (日) 12:42的版本&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;4&quot; class=&quot;diff-notice&quot; lang=&quot;zh-Hans&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;（没有差异）&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;!-- diff cache key zybkcn_com:diff:1.41:old-99:rev-273 --&gt;
&lt;/table&gt;</summary>
		<author><name>鹿野耕云</name></author>
	</entry>
	<entry>
		<id>https://test.zybkcn.com/w/index.php?title=MediaWiki:Gadget-TextSpacing.js&amp;diff=99&amp;oldid=prev</id>
		<title>鹿野耕云：​创建页面，内容为“/**  * This gadget automatically adjust spacing between Chinese with English,  * with symbols and with numbers.  *  * @author User:Diskdance &lt;https://w.wiki/5F6e&gt;  * @license BSD-3-Clause  * @see https://github.com/diskdance/gadget-text-spacing  */ // &lt;nowiki&gt; (function () {     &#039;use strict&#039;;      const pendingActions = new WeakMap();     // Optimization: lazily execute pending actions once an element is visible     const observer = new IntersectionObserver…”</title>
		<link rel="alternate" type="text/html" href="https://test.zybkcn.com/w/index.php?title=MediaWiki:Gadget-TextSpacing.js&amp;diff=99&amp;oldid=prev"/>
		<updated>2025-11-24T02:55:13Z</updated>

		<summary type="html">&lt;p&gt;创建页面，内容为“&lt;span class=&quot;autocomment&quot;&gt;*  * This gadget automatically adjust spacing between Chinese with English,  * with symbols and with numbers.  *  * @author &amp;#91;&amp;#91;User:Diskdance&amp;#93;&amp;#93; &amp;lt;https://w.wiki/5F6e&amp;gt;  * @license BSD-3-Clause  * @see https://github.com/diskdance/gadget-text-spacing：​&lt;/span&gt; // &amp;lt;nowiki&amp;gt; (function () {     &amp;#039;use strict&amp;#039;;      const pendingActions = new WeakMap();     // Optimization: lazily execute pending actions once an element is visible     const observer = new IntersectionObserver…”&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;/**&lt;br /&gt;
 * This gadget automatically adjust spacing between Chinese with English,&lt;br /&gt;
 * with symbols and with numbers.&lt;br /&gt;
 *&lt;br /&gt;
 * @author [[User:Diskdance]] &amp;lt;https://w.wiki/5F6e&amp;gt;&lt;br /&gt;
 * @license BSD-3-Clause&lt;br /&gt;
 * @see https://github.com/diskdance/gadget-text-spacing&lt;br /&gt;
 */&lt;br /&gt;
// &amp;lt;nowiki&amp;gt;&lt;br /&gt;
(function () {&lt;br /&gt;
    &amp;#039;use strict&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
    const pendingActions = new WeakMap();&lt;br /&gt;
    // Optimization: lazily execute pending actions once an element is visible&lt;br /&gt;
    const observer = new IntersectionObserver(onIntersection);&lt;br /&gt;
    function onIntersection(entries) {&lt;br /&gt;
        for (const entry of entries) {&lt;br /&gt;
            if (!entry.isIntersecting) {&lt;br /&gt;
                continue;&lt;br /&gt;
            }&lt;br /&gt;
            const element = entry.target;&lt;br /&gt;
            observer.unobserve(element);&lt;br /&gt;
            const callbacks = pendingActions.get(element);&lt;br /&gt;
            if (callbacks === undefined) {&lt;br /&gt;
                continue;&lt;br /&gt;
            }&lt;br /&gt;
            while (true) {&lt;br /&gt;
                const callback = callbacks.shift(); // FIFO&lt;br /&gt;
                if (callback === undefined) {&lt;br /&gt;
                    break;&lt;br /&gt;
                }&lt;br /&gt;
                callback(element);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    function queueDomMutation(element, callback) {&lt;br /&gt;
        var _a;&lt;br /&gt;
        if (!pendingActions.has(element)) {&lt;br /&gt;
            pendingActions.set(element, []);&lt;br /&gt;
        }&lt;br /&gt;
        (_a = pendingActions.get(element)) === null || _a === void 0 ? void 0 : _a.push(callback);&lt;br /&gt;
        observer.observe(element);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function isInlineHTMLElement(node) {&lt;br /&gt;
        return (node instanceof HTMLElement &amp;amp;&amp;amp;&lt;br /&gt;
            window.getComputedStyle(node).display.includes(&amp;#039;inline&amp;#039;));&lt;br /&gt;
    }&lt;br /&gt;
    function isTextNode(node) {&lt;br /&gt;
        return node.nodeType === Node.TEXT_NODE;&lt;br /&gt;
    }&lt;br /&gt;
    function isVisible(element) {&lt;br /&gt;
        const style = window.getComputedStyle(element);&lt;br /&gt;
        return (style.display !== &amp;#039;none&amp;#039; &amp;amp;&amp;amp;&lt;br /&gt;
            ![&amp;#039;hidden&amp;#039;, &amp;#039;collapse&amp;#039;].includes(style.visibility) &amp;amp;&amp;amp;&lt;br /&gt;
            Number.parseFloat(style.opacity) &amp;gt; 0);&lt;br /&gt;
    }&lt;br /&gt;
    function getNodeText(node) {&lt;br /&gt;
        return node instanceof HTMLElement ? node.innerText : node.data;&lt;br /&gt;
    }&lt;br /&gt;
    /**&lt;br /&gt;
     * Split a string before an array of indexes.&lt;br /&gt;
     *&lt;br /&gt;
     * For example,&lt;br /&gt;
     * ```&lt;br /&gt;
     * splitAtIndexes(&amp;#039;123456789&amp;#039;, [3, 5, 7]);&lt;br /&gt;
     * ```&lt;br /&gt;
     * results in&lt;br /&gt;
     * ```&lt;br /&gt;
     * [&amp;#039;123&amp;#039;, &amp;#039;45&amp;#039;, &amp;#039;67&amp;#039;, &amp;#039;89&amp;#039;]&lt;br /&gt;
     * ```&lt;br /&gt;
     *&lt;br /&gt;
     * Note that empty string are included:&lt;br /&gt;
     * ```&lt;br /&gt;
     * splitAtIndexes(&amp;#039;123456789&amp;#039;, [0, 9]);&lt;br /&gt;
     * ```&lt;br /&gt;
     * results in&lt;br /&gt;
     * ```&lt;br /&gt;
     * [&amp;#039;&amp;#039;, &amp;#039;123456789&amp;#039;, &amp;#039;&amp;#039;]&lt;br /&gt;
     * ```&lt;br /&gt;
     *&lt;br /&gt;
     * Indexes that are negative or greater than the length of the string are ignored.&lt;br /&gt;
     *&lt;br /&gt;
     * @param str string to split&lt;br /&gt;
     * @param indexes indexes&lt;br /&gt;
     * @returns splitted string fragments&lt;br /&gt;
     */&lt;br /&gt;
    function splitAtIndexes(str, indexes) {&lt;br /&gt;
        const result = [];&lt;br /&gt;
        const normalizedIndexes = [&lt;br /&gt;
            // Remove duplications and sort in ascending order&lt;br /&gt;
            ...new Set(indexes&lt;br /&gt;
                .sort((a, b) =&amp;gt; a - b)&lt;br /&gt;
                .filter((i) =&amp;gt; i &amp;gt;= 0 &amp;amp;&amp;amp; i &amp;lt;= str.length)),&lt;br /&gt;
            str.length,&lt;br /&gt;
        ];&lt;br /&gt;
        for (let i = 0; i &amp;lt; normalizedIndexes.length; i++) {&lt;br /&gt;
            const slice = str.slice(normalizedIndexes[i - 1], normalizedIndexes[i]);&lt;br /&gt;
            result.push(slice);&lt;br /&gt;
        }&lt;br /&gt;
        return result;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const REGEX_RANGE_CHINESE = &amp;#039;(?:[\\u2E80-\\u2E99\\u2E9B-\\u2EF3\\u2F00-\\u2FD5\\u3005\\u3007\\u3021-\\u3029\\u3038-\\u303B\\u3400-\\u4DBF\\u4E00-\\u9FFF\\uF900-\\uFA6D\\uFA70-\\uFAD9]|\\uD81B[\\uDFE2\\uDFE3\\uDFF0\\uDFF1]|[\\uD840-\\uD868\\uD86A-\\uD86C\\uD86F-\\uD872\\uD874-\\uD879\\uD880-\\uD883][\\uDC00-\\uDFFF]|\\uD869[\\uDC00-\\uDEDF\\uDF00-\\uDFFF]|\\uD86D[\\uDC00-\\uDF38\\uDF40-\\uDFFF]|\\uD86E[\\uDC00-\\uDC1D\\uDC20-\\uDFFF]|\\uD873[\\uDC00-\\uDEA1\\uDEB0-\\uDFFF]|\\uD87A[\\uDC00-\\uDFE0]|\\uD87E[\\uDC00-\\uDE1D]|\\uD884[\\uDC00-\\uDF4A])&amp;#039;;&lt;br /&gt;
    const REGEX_RANGE_OTHER_LEFT = &amp;#039;[A-Za-z0-9@~%+=|±\\)}#$¥€£₤]&amp;#039;;&lt;br /&gt;
    const REGEX_RANGE_OTHER_RIGHT = &amp;#039;[A-Za-z0-9@~%+=|±\\({#$¥€£₤]&amp;#039;;&lt;br /&gt;
    const REGEX_STR_INTER_SCRIPT = `(?:(${REGEX_RANGE_CHINESE})(?=${REGEX_RANGE_OTHER_RIGHT})|(${REGEX_RANGE_OTHER_LEFT})(?=${REGEX_RANGE_CHINESE}))`;&lt;br /&gt;
    const SPACE = &amp;#039;\u200A&amp;#039;;&lt;br /&gt;
    const WRAPPER_CLASS = &amp;#039;gadget-space&amp;#039;;&lt;br /&gt;
    const SELECTOR_ALLOWED = [&lt;br /&gt;
        &amp;#039;a&amp;#039;, &amp;#039;abbr&amp;#039;, &amp;#039;article&amp;#039;, &amp;#039;aside&amp;#039;, &amp;#039;b&amp;#039;,&lt;br /&gt;
        &amp;#039;bdi&amp;#039;, &amp;#039;big&amp;#039;, &amp;#039;blockquote&amp;#039;, &amp;#039;button&amp;#039;,&lt;br /&gt;
        &amp;#039;caption&amp;#039;, &amp;#039;center&amp;#039;, &amp;#039;cite&amp;#039;, &amp;#039;data&amp;#039;,&lt;br /&gt;
        &amp;#039;dd&amp;#039;, &amp;#039;del&amp;#039;, &amp;#039;details&amp;#039;, &amp;#039;dfn&amp;#039;, &amp;#039;div&amp;#039;,&lt;br /&gt;
        &amp;#039;dt&amp;#039;, &amp;#039;em&amp;#039;, &amp;#039;figcaption&amp;#039;, &amp;#039;footer&amp;#039;,&lt;br /&gt;
        &amp;#039;h1&amp;#039;, &amp;#039;h2&amp;#039;, &amp;#039;h3&amp;#039;, &amp;#039;h4&amp;#039;, &amp;#039;h5&amp;#039;, &amp;#039;header&amp;#039;,&lt;br /&gt;
        &amp;#039;i&amp;#039;, &amp;#039;ins&amp;#039;, &amp;#039;label&amp;#039;, &amp;#039;legend&amp;#039;, &amp;#039;li&amp;#039;,&lt;br /&gt;
        &amp;#039;main&amp;#039;, &amp;#039;mark&amp;#039;, &amp;#039;option&amp;#039;, &amp;#039;p&amp;#039;, &amp;#039;q&amp;#039;,&lt;br /&gt;
        &amp;#039;ruby&amp;#039;, &amp;#039;s&amp;#039;, &amp;#039;section&amp;#039;, &amp;#039;small&amp;#039;, &amp;#039;span&amp;#039;,&lt;br /&gt;
        &amp;#039;strike&amp;#039;, &amp;#039;strong&amp;#039;, &amp;#039;sub&amp;#039;, &amp;#039;summary&amp;#039;,&lt;br /&gt;
        &amp;#039;sup&amp;#039;, &amp;#039;td&amp;#039;, &amp;#039;th&amp;#039;, &amp;#039;time&amp;#039;, &amp;#039;u&amp;#039;,&lt;br /&gt;
    ];&lt;br /&gt;
    const SELECTOR_BLOCKED = [&lt;br /&gt;
        &amp;#039;code&amp;#039;, &amp;#039;kbd&amp;#039;, &amp;#039;pre&amp;#039;, &amp;#039;rp&amp;#039;, &amp;#039;rt&amp;#039;,&lt;br /&gt;
        &amp;#039;samp&amp;#039;, &amp;#039;textarea&amp;#039;, &amp;#039;var&amp;#039;,&lt;br /&gt;
        // Elements with this class are excluded&lt;br /&gt;
        &amp;#039;.gadget-nospace&amp;#039;,&lt;br /&gt;
        // Editable elements&lt;br /&gt;
        &amp;#039;[contenteditable=&amp;quot;true&amp;quot;]&amp;#039;,&lt;br /&gt;
        // ACE editor content&lt;br /&gt;
        &amp;#039;.ace_editor&amp;#039;,&lt;br /&gt;
        // Visual Editor (and 2017 Wikitext Editor) content &amp;amp; diff&lt;br /&gt;
        &amp;#039;.ve-ui-surface&amp;#039;,&lt;br /&gt;
        &amp;#039;.ve-init-mw-diffPage-diff&amp;#039;,&lt;br /&gt;
        // Diff&lt;br /&gt;
        &amp;#039;.diff-context&amp;#039;,&lt;br /&gt;
        &amp;#039;.diff-addedline&amp;#039;,&lt;br /&gt;
        &amp;#039;.diff-deletedline&amp;#039;,&lt;br /&gt;
        // Diff (inline mode)&lt;br /&gt;
        &amp;#039;.mw-diff-inline-added&amp;#039;,&lt;br /&gt;
        &amp;#039;.mw-diff-inline-deleted&amp;#039;,&lt;br /&gt;
        &amp;#039;.mw-diff-inline-moved&amp;#039;,&lt;br /&gt;
        &amp;#039;.mw-diff-inline-changed&amp;#039;,&lt;br /&gt;
        &amp;#039;.mw-diff-inline-context&amp;#039;,&lt;br /&gt;
    ];&lt;br /&gt;
    // FIXME: Use :is() in the future once it has better browser compatibility&lt;br /&gt;
    const SELECTOR = SELECTOR_ALLOWED&lt;br /&gt;
        .map((allowed) =&amp;gt; `${allowed}:not(${SELECTOR_BLOCKED&lt;br /&gt;
    .flatMap((blocked) =&amp;gt; &lt;br /&gt;
// Not include itself if it is a tag selector&lt;br /&gt;
blocked[0].match(/[a-z]/i) ? `${blocked} *` : [blocked, `${blocked} *`])&lt;br /&gt;
    .join(&amp;#039;,&amp;#039;)})`)&lt;br /&gt;
        .join(&amp;#039;,&amp;#039;);&lt;br /&gt;
    function getLeafElements(parent) {&lt;br /&gt;
        const candidates = parent.querySelectorAll(SELECTOR);&lt;br /&gt;
        const result = [];&lt;br /&gt;
        if (parent.matches(SELECTOR)) {&lt;br /&gt;
            result.push(parent);&lt;br /&gt;
        }&lt;br /&gt;
        for (const candidate of candidates) {&lt;br /&gt;
            for (const childNode of candidate.childNodes) {&lt;br /&gt;
                if (isTextNode(childNode)) {&lt;br /&gt;
                    result.push(candidate);&lt;br /&gt;
                    break;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        return result;&lt;br /&gt;
    }&lt;br /&gt;
    function getNextVisibleSibling(node) {&lt;br /&gt;
        let currentNode = node;&lt;br /&gt;
        // Use loops rather than recursion for better performance&lt;br /&gt;
        while (true) {&lt;br /&gt;
            const candidate = currentNode.nextSibling;&lt;br /&gt;
            if (candidate === null) {&lt;br /&gt;
                const parent = currentNode.parentElement;&lt;br /&gt;
                if (parent === null) {&lt;br /&gt;
                    // Parent is Document, so no visible sibling&lt;br /&gt;
                    return null;&lt;br /&gt;
                }&lt;br /&gt;
                // Bubble up to its parent and get its sibling&lt;br /&gt;
                currentNode = parent;&lt;br /&gt;
                continue;&lt;br /&gt;
            }&lt;br /&gt;
            if (!(candidate instanceof HTMLElement || candidate instanceof Text)) {&lt;br /&gt;
                // Comments, SVGs, etc.: get its sibling as result&lt;br /&gt;
                currentNode = candidate;&lt;br /&gt;
                continue;&lt;br /&gt;
            }&lt;br /&gt;
            if (candidate instanceof HTMLElement) {&lt;br /&gt;
                if (!isVisible(candidate)) {&lt;br /&gt;
                    // Invisible: recursively get this element&amp;#039;s next sibling&lt;br /&gt;
                    currentNode = candidate;&lt;br /&gt;
                    continue;&lt;br /&gt;
                }&lt;br /&gt;
                if (!isInlineHTMLElement(candidate)) {&lt;br /&gt;
                    // Next sibling is not inline (at next line), so no siblings&lt;br /&gt;
                    return null;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            if (candidate instanceof Text &amp;amp;&amp;amp; candidate.data.trim() === &amp;#039;&amp;#039;) {&lt;br /&gt;
                // Skip empty Text nodes (e.g. line breaks)&lt;br /&gt;
                currentNode = candidate;&lt;br /&gt;
                continue;&lt;br /&gt;
            }&lt;br /&gt;
            return candidate;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    function createSpacingWrapper(str) {&lt;br /&gt;
        const span = document.createElement(&amp;#039;span&amp;#039;);&lt;br /&gt;
        span.className = WRAPPER_CLASS;&lt;br /&gt;
        span.textContent = str.slice(-1);&lt;br /&gt;
        return [str.slice(0, -1), span];&lt;br /&gt;
    }&lt;br /&gt;
    function adjustSpacing(element) {&lt;br /&gt;
        var _a;&lt;br /&gt;
        // Freeze NodeList in advance&lt;br /&gt;
        const childNodes = [...element.childNodes];&lt;br /&gt;
        const textSpacingPosMap = new Map();&lt;br /&gt;
        for (const child of childNodes) {&lt;br /&gt;
            if (!(child instanceof Text)) {&lt;br /&gt;
                continue;&lt;br /&gt;
            }&lt;br /&gt;
            const nextSibling = getNextVisibleSibling(child);&lt;br /&gt;
            let testString = getNodeText(child);&lt;br /&gt;
            if (nextSibling !== null) {&lt;br /&gt;
                // Append first character to detect script intersection&lt;br /&gt;
                testString += (_a = getNodeText(nextSibling)[0]) !== null &amp;amp;&amp;amp; _a !== void 0 ? _a : &amp;#039;&amp;#039;;&lt;br /&gt;
            }&lt;br /&gt;
            const indexes = [];&lt;br /&gt;
            // Global regexps are stateful so do initialization in each loop&lt;br /&gt;
            const regexTextNodeData = new RegExp(REGEX_STR_INTER_SCRIPT, &amp;#039;g&amp;#039;);&lt;br /&gt;
            while (true) {&lt;br /&gt;
                const match = regexTextNodeData.exec(testString);&lt;br /&gt;
                if (match === null) {&lt;br /&gt;
                    break;&lt;br /&gt;
                }&lt;br /&gt;
                indexes.push(match.index + 1); // +1 to match script boundary&lt;br /&gt;
            }&lt;br /&gt;
            if (indexes.length === 0) {&lt;br /&gt;
                // Optimization: skip further steps&lt;br /&gt;
                // Also prevent unnecessary mutation, which will be detected by MutationObserver,&lt;br /&gt;
                // resulting in infinite loops&lt;br /&gt;
                continue;&lt;br /&gt;
            }&lt;br /&gt;
            textSpacingPosMap.set(child, indexes);&lt;br /&gt;
        }&lt;br /&gt;
        // Schedule DOM mutation to prevent forced reflows&lt;br /&gt;
        queueDomMutation(element, () =&amp;gt; {&lt;br /&gt;
            for (const [node, indexes] of textSpacingPosMap) {&lt;br /&gt;
                const text = node.data;&lt;br /&gt;
                const fragments = splitAtIndexes(text, indexes);&lt;br /&gt;
                const replacement = fragments&lt;br /&gt;
                    .slice(0, -1)&lt;br /&gt;
                    .flatMap((fragment) =&amp;gt; createSpacingWrapper(fragment));&lt;br /&gt;
                replacement.push(fragments.slice(-1)[0]);&lt;br /&gt;
                // Optimization: prevent forced reflows&lt;br /&gt;
                requestAnimationFrame(() =&amp;gt; {&lt;br /&gt;
                    node.replaceWith(...replacement);&lt;br /&gt;
                });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
    function addSpaceToString(str) {&lt;br /&gt;
        const regex = new RegExp(REGEX_STR_INTER_SCRIPT, &amp;#039;g&amp;#039;);&lt;br /&gt;
        return str.replace(regex, `$1$2${SPACE}`);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function run(element) {&lt;br /&gt;
        const leaves = getLeafElements(element);&lt;br /&gt;
        for (const leaf of leaves) {&lt;br /&gt;
            adjustSpacing(leaf);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    const mutationObserver = new MutationObserver((records) =&amp;gt; {&lt;br /&gt;
        for (const record of records) {&lt;br /&gt;
            if (record.type !== &amp;#039;childList&amp;#039;) {&lt;br /&gt;
                continue;&lt;br /&gt;
            }&lt;br /&gt;
            const nodes = [...record.addedNodes];&lt;br /&gt;
            // Exclude mutations caused by adjustSpacing() to prevent infinite loops&lt;br /&gt;
            // Typically they will contain nodes with class WRAPPER_CLASS&lt;br /&gt;
            if (nodes.some((node) =&amp;gt; node instanceof HTMLElement &amp;amp;&amp;amp; node.classList.contains(WRAPPER_CLASS))) {&lt;br /&gt;
                continue;&lt;br /&gt;
            }&lt;br /&gt;
            for (const node of nodes) {&lt;br /&gt;
                if (node instanceof HTMLElement) {&lt;br /&gt;
                    run(node);&lt;br /&gt;
                }&lt;br /&gt;
                else if (node instanceof Text) {&lt;br /&gt;
                    const { parentElement } = node;&lt;br /&gt;
                    if (parentElement !== null) {&lt;br /&gt;
                        run(parentElement);&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
    function main() {&lt;br /&gt;
        document.title = addSpaceToString(document.title);&lt;br /&gt;
        // Watch for added nodes&lt;br /&gt;
        mutationObserver.observe(document.body, { subtree: true, childList: true });&lt;br /&gt;
        run(document.body);&lt;br /&gt;
    }&lt;br /&gt;
    $(main);&lt;br /&gt;
&lt;br /&gt;
})();&lt;br /&gt;
// &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>鹿野耕云</name></author>
	</entry>
</feed>