MCBBS Wiki欢迎您共同参与编辑!在参与编辑之前请先阅读Wiki方针

如果在编辑的过程中遇到了什么问题,可以去讨论板提问。

为了您能够无阻碍地参与编辑 未验证/绑定过邮箱的用户,请尽快绑定/验证

MCBBS Wiki GitHub群组已上线!

您可以在回声洞中发表吐槽!

服务器状态监控。点击进入

本站由MCBBS用户自行搭建,与MCBBS及东银河系漫游指南(北京)科技有限公司没有从属关系。点此了解 MCBBS Wiki 不是什么>>

MediaWiki:HanziConverter.js

来自MCBBS Wiki
Salt lovely留言 | 贡献2021年4月15日 (四) 15:10的版本 (.)
跳到导航 跳到搜索

注意:在发布之后,您可能需要清除浏览器缓存才能看到所作出的变更的影响。

  • Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5Ctrl-R(Mac为⌘-R
  • Google Chrome:Ctrl-Shift-R(Mac为⌘-Shift-R
  • Internet Explorer或Edge:按住Ctrl的同时单击刷新,或按Ctrl-F5
  • Opera:Ctrl-F5
"use strict";
// 加载核心以及补充包、CSS
mw.loader.load("//mcbbs-wiki.cn/index.php?title=MediaWiki:HanziConverterCore.js&action=raw&ctype=text/javascript", "text/javascript");
mw.loader.load("//mcbbs-wiki.cn/index.php?title=MediaWiki:HanziConverterPlus.js&action=raw&ctype=text/javascript", "text/javascript");
mw.loader.load("//mcbbs-wiki.cn/index.php?title=MediaWiki:HanziConverterCSS.js&action=raw&ctype=text/css", "text/css");
// 外壳部分, 需要依靠核心部分来运行, 估计不支持IE
// 编译自TypeScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
(function () {
    let prefix = '[SaltHanziConverter]';
    let techprefix = 'SaltHanziConverter-';
    let ver = '0.1.0';
    let type = -1; // 默认-1 即不转换
    const ignoreElements = ['TEXTAREA', 'STYLE', 'SCRIPT', 'INPUT'];
    const scanAttributes = ['title', 'placeholder'];
    const log = console.log, time = console.time, timeEnd = console.timeEnd, HanziConverter = window.HanziConverterFunction;
    /**开关功能 */
    function userSwitch() {
        // 三种模式:强制简体/强制繁体/不作转换 分别对应 0/1/-1 汉/漢/无
        type = format2Integer(readWithDefault('HanziConverterType', -1));
        function format2Integer(n) {
            if (typeof n === 'number' && n % 1 === 0)
                return n;
            n = parseInt(n + '');
            if (isNaN(n))
                n = 0;
            return n;
        }
        // 添加切换按钮
        let frag = document.createDocumentFragment(), div = document.createElement('div');
        div.id = 'HanziConverterTypeSwitch';
        let t1 = document.createElement('span'), t2 = document.createElement('span'), t3 = document.createElement('span');
        t1.textContent = '汉';
        t3.textContent = '|';
        t2.textContent = '漢';
        t1.className = 's';
        t3.className = 'd';
        t2.className = 't';
        div.appendChild(t1);
        div.appendChild(t3);
        div.appendChild(t2);
        div.onclick = function () {
            type++;
            if (type > 1 || type < -1)
                type = -1;
            write('HanziConverterType', type);
            styleChange();
            checkAndConvert();
            checkAttributeAndConvert();
        };
        styleChange();
        frag.appendChild(div);
        function styleChange() {
            switch (type) {
                case 1:
                    div.className = 'simplified';
                    div.title = '文字转为简体';
                    break;
                case 0:
                    div.className = 'traditional';
                    div.title = '文字转为繁体';
                    break;
                default:
                    div.className = 'none';
                    div.title = '不作繁简转化';
                    break;
            }
        }
        // 适配网页
        document.body.appendChild(frag);
    }
    /**主过程 */
    function main() {
        userSwitch();
        checkAndConvert();
        checkAttributeAndConvert();
        // MW会不停地翻新某个script导致监视器被不停触发...
        // 因此需要节流
        setTimeout(() => {
            let observer = new MutationObserver(function (records) {
                // for of比map性能更好
                for (let record of records)
                    for (let node of record.addedNodes)
                        checkAndConvert(node);
            });
            observer.observe(document.body, {
                subtree: true,
                attributes: false,
                childList: true,
                characterData: false
            });
            let attrObserver = new MutationObserver(function (records) {
                var _a;
                // for of比map性能更好
                for (let record of records)
                    if (scanAttributes.indexOf((_a = record.attributeName) !== null && _a !== void 0 ? _a : '') != -1 && record.target instanceof HTMLElement)
                        checkAttributeAndConvert(record.target);
            });
            attrObserver.observe(document.body, {
                subtree: true,
                attributes: true,
                childList: false,
                characterData: false
            });
        }, 1500);
        setTimeout(() => {
            checkAndConvert();
            checkAttributeAndConvert();
        }, 1500);
        // 整活
        log(HanziConverter(prefix + ' 一只忧郁的台湾乌龟', type));
    }
    /** */
    function docReady(callback) {
        if (document.readyState == 'loading')
            document.addEventListener('DOMContentLoaded', () => {
                callback();
            });
        else
            callback();
    }
    /**主要功能 */
    function checkAndConvert(target = document.body) {
        return __awaiter(this, void 0, void 0, function* () {
            if (type != 0 && type != 1)
                return;
            // time(prefix + ' Text')
            let nodes = findAllTextNodes(target);
            for (let i = 0; i < nodes.length; i++) {
                let node = nodes[i];
                if (typeof node.textContent == 'string') {
                    let _temp = HanziConverter(node.textContent, type);
                    if (node.textContent != _temp) // 防止过于频繁的写入
                        node.textContent = _temp;
                }
            }
            // timeEnd(prefix + ' Text') // WikiText近48w字节的页面也能在350ms内搞定, 而且全程异步不影响操作
        });
    }
    /**替换属性中的汉字 */
    function checkAttributeAndConvert(parentElement = document.body) {
        return __awaiter(this, void 0, void 0, function* () {
            if (type != 0 && type != 1)
                return;
            // time(prefix + ' Attr')
            for (let _temp of scanAttributes)
                convertAttribute(_temp, parentElement);
            // timeEnd(prefix + ' Attr') // 耗时很短, 不过为了应付意外情况, 还是选择了异步
        });
    }
    /**查找所有的文字节点 */
    function findAllTextNodes(parent) {
        var _a, _b, _c;
        let nodes = [];
        if (parent.hasChildNodes()) {
            let children = Array.from(parent.childNodes);
            for (let n of children) {
                if (((_a = n.parentElement) === null || _a === void 0 ? void 0 : _a.id) == 'HanziConverterTypeSwitch')
                    continue;
                if (ignoreElements.indexOf((_c = (_b = n.parentElement) === null || _b === void 0 ? void 0 : _b.tagName.toUpperCase()) !== null && _c !== void 0 ? _c : '') != -1)
                    continue;
                if (n.nodeType == 3)
                    nodes.push(n);
                else
                    nodes.push(...findAllTextNodes(n));
            }
        }
        return nodes;
    }
    /**替换范围内所有元素的属性 */
    function convertAttribute(attr, parentElement) {
        var _a;
        let nodes = parentElement.querySelectorAll('*[' + attr + ']'), _temp = '';
        for (let i = 0; i < nodes.length; i++) {
            let n = nodes[i];
            if (n instanceof HTMLElement && (_temp = (_a = n.getAttribute(attr)) !== null && _a !== void 0 ? _a : '').length > 0) {
                let _temp_ = HanziConverter(_temp, type);
                if (_temp_ != _temp)
                    n.setAttribute(attr, _temp_);
            }
        }
    }
    /**
     * 根据key存入本地存储
     * @param key 键值
     * @param value 要存放的值
     */
    function write(key, value) {
        if (value) {
            value = JSON.stringify(value);
        }
        localStorage.setItem(techprefix + key, value);
    }
    /**
     * 根据key读取本地数据
     * @param key 键值
     */
    function readWithDefault(key, defaultValue) {
        let value = localStorage.getItem(techprefix + key);
        if (value && value != "undefined" && value != "null") {
            let temp = JSON.parse(value);
            if (typeof defaultValue == 'boolean' && typeof temp == 'string') { // 防坑措施
                // @ts-ignore
                if (temp == 'true') {
                    temp = true;
                }
                else {
                    temp = false;
                }
            }
            return temp;
        }
        write(key, defaultValue);
        return defaultValue;
    }
    /**
     * 节流函数,必定执行最后一次操作
     * @param threshold 阈值
     * @param handler 要执行的函数
     * @param _arguments 要执行的函数的参数
     */
    let throttled = function (handler, threshold = 500, ..._arguments) {
        let throttledTimer, throttledLastTrigger, timerTriggered = true;
        return function () {
            let now = new Date().getTime(), timePast = now - (throttledLastTrigger !== null && throttledLastTrigger !== void 0 ? throttledLastTrigger : 0);
            if (timePast < threshold) {
                if (timerTriggered) {
                    timerTriggered = false;
                    throttledTimer = setTimeout(() => {
                        // log('TimeoutRunHandler ' + timerTriggered)
                        timerTriggered = true;
                        throttledLastTrigger = new Date().getTime();
                        handler(..._arguments);
                    }, threshold - timePast);
                }
            }
            else {
                if (!timerTriggered) {
                    clearTimeout(throttledTimer);
                    // log('ClearTimeout ' + timerTriggered)
                }
                // log('RunHandler ' + timerTriggered)
                timerTriggered = false;
                throttledLastTrigger = now;
                handler(..._arguments);
                timerTriggered = true;
            }
        };
    };
    // /** 
    //  * assert: 断言
    //  * @param condition 为假时报错
    //  * @param msg 报错语句,默认为“发生错误”
    //  * */
    // function assert(condition: any, msg?: string): asserts condition {
    //     if (!condition) throw new Error(prefix + ': ' + (msg ?? '发生错误'))
    // }
    // /**version: 显示版本*/
    // function version() {
    //     log(prefix + ' ' + ver)
    // }
    docReady(main);
})();