انتقل إلى المحتوى

ميدياويكي:Gadget-Numeral-converter-toggle.js

من ويكيبيديا، الموسوعة الحرة

ملاحظة: بعد الحفظ، قد يلزمك إفراغ الكاش لرؤية التغييرات (إفراغ الكاش الآن).

/**
 * Numeral converter toggle
 * forked from [[mw:MediaWiki:Gadget-Numerakri.js]]
 * maintainer حبيشان
 */
mw.loader.using(['mediawiki.cookie', 'mediawiki.util', 'mediawiki.user']).then(function () {
    'use strict';
    const skipclass = ['mwgadget-numconv-skip', 'mw-json'],
        we = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '%'],
        es = ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩', '٪'],
        rejectedTags = ['input', 'textarea', 'style', 'script', 'pre'],
        settingkey = 'gadget-Numeral_converter',
        msgs = {
            'numconv-turn-on-label': 'أرقام مشرقية',
            'numconv-turn-on-tooltip': 'تحويل الأرقام إلى أرقام مشرقية',
            'numconv-turn-off-label': 'أرقام مغربية',
            'numconv-turn-off-tooltip': 'إبقاء الأرقام مغربية',
        };

    var isOn = mw.loader.getState('ext.gadget.Numeral_converter') === 'ready',
        walker;

    function hasAnyClass(element, classes) {
		let ret = false;
		for(let i=1; i<classes.length; i++) {
   			if (element.hasClass(classes[i])) {
				ret = true;
				break;
			}
		}	
		return ret;
	}

    /**
     * @param {HTMLElement|TextNode} node
     * @return {number} NodeFilter.FILTER_* constant
     */
    function filterNode(node) {
        if (node.nodeType === Node.TEXT_NODE) {
            return NodeFilter.FILTER_ACCEPT;
        }
        var n = node.nodeName && node.nodeName.toLowerCase();
        if ( rejectedTags.indexOf(n) > -1 ||
            // node.hasAttribute('contenteditable') ||
            hasAnyClass($(node), skipclass)
        ) {
            // Skip this element and skip its children
            return NodeFilter.FILTER_REJECT;
        }
        // Skip this element, but check its children
        return NodeFilter.FILTER_SKIP;
    }

    /**
     * @param {TextNode} node
     */
    function handleTextNode(node) {
        function we2es(text) {
            for (let i=0; i <= 10; i++) {
                text = text.replaceAll(we[i], es[i]);
            }
            return text
        }
    
        function es2we(text) {
            for (let i=0; i <= 10; i++) {
                text = text.replaceAll(es[i], we[i]);
            }
            return text
        }
        var original = node.nodeValue,
            changed;
        if (isOn) {
            changed = we2es(original);
            changed = changed.replaceAll(/([A-z]\s*)([٠-٩٪\-\.]+)/g, (match, p1, p2, offset, string) => p1 + es2we(p2));
            changed = changed.replaceAll(/([٠-٩٪\-\.]+)([A-z])/g, (match, p1, p2, offset, string) => es2we(p1) + p2);
        } else {
            changed = es2we(original);
        }
        if (original !== changed) {
            node.nodeValue = changed;
        }
    }

    // https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw-method-requestIdleCallback
    function idleWalker(deadline) {
        var el;
        if (!walker) {
            return;
        }
        while (deadline.timeRemaining() > 0) {
            el = walker.nextNode();
            if (!el) {
                // Reached the end
                walker = null;
                return;
            }
            handleTextNode(el);
        }

        // The user may interact with the page. We pause so the browser can process
        // interaction. The text handler will continue after that.
        if (walker) {
            mw.requestIdleCallback(idleWalker);
        }
    }

    function startPageConversion() {
        if (isOn) {
            $('ol:lang(ar) li, ol.references, li.references').css('list-style-type', 'arabic-indic');
        } else {
            $('ol:lang(ar) li, ol.references, li.references').css('list-style-type', 'decimal');
        }
        // If a walker is already active, replace it.
        // If no walker is active yet, start it.
        if (!walker) {
            mw.requestIdleCallback(idleWalker);
        }
        walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, filterNode, false);
    }


    /**
     * Save a browser cookie for 30 days, or remove it.
     * @param {string|null} value
     */
    function saveType(value) {
        mw.requestIdleCallback(function () {
            if (mw.user.isAnon()) {
                mw.cookie.set(settingkey, value, { expires: 30 * 86400 , path: '/' });
            } else {
                new mw.Api().saveOption(settingkey, value);
                mw.user.options.set(settingkey, value);
            }
            mw.storage.session.set(settingkey, value);
        });
    }

    /**
     * @return {string}
     */
    function getStoredType() {
        var value = mw.user.isAnon() ? mw.cookie.get(settingkey, '0') : mw.user.options.get(settingkey) || '0';
        var svalue = mw.storage.session.get(settingkey);

        if (svalue && svalue !== value) {
            value = svalue;
            saveType(value);
        } else if (value && Number(value)>1 ) {
            value = value === '2'? '1': '0';
            saveType(value);
        }

        return value === '1';
    }

    function togglePortlets() {
        var labelSelector;
        switch (mw.config.get('skin')) {
            case 'vector':
            case 'vector-2022':
            case 'minerva':
                labelSelector = '#pt-numconvert span:not(:empty), #pt-numconvert-sticky-header span:not(:empty)';
                break;
            default:
                labelSelector = '#pt-numconvert a';
        }
        $(labelSelector).text(getMsg('label'));
        $('#pt-numconvert a, #pt-numconvert-sticky-header a')
            .attr('title', getMsg('tooltip'));
    }

    function setHtmlClass() {
        $(document.documentElement).toggleClass('numconv-on', isOn);
    }
    
    function toggleMode() {
        isOn = !isOn;
        saveType(isOn? '1': '0');
        togglePortlets();
        setHtmlClass()
        startPageConversion();
        //if (isOn) {
        //    mw.loader.load('ext.gadget.Numeral_converter');
        // } else {
        //     startPageConversion();
        // }
    }

    function getMsg(suffix) {
        var key = 'numconv-turn-' + (isOn ? 'off' : 'on') + '-' + suffix;
        return msgs[key];
    }

    function init() {

        // Decide selected type
        isOn = getStoredType();
        setHtmlClass();
        if (isOn && mw.user.isAnon()) {
            // mw.loader.load('ext.gadget.Numeral_converter');
            startPageConversion();
        }
        $(mw.util.addPortletLink(
            mw.user.isAnon() ? 'p-user-menu-anon-editor' : 'p-personal',
            '#',
            getMsg('label'),
            'pt-numconvert',
            getMsg('tooltip'),
            null,
            mw.user.isAnon() ?
                '#pt-createaccount' :
                '#pt-preferences'
        ))
		.children().on('click', function (e) {
			e.preventDefault();
			toggleMode();
		});
    };

    $(function () {
        mw.requestIdleCallback(init);
    });
});