NSSF : Khmer Number to Arabic Number Converter

Convert Khmer numbers inside NSSF targeting invoice number in to Arabic ones and copy it to clipboard.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name          NSSF : Khmer Number to Arabic Number Converter
// @namespace     lychanraksmey.eu.org
// @author        LCR
// @version       1.5 
// @description   Convert Khmer numbers inside NSSF targeting invoice number in to Arabic ones and copy it to clipboard.
// @match         https://enterprise.nssf.gov.kh/*
// @icon          https://www.google.com/s2/favicons?sz=64&domain=nssf.gov.kh
// @grant         GM_setClipboard
 // @license      MIT 
// ==/UserScript==

(function() {
    'use strict';
    const khmerToArabicMap = {
        '០': '0',
        '១': '1',
        '២': '2',
        '៣': '3',
        '៤': '4',
        '៥': '5',
        '៦': '6',
        '៧': '7',
        '៨': '8',
        '៩': '9'
    };

    function khmerToArabic(str) {
        return str.replace(/[០-៩]/g, m => khmerToArabicMap[m] || m);
    }

    function getElementsByXPath(xpath) {
        const result = [];
        const query = document.evaluate(xpath, document, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
        let node = query.iterateNext();
        while (node) {
            result.push(node);
            node = query.iterateNext();
        }
        return result;
    }

    function createToolbarButton(id, text, color, onClick) {
        const btn = document.createElement('button');
        btn.id = id;
        btn.textContent = text;
        btn.style.backgroundColor = color;
        btn.style.color = 'white';
        btn.style.padding = '5px 10px'; 
        btn.style.margin = '0 5px'; // Small margin for spacing between buttons
        btn.style.border = 'none';
        btn.style.borderRadius = '4px';
        btn.style.cursor = 'pointer';
        btn.style.whiteSpace = 'nowrap';
        btn.addEventListener('click', onClick);
        return btn;
    }
    function injectConversionDiv() {
        const targetToolbar = document.querySelector('mat-toolbar.app-toolbar');
        if (!targetToolbar) {
            console.log("Target mat-toolbar not found, trying again in 500ms...");
            setTimeout(injectConversionDiv, 500);
            return;
        }
        const convertDiv = document.createElement('div');
        convertDiv.id = 'conversionDiv';
        convertDiv.style.flexGrow = '1';
        convertDiv.style.display = 'flex';
        convertDiv.style.justifyContent = 'center';
        convertDiv.style.alignItems = 'center';
        convertDiv.style.height = '100%';
        const convertButton = createToolbarButton(
            'floating-convert-btn',
            '♻ Convert',
            '#e74c3c', // Red
            convertBtnHandler
        );
        convertDiv.appendChild(convertButton);

        const copyMoneyButton = createToolbarButton(
            'floating-copy-money-btn',
            '💵 Copy Money',
            '#944ce0', // Purple
            copyMoneyBtnHandler
        );
        convertDiv.appendChild(copyMoneyButton);
        targetToolbar.prepend(convertDiv);
        window.convertButton = convertButton;
        window.copyMoneyButton = copyMoneyButton;
        window.hasConverted = false;
    }

    function convertBtnHandler() {
        const btn = window.convertButton;
        const hasConverted = window.hasConverted;

        document.querySelectorAll('.mat-tab-label-content').forEach((el, i) => {
           // console.log(`[${i}]`, el.textContent.trim()); for Tabs debugging
        });
        const invoiceTab = document.querySelectorAll('.mat-tab-label')[3];
        if (invoiceTab) invoiceTab.click();

        setTimeout(() => {
            if (!hasConverted) {
                // First click: perform conversion and switch behavior
                const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false);
                const regex = /[០-៩]{8}-[០-៩]{2}/g;
                let node;

                while ((node = walker.nextNode())) {
                    if (regex.test(node.nodeValue)) {
                        const span = document.createElement('span');
                        let newHTML = node.nodeValue.replace(regex, match => {
                            console.log('Matched Number', match);
                            const converted = khmerToArabic(match);
                            return `<h2>${match}</h2><br><h2 class="converted-khmer" style="margin-top:2px; margin-bottom:10px; font-weight:bold; color:#e74c3c;">${converted}</h2>`;
                        });
                        span.innerHTML = newHTML; //keep Khmer Number for referencing.
                        node.parentNode.replaceChild(span, node);
                    } else {
                        const convertedText = khmerToArabic(node.nodeValue);
                        if (convertedText !== node.nodeValue) {
                            node.nodeValue = convertedText;
                        }
                    }
                }

                btn.textContent = '📋 Copy ID';
                btn.style.backgroundColor = '#3498db';
                window.hasConverted = true;
                return;
            }

            // Second click: copy logic
            const match = document.body.innerText.match(/\b\d{8}-\d{2}\b/);
            if (match) {
                GM_setClipboard(match[0]);
                btn.textContent = `✅ Copied ${match[0]}`;
                btn.style.backgroundColor = '#2ecc71';

                setTimeout(() => {
                    btn.textContent = '📋 Copy ID';
                    btn.style.backgroundColor = '#3498db';
                }, 2000);
            } else {
                btn.textContent = 'No valid ID';
                btn.style.backgroundColor = '#e74c3c';
                setTimeout(() => {
                    btn.textContent = '♻ Convert'; 
                    btn.style.backgroundColor = '#e74c3c'; 
                }, 2000);
                console.log("No valid ID");
            }
         }, 50);
    }

    function copyMoneyBtnHandler() {
        const btnMoney = window.copyMoneyButton;
        const invoiceTab = document.querySelectorAll('.mat-tab-label')[3];
        if (invoiceTab) invoiceTab.click();

        setTimeout(() => {
            if (!btnMoney) return;
            let moneyToCopy = '';
            const fallbackTds = getElementsByXPath("//td[contains(text(), ',') and not(contains(text(), '-'))]");
            if (fallbackTds.length > 0) {
                for (let i = 0; i < fallbackTds.length; i++) {
                    const currentValue = fallbackTds[i].textContent.trim();
                }                
                const lastValue = fallbackTds[fallbackTds.length - 1].textContent.trim();
                moneyToCopy = lastValue; // Target the last matching <td> element
            }

            if (moneyToCopy) {
                const cleanedMoney = moneyToCopy.replace(/,/g, '');
                GM_setClipboard(cleanedMoney);
                btnMoney.textContent = `✅ Copied ${cleanedMoney}`;
                btnMoney.style.backgroundColor = '#2ecc71'; // Green

                setTimeout(() => {
                    btnMoney.textContent = '💵 Copy Money';
                    btnMoney.style.backgroundColor = '#944ce0';
                }, 2000);
            } else {
                btnMoney.textContent = 'No valid money';
                btnMoney.style.backgroundColor = '#e74c3c';
                setTimeout(() => {
                    btnMoney.textContent = '💵 Copy Money';
                    btnMoney.style.backgroundColor = '#944ce0';
                }, 2000);
                console.log("No valid money");
            }
         }, 50);
    }
    injectConversionDiv();
})();