Greasy Fork is available in English.

单位转换

鼠标选取,即可把外币、英制长度、英制重量、华氏温度和油耗等转换为个人更习惯的单位(人民币、公制和摄氏度等)。已添加:美元、欧元、港币、日元、英镑、新加坡元、澳大利亚元、加拿大元、丹麦克朗、韩国元、澳门元、挪威克朗、新西兰元、菲律宾比索、人民币、卢布、瑞典克朗、瑞士法郎、泰国铢、越南盾。货币汇率为 2024 年 5 月 5 日数据,不会自动更新,如需要最新数据自己手动修改(狗头)。如需要其他国家,请在第 1030 行添加,Google 搜索 100XX 币人民币。

// ==UserScript==
// @name       单位转换
// @author       电报 @yzc020,原作者 ChandlerVer5(项目名:智能选择)
// @secondary development yzc020
// @namespace   https://greasyfork.org/users/183871
// @version    1.02
// @description  鼠标选取,即可把外币、英制长度、英制重量、华氏温度和油耗等转换为个人更习惯的单位(人民币、公制和摄氏度等)。已添加:美元、欧元、港币、日元、英镑、新加坡元、澳大利亚元、加拿大元、丹麦克朗、韩国元、澳门元、挪威克朗、新西兰元、菲律宾比索、人民币、卢布、瑞典克朗、瑞士法郎、泰国铢、越南盾。货币汇率为 2024 年 5 月 5 日数据,不会自动更新,如需要最新数据自己手动修改(狗头)。如需要其他国家,请在第 1030 行添加,Google 搜索 100XX 币人民币。
// @noframes
// @include             *
// @exclude             *www.w3school.com.cn*
// @run-at              document-end
// @grant    GM_addStyle
// @grant    GM_setClipboard
// @grant    GM_registerMenuCommand
// @license MIT
// ==/UserScript==

!function (argument) {
	window.MagicSel = {};
	// ===============

	if (typeof IS_TESTING == "undefined") {
    IS_TESTING = false;
	}

function calc_default_lang () {
    switch (window.navigator.language) {
        case 'zh-CN': case 'zh_TW': case 'zh': case 'ja':
            return 'cn';
    }

    return 'en';
}

// The significant number
g_sig_numbers = 3;
// Systems: imp->imperial system, std->metric (international) system, us->US system
g_dest_sys = 'std';
// Language: en->English, cn->Chinese
g_lang = calc_default_lang ();
// Target currency:
//     dollar/euro/pound/hkd/yen/sfr/sgd/sek/dkk/nok/cad/aud/mop/php/nzd/krw/rouble/rmb
g_target_cur = 'rmb';

// 1->number, 2->mul
g_pure_number = '[0-9,]+[.]?|[0-9,]*[.][0-9]+|[0-9.]+[,][0-9][0-9]'
g_number_exp = '((?:' + g_pure_number + ')(?:\\s+(?:' + g_pure_number + ')\\s*/\\s*(?:' + g_pure_number + '))?)\\s*(十 | 百 | 千 | 万 | 十万 | 百万 | 千万 | 亿 | 十亿 | 百亿 | 千亿 | 万亿 | million|m|trillion|t|billion|b|thousand|k)?';
//match: (1) (2)/(3)
g_frac_num_re = new RegExp ('(' + g_pure_number + ')\\s+(' + g_pure_number + ')\\s*/\\s*(' + g_pure_number + ')')

function ex_digits_from_mul_str (mul) {
	mul = (mul || "").trim ();
	var ex_digits = 0;
	switch (mul) {
	    case ' 十 ':
    		ex_digits = 1;
    		break;
	    case ' 百 ':
    		ex_digits = 2;
    		break;
	    case ' 千 ': case 'thousand': case 'k':
    		ex_digits = 3;
    		break;
	    case ' 万 ':
    		ex_digits = 4;
    		break;
    	case ' 十万 ':
    		ex_digits = 5;
    		break;
    	case ' 百万 ': case 'million': case 'm':
    		ex_digits = 6;
    		break;
    	case ' 千万 ':
    		ex_digits = 7;
    		break;
    	case ' 亿 ':
    		ex_digits = 8;
    		break;
    	case ' 十亿 ': case 'billion': case 'b':
    		ex_digits = 9;
    		break;
    	case ' 百亿 ':
    		ex_digits = 10;
    		break;
    	case ' 千亿 ':
    		ex_digits = 11;
    		break;
    	case ' 万亿 ': case 'trillion': case 't':
    		ex_digits = 12;
    		break;
	}

	return ex_digits;
}

function remove_trailing_zeros (s) {
    var dot = s.indexOf ('.');
    if (dot < 0) {
        return s;
    }

    p = s.length - 1;
    while (s [p] == '0') {
        p --;
    }

    if (p == dot) {
        p --;
    }

    return s.substr (0, p + 1);
}

function raw_render_number (val, sep, sig_numbers) {
    var s = '';
    if (val < 1) {
        var lg = Math.log (val)/Math.LN10;
        var n = Math.round (-lg + sig_numbers);
        s = val.toFixed (n);
    } else {
        var lg = Math.log (val)/Math.LN10;
        var n = Math.round (sig_numbers - lg);
        if (n > 0) {
            s = val.toFixed (n);
            while (s && s [s.length - 1] == '0') {
                s = s.substr (0, s.length - 1);
            }
            if (s && s [s.length - 1] == '.') {
                s = s.substr (0, s.length - 1);
            }
        } else {
            s = val.toFixed (0);
        }
    }

    s = remove_trailing_zeros (s);

    if (sep > 0) {
        var dot = s.indexOf ('.');
        if (dot < 0) {
            dot = s.length;
        }

        dot -= sep;
        while (dot > 0) {
            s = s.substr (0, dot) + "," + s.substr (dot);
            dot -= sep;
        }
    }

    return s;
}

g_lang_info = {
    cn: {
        render_number: function (val, sig_numbers) {
            var neg = val < 0;
            val = Math.abs (val);
            if (val < 1e-20) {
                return "0";
            }

            var suffix = '';
            if (val >= 1e12) {
                suffix = "万亿";
                val /= 1e12;
            } else if (val >= 1e8) {
                suffix = "亿";
                val /= 1e8;
            } else if (val >= 1e4) {
                suffix = "万";
                val /= 1e4;
            }

            var s = raw_render_number (val, -1, sig_numbers) + suffix;
            if (neg) {
                s = '-' + s;
            }

            return s;
        }
    },
    en: {
        render_number: function (val, sig_numbers) {
            var neg = val < 0;
            val = Math.abs (val);
            if (val < 1e-20) {
                return "0";
            }

            var s = raw_render_number (val, 3, sig_numbers);
            if (neg) {
                s = '-' + s;
            }

            return s;
        }
    }
} //g_lang_info

//the regular expression for extracting fmt string for plural representations
//e.g. '[pound,pounds]' in fmt fields.
var g_plural_reg = /^(.*)\[(.*)\](.*)$/;

function number_render (val, fmt, sig_numbers) {
    var var_s = g_lang_info [g_lang].render_number (val, sig_numbers);
    if (fmt.length == undefined) {
        fmt = fmt [g_lang];
    }
    var m = fmt.match (g_plural_reg);

    if (m) {
        var pts = m [2].split (',');
        if (parseFloat (var_s) > 1 && pts.length > 1) {
            m [2] = pts [1];
        } else {
            m [2] = pts [0];
        }
        fmt = m [1] + m [2] + m [3];
    }

    return fmt.replace ("{}", var_s);
}

//some shared constants
LIQUIDVOLUME_US_GAL_RATE = 0.003785411784;
LIQUIDVOLUME_IMP_GAL_RATE = 0.00454609;
LEN_IMP_MILE_RATE = 1609.344;
SECONDS_PER_HOUR = 3600;

//constants for metric conversion, default base is international standard (std)
//if contains groups, use ?: after (
g_metrics = {
    liquidvolume: {
        us: {
            units: {
                gal: {
                    rate: LIQUIDVOLUME_US_GAL_RATE,
                    suffixes: [' 嗧 ', ' 加仑 ', ' 美制加仑 ', 'gallons?', 'gal [.]?'],
                    fmt: {en: '{} US gal.', cn: '{} 美制加仑 '}
                },
                quart: {
                    rate: 0.000946353,
                    suffixes: [' 夸脱 ', ' 美制夸脱 ', 'quarts?'],
                    fmt: {en: '{} US [quart,quarts]', cn: '{} 美制夸脱 '}
                },
                pint: {
                    rate: 0.000473176,
                    suffixes: [' 品脱 ', ' 美制品脱 ', 'pints?'],
                    fmt: {en: '{} US [pint,pints]', cn: '{} 美制品脱 '}
                },
                cup: {
                	nondst: true,
                    rate: 0.000236588,
                    suffixes: [' 杯 ', ' 美制杯 ', 'cups?'],
                    fmt: {en: '{} US [cup,cups]', cn: '{} 美制杯 '}
                },
                oz: {
                    rate: 0.0000295735295625,
                    suffixes: [' 液体盎司 ', ' 美制液体盎司 ', 'ounces?', 'fl [.]? oz [.]?', '℥',
                        'fl? ?℥'],
                    fmt: {en: '{} US fl oz', cn: '{} 美制液体盎司 '}
                },
                tbsp: {
                	nondst: true,
                    rate: 0.0000147868,
                    suffixes: [' 汤匙 ', ' 美制汤匙 ', 'tablespoons?', 'tbsp [.]?'],
                    fmt: {en: '{} US tbsp.', cn: '{} 美制汤匙 '}
                },
                tsp: {
                    rate: 0.00000492892,
                    suffixes: [' 茶匙 ', ' 美制茶匙 ', 'teaspoons?', 'tsp [.]?'],
                    fmt: {en: '{} US tsp.', cn: '{} 美制茶匙 '}
                },
            }
        },
        imp: {
            units: {
                gal: {
                    rate: LIQUIDVOLUME_IMP_GAL_RATE,
                    suffixes: [' 嗧 ', ' 加仑 ', ' 英制加仑 ', 'gallons?', 'gal [.]?'],
                    fmt: {en: '{} gal.', cn: '{} 英制加仑 '}
                },
                quart: {
                    rate: 0.00113652,
                    suffixes: [' 夸脱 ', ' 英制夸脱 ', 'quarts?'],
                    fmt: {en: '{} [quart,quarts]', cn: '{} 英制夸脱 '}
                },
                pint: {
                    rate: 0.000568261,
                    suffixes: [' 品脱 ', ' 英制品脱 ', 'pints?'],
                    fmt: {en: '{} [pint,pints]', cn: '{} 英制品脱 '}
                },
                oz: {
                    rate: 0.0000284130625,
                    suffixes: [' 液体盎司 ', ' 英制液体盎司 ', 'ounces?', 'fl [.]? oz [.]?', '℥',
                        'fl? ?℥'],
                    fmt: {en: '{} fl oz', cn: '{} 英制液体盎司 '}
                },
                tbsp: {
                	nondst: true,
                    rate: 0.0000177582,
                    suffixes: [' 汤匙 ', ' 英制汤匙 ', 'tablespoons?', 'tbsp [.]?'],
                    fmt: {en: '{} tbsp.', cn: '{} 英制汤匙 '}
                },
                tsp: {
                    rate: 0.00000591939,
                    suffixes: [' 茶匙 ', ' 英制茶匙 ', 'teaspoons?', 'tsp [.]?'],
                    fmt: {en: '{} tsp.', cn: '{} 英制茶匙 '}
                }
            }
        },
        std: {
            units: {
                l: {
                    rate: 1e-3,
                    suffixes: [' 升 ', 'l [.]?', 'lit [re][re] s?', 'dm³'],
                    fmt: {en: '{} L', cn: '{} 升 '}
                },
                ml: {
                    rate: 1e-6,
                    suffixes: [' 毫升 ', 'ml [.]?', 'millilit [re][re] s?', 'cm³', '㎤'],
                    fmt: {en: '{} mL', cn: '{} 毫升 '}
                }
            }
        }
    }, //liquidvolume
    volume: {
        imp: {
            units: {
                cubicmile: {
                    rate: LEN_IMP_MILE_RATE*LEN_IMP_MILE_RATE*LEN_IMP_MILE_RATE,
                    suffixes: [' 立方 [哩迈]', ' 立方英里 ', 'cuibic miles?', 'mi [.]?³'],
                    fmt: {en: '{} mi³', cn: '{} 立方英里 '}
                },
                cubicfoot: {
                    rate: 0.3048*0.3048*0.3048,
                    suffixes: [' 立方呎 ', ' 立方英尺 ', 'cubic f [eo][eo] t', 'ft [.]?³'],
                    fmt: {en: '{} ft³', cn: '{} 立方英尺 '}
                },
                cubicinch: {
                    rate: 0.0254*0.0254*0.0254,
                    suffixes: [' 立方吋 ', ' 立方英寸 ', 'cubic inche?s?', 'in [.]?³'],
                    fmt: {en: '{} in³', cn: '{} 立方英寸 '}
                },
                cubicyard: {
                	nondst: true,
                    rate: 0.9144*0.9144*0.9144,
                    suffixes: [' 立方码 ', 'cubic yards?', 'yd [.]?³'],
                    fmt: {en: '{} yd³', cn: '{} 立方码 '}
                },
            }
        },
        std: {
            units: {
                cbkm: {
                    rate: 1e9,
                    suffixes: [' 立方千米 ', ' 立方公里 ', 'cubic kilomet [er][er] s?', 'km [.]?³', '[㎞㏎]³'],
                    fmt: {en: '{} km³', cn: '{} 立方千米 '}
                },
                cbm: {
                    rate: 1,
                    suffixes: [' 立?方米?', ' 方 ', ' 立方公尺 ', 'cubic met [er][er] s?', 'm [.]?³'],
                    fmt: {en: '{} m³', cn: '{} 立方米 '}
                },
                cbdm: {
                	nondst: true,
                    rate: 1e-3,
                    suffixes: [' 立方分米 ', 'cubic decimet [er][er] s?', 'dm [.]?³'],
                    fmt: {en: '{} dm³', cn: '{} 立方分米 '}
                },
                cbcm: {
                    rate: 1e-6,
                    suffixes: [' 立方厘米 ', ' 立方公分 ', 'cubic centimet [er][er] s?', 'cm [.]?³', '㎝³'],
                    fmt: {en: '{} cm³', cn: '{} 立方厘米 '}
                },
                cbmm: {
                    rate: 1e-9,
                    suffixes: [' 立方毫米 ', ' 立方公厘 ', 'cubic millimet [er][er] s?', 'mm [.]?³', '㎜³'],
                    fmt: {en: '{} mm³', cn: '{} 立方毫米 '}
                },
                cbum: {
                    rate: 1e-18,
                    suffixes: [' 立方微米 ', 'cubic micromet [er][er] s?', '[μu] m [.]?³'],
                    fmt: {en: '{} μm³', cn: '{} 立方微米 '}
                },
            }
        }
    }, //volume
    mass: {
        imp: {
            units: {
                oz: {
                    rate: 0.028349523125,
                    suffixes: [' 盎司 ', 'ounces?', 'oz [.]?', '℥'],
                    fmt: {en: '{} oz', cn: '{} 盎司 '}
                },
                pound: {
                    rate: 0.45359237,
                    suffixes: [' 英?磅 ', 'pounds?', 'lbs?'],
                    fmt: {en: '{} [lb,lbs]', cn: '{} 英磅 '}
                },
                stone: {
                	nondst: true,
                    rate: 6.35029,
                    suffixes: [' 英石 ', 'stones?', 'st [.]?'],
                    fmt: {en: '{} st', cn: '{} 英石 '}
                }
            }
        },
        chn: {
        	units: {
				jin: {
                	nondst: true,
                    rate: 0.5,
                    suffixes: [' 斤 '],
                    fmt: {en: '{} jin', cn: '{} 斤 '}
                },
                liang: {
                	nondst: true,
                    rate: 0.05,
                    suffixes: [' 两 '],
                    fmt: {en: '{} liang', cn: '{} 两 '}
                },
                qian: {
                	nondst: true,
                    rate: 0.005,
                    suffixes: [' 钱 '],
                    fmt: {en: '{} qian', cn: '{} 钱 '}
                }
        	}
        },
        std: {
            units: {
                ton: {
                    rate: 1000,
                    suffixes: [' 吨 ', 'tons?'],
                    fmt: {en: '{} [ton,tons]', cn: '{} 吨 '}
                },
                kg: {
                    rate: 1,
                    suffixes: [' 千克 ', ' 公斤 ', 'kg [.]?', 'kilograms?', '㎏'],
                    fmt: {en: '{} kg', cn: '{} 公斤 '}
                },
                g: {
                    rate: 1e-3,
                    suffixes: [' 克 ', 'g [.]?', 'grams?'],
                    fmt: {en: '{} g', cn: '{} 克 '}
                },
                mg: {
                    rate: 1e-6,
                    suffixes: [' 毫克 ', 'mg [.]?', 'milligrams?', '㎎'],
                    fmt: {en: '{} mg', cn: '{} 毫克 '}
                },
                mcg: {
                    rate: 1e-9,
                    suffixes: [' 微克 ', 'mcg [.]?', '[uµ] g [.]?', 'micrograms?'],
                    fmt: {en: '{} µg', cn: '{} 微克 '}
                }
            }
        }
    }, //mass
    area: {
        imp: {
            units: {
                sqmi: {
                    rate: LEN_IMP_MILE_RATE*LEN_IMP_MILE_RATE,
                    suffixes: ['square miles?', 'sq ?mi [.]?', ' 平方英里 ', 'mi²',
                        ' 平方 [哩迈]'],
                    fmt: {en: '{} mi²', cn: '{} 平方英里 '}
                },
                sqft: {
					rate: 0.3048*0.3048,
					suffixes: ['square f [eo][eo] t', 'sq [.]? ?ft [.]?', ' 平方英尺 ', ' 平方呎 ',
					    'ft²'],
					fmt: {en: '{} ft²', cn: '{} 平方英尺 '}
                },
                sqinch: {
                    rate: 0.0254*0.0254,
                    suffixes: [' 平方吋 ', ' 平方英寸 ', 'square inche?s?', 'in [.]?²'],
                    fmt: {en: '{} in²', cn: '{} 平方英寸 '}
                },
                sqyard: {
                	nondst: true,
                    rate: 0.9144*0.9144,
                    suffixes: [' 平方码 ', 'square yards?', 'yd [.]?²'],
                    fmt: {en: '{} yd²', cn: '{} 平方码 '}
                },
                acre: {
                	nondst: true,
					rate: 4046.8564224,
					suffixes: ['acres?', 'ac [.]?', ' 英亩 '],
					fmt: {en: '{} [acre,acres]', cn: '{} 英亩 '}
                },
            }
        },
        cn: {
            units: {
                cnacre: {
                    nondst: true,
                    rate: 666.6667,
                    suffixes: [' 亩 '],
                    fmt: {en: '{} mu', cn: '{} 亩 '}
                },
            }
        },
        std: {
            units: {
                sqkm: {
                    rate: 1000*1000,
                    suffixes: ['square kilomet [er][er] s?', 'km', 'sq ?km [.]?', ' 平方千米 ',
                        ' 平方公里 ', '㎢'],
                    fmt: {en: '{} km²', cn: '{} 平方公里 '}
                },
                ha: {
                    nondst: true,
                    rate: 1e4,
                    suffixes: ['hectare', 'ha', ' 公顷 '],
                    fmt: {en: '{} ha', cn: '{} 公顷 '}
                },
                sqm: {
                    rate: 1,
                    suffixes: ['square met [er][er] s?', 'sqm [.]?', 'm²', ' 平方米 ', '[方平]', '㎡'],
                    fmt: {en: '{} m²', cn: '{} 平方米 '}
                },
                sqdm: {
                	nondst: true,
                    rate: 0.1*0.1,
                    suffixes: [' 平方分米 ', 'square decimet [er][er] s?', 'dm²'],
                    fmt: {en: '{} dm²', cn: '{} 平方分米 '}
                },
                sqcm: {
                    rate: 1e-4,
                    suffixes: [' 平方厘米 ', 'square centimet [er][er] s?', 'cm²', '㎠'],
                    fmt: {en: '{} cm²', cn: '{} 平方厘米 '}
                },
                sqmm: {
                    rate: 1e-6,
                    suffixes: [' 平方毫米 ', 'square millimet [er][er] s?', 'mm²', '㎟'],
                    fmt: {en: '{} mm²', cn: '{} 平方毫米 '}
                }
            }
        }
    }, //area
    len: {
        imp: {
            units: {
                mile: {
                    rate: LEN_IMP_MILE_RATE,
                    suffixes: ['[哩迈]', ' 英里 ', 'miles?', 'mi [.]?'],
                    fmt: {en: '{} mi', cn: '{} 英里 '}
                },
                foot: {
                    rate: 0.3048,
                    suffixes: [' 呎 ', ' 英?尺 ', 'f [eo][eo] t', 'ft [.]?', "'"],
                    smaller: 'inch',
                    fmt: {en: '{} ft', cn: '{} 英尺 '}
                },
                inch: {
                    rate: 0.0254,
                    suffixes: [' 吋 ', ' 英?寸 ', 'inche?s?', 'in [.]?', '"',"''"],
                    fmt: {en: '{} in', cn: '{} 英寸 '}
                },
                yard: {
                	nondst: true,
                    rate: 0.9144,
                    suffixes: [' 码 ', 'yards?', 'yd [.]?'],
                    fmt: {en: '{} yd', cn: '{} 码 '}
                }
            }
        },
        chn: {
            units: {
                li: {
                    rate: 500,
                    suffixes: [' 里 '],
                    fmt: {en: '{} li', cn: '{} 里 '}
                },
                zhang: {
                    rate: 3.3333333333,
                    suffixes: [' 丈 '],
                    fmt: {en: '{} zhang', cn: '{} 丈 '}
                },
                chi: {
                    rate: 0.3333333333,
                    suffixes: [' 市?尺 '],
                    smaller: 'cun',
                    fmt: {en: '{} chi', cn: '{} 尺 '}
                },
                cun: {
                    rate: 0.03333333333,
                    suffixes: [' 市?寸 '],
                    fmt: {en: '{} cun', cn: '{} 寸 '}
                }
            }
        },
        std: {
            units: {
                km: {
                    rate: 1000,
                    suffixes: [' 千米 ', ' 公里 ', 'kilomet [er][er] s?', 'km [.]?', '[㎞㏎]'],
                    fmt: {en: '{} km', cn: '{} 公里 '}
                },
                m: {
                    rate: 1,
                    suffixes: [' 米 ', ' 公尺 ', 'met [er][er] s?', 'm [.]?'],
                    smaller: 'dm',
                    fmt: {en: '{} m', cn: '{} 米 '}
                },
                dm: {
                	nondst: true,
                    rate: 0.1,
                    suffixes: [' 分米 ', 'decimet [er][er] s?', 'dm [.]?'],
                    fmt: {en: '{} dm', cn: '{} 分米 '}
                },
                cm: {
                    rate: 1e-2,
                    suffixes: [' 厘米 ', ' 公分 ', 'centimet [er][er] s?', 'cm [.]?', '㎝'],
                    fmt: {en: '{} cm', cn: '{} 厘米 '}
                },
                mm: {
                    rate: 1e-3,
                    suffixes: [' 毫米 ', ' 公厘 ', 'millimet [er][er] s?', 'mm [.]?', '㎜'],
                    fmt: {en: '{} mm', cn: '{} 毫米 '}
                },
                um: {
                    rate: 1e-6,
                    suffixes: [' 微米 ', 'micromet [er][er] s?', '[μu] m [.]?'],
                    fmt: {en: '{} μm', cn: '{} 微米 '}
                }
            }
        }
    }, //len
    fuel: { //base: meter^3 per meter
    	us: {
    		units: {
				mpg: {
					rev_rate: LIQUIDVOLUME_US_GAL_RATE/LEN_IMP_MILE_RATE,
					suffixes: ['(?:est [.]? )?mpg (?:[(] us [)])?',
							   '(?:est [.]? )?miles? per (us )?gallon',
							   '(?:[哩迈]| 英里)(?: 每 |/)(?: 美制)? 加仑 '],
					fmt: {en: '{} MPG (US)', cn: '{} 英里 / 美制加仑 '}
				}
    		}
    	},
    	imp: {
    		units: {
				mpg: {
					rev_rate: LIQUIDVOLUME_IMP_GAL_RATE/LEN_IMP_MILE_RATE,
					suffixes: ['(?:est [.]? )?mpg', '(?:est [.]? )?miles? per (?:imp )?gallon',
					           '(?:[哩迈]| 英里)(?: 每 |/)(英制)? 加仑 '],
					fmt: {en: '{} MPG (imp)', cn: '{} 英里 / 英制加仑 '}
				}
    		}
    	},
    	std: {
    		units: {
				lp100km: {
					rate: 1e-8,
					suffixes: ['(?:est [.]? )?L (?:p|/) 100km', ' 个 [油字]', ' 升每百 (公里 | 千米)'],
					fmt: {en: '{} L/100km', cn: '{} 升 / 百公里 '}
				}
    		}
    	},
    	tw: {
    		units: {
				kmpl: {
					rev_rate: 1e-6,
					suffixes: ['(?:est [.]? )?kmpl', '(?:est [.]? )?km/L', '(?: 公里 | 千米) 每升 '],
					fmt: {en: '{} km/L', cn: '{} 千米 / 升 '}
				}
    		}
    	},
    }, //fuel
    speed: { //base: meter/second
    	imp: {
    		units: {
    			mph: {
					rate: LEN_IMP_MILE_RATE/SECONDS_PER_HOUR,
					suffixes: ['mph', '(?:[哩迈]| 英里) 每小时 '],
					fmt: {en: '{} MPH', cn: '{} 英里 / 小时 '}
    			}
    		}
    	},
    	std: {
    		units: {
    			kmph: {
    				rate: 1e3/SECONDS_PER_HOUR,
    				suffixes: ['kmph', '(?: 公里|千米) 每小时 '],
					fmt: {en: '{} km/H', cn: '{} 千米 / 小时 '}
    			}
    		}
    	}
    }
} //g_metrics

function is_letter (c) {
    return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}

//is_euro_sep checks whether s is a European style number: 1.234,56 (== 1234.56)
function is_euro_sep (s) {
    if (s.length < 4 || s [s.length-3] != ',') {
        //too short or not comma, false
        return false;
    }

    s = s.substr (0, s.length - 3)
    if (s.indexOf (',') >= 0) {
        // More than one comma, false
        return false;
    }

    return true;
}

//str2num converts a number text into a float number.
// Remove seperators (standard or Europeon style) if any.
function str2num (s) {
    s = s.trim ()

    var m = s.match (g_frac_num_re);
    if (m) {
        return parseFloat (m [1].replace (/,/gm, '')) + parseFloat (m [2].replace (/,/gm, ''))/parseFloat (m [3].replace (/,/gm, ''))
    }

    if (is_euro_sep (s)) {
        return parseFloat (s.replace (/[.]/gm, '').replace (/,/gm, '.'))
    } else {
        return parseFloat (s.replace (/,/gm, ''))
    }
}

function entry_of_orgmul (org, mul) {
	var val = str2num (org);
	var ex_digits = ex_digits_from_mul_str (mul);
	while (ex_digits > 0) {
		val *= 10;  ex_digits --;
	}
	return {
		org: org,
		mul: mul,
		val: val
	}
}

//the set of ambiguous units. e.g. 千克 could be parsed as 千 克
g_ambiguous_units = {
        ' 千克 ': true,
        ' 千米 ': true
};

//parse_suffix_entry parses the text as a number with a suffix regexp
//return null if failed.
//the match matrix of regexp is supposed: 1->org, 2->mul, 3->gap, 4->[tp]
function parse_suffix_entry (text, reg) {
    var mat = text.match (reg);
    if (mat) {
        var mul = safe_to_lower_case (mat [2]);
        var tp = safe_to_lower_case (mat [4]);
        var gap = mat [3];
        if (tp && mul && !gap) {
            if (is_letter (mul [mul.length - 1]) && is_letter (tp [0])) {
            	//tp and mul (both letters) are seperated by nothing (!gap), this is a wrong match
                return null;
            }

            if (g_ambiguous_units [mul + tp]) {
                return null;
            }
        }

        return entry_of_orgmul (mat [1], mul);
    } //if
    return null
}

//parse_prefix_entry parses the text as a number with a prefix regexp
//return null if failed.
//the match matrix of regexp is supposed: 2->org, 3->mul
function parse_prefix_entry (text, reg) {
    var mat = text.match (reg);
    if (mat) {
        return entry_of_orgmul (mat [2], safe_to_lower_case (mat [3]));
    } //if
    return null
}

//reg: 1->org, 2->mul, 3->gap, 4->tp, 5->small-org, 6->small-mul
function parse_suffix_with_smaller (text, reg) {
    var mat = text.match (reg);
    if (mat) {
        var mul = safe_to_lower_case (mat [2]);
        var tp = safe_to_lower_case (mat [4]);
        var gap = mat [3];
        if (tp && mul && !gap) {
            if (is_letter (mul [mul.length - 1]) && is_letter (tp [0])) {
            	//tp and mul (both letters) are seperated by nothing (!gap), this is a wrong match
                return null;
            }

            if (g_ambiguous_units [mul + tp]) {
                return null;
            }
        }

        return {
        	cur: entry_of_orgmul (mat [1], mul),
        	smaller: entry_of_orgmul (mat [5], safe_to_lower_case (mat [6]))
        }
    } //if
    return null
}
//value_score calculates how well a value is to be read.
// The larger score the better. Could be negative.
function value_score (val) {
    val = Math.abs (val);
    if (val < 1e-15) {
        return 0;
    }

    var lg = Math.log (val) / Math.LN10;

    var score = 0;
    if (val < 0.9) {
        score -= 1;
        lg = -lg;
    }

    score -= Math.abs (lg);
    return score;
}

//metric_convert chooses the best final unites and convert the value to it.
function metric_convert (val, dst_si) {
    var cnv = null;
    var best_score = 0;
    for (var dst_u in dst_si.units) {
        var dst_ui = dst_si.units [dst_u];
        if (dst_ui.nondst) {
        	continue;
        }
        var dst_val;
        if (dst_ui.rate) {
        	dst_val = val /dst_ui.rate;
        } else {
        	dst_val = dst_ui.rev_rate/val;
        }
        var score = value_score (dst_val);
        if (!cnv || score > best_score) {
            best_score = score;
            cnv = number_render (dst_val, dst_ui.fmt, g_sig_numbers);
        }
    }
    return cnv;
}

function convert_to_standard (text, si) {
	var found = false
	var res
	for (var u in si.units) {
		var ui = si.units [u]
		var ent = parse_suffix_entry (text, ui.suffix_reg)
		if (ent) {
			if (found) {
				//ambiguous, give up
				return null
			}
			var val;
			if (ui.rate) {
				val = ui.rate * ent.val
			} else {
				val = ui.rev_rate/ent.val
			}
			res = {
				val: val,
				in: number_render (ent.val, ui.fmt, 15)
			}
			found = true
		}
	}
	if (!found) {
		return null
	}
	return res
}

function cat_units (v1, v2) {
	if (is_letter (v1 [v1.length - 1])) {
		v1 += ' ';
	}
	return v1 + v2;
}

function check_dbl_units (res, text, si, dst_si) {
	var mat = text.match (si.dbl_units_reg)
	if (mat) {
		var unit1 = mat [1];
		var unit2 = mat [1 + (mat.length - 1)/2];

		var val = 0;
		var val1 = convert_to_standard (unit1, si);
		if (!val1) {
			return res;
		}
		val += val1.val;
		var val2 = convert_to_standard (unit2, si);
		if (!val2) {
			return res;
		}
		val += val2.val;

		cnv = metric_convert (val, dst_si);
		if (cnv) {
			res = append_line (res, cat_units (val1.in, val2.in), cnv);
		}
	}
	return res
}

//check_metric tries to convert the normalized text into destination system value.
function check_metric (res, text) {
	var cnvs = [];
	for (var m in g_metrics) {
		var mi = g_metrics [m];
		var dst_si = mi [g_dest_sys];
		if (!dst_si) {
			dst_si =  mi.imp;
		}
		for (var s in mi) {
			if (s == g_dest_sys) {
					continue;
			}
			var si = mi [s];
			for (var u in si.units) {
				var ui = si.units [u];
				var ent = parse_suffix_entry (text, ui.suffix_reg);
				if (ent) {
					var val;
					if (ui.rate) {
						val = ui.rate * ent.val;
					} else {
						val = ui.rev_rate/ent.val;
					}
					cnv = metric_convert (val, dst_si);
					if (cnv) {
						res = append_line (res, number_render (ent.val, ui.fmt, 15), cnv);
					}
				}
				if (ui.smaller) {
					ent = parse_suffix_with_smaller (text, ui.suffix_with_smaller_reg)
					if (ent) {
						var val;
						if (ui.rate) {
							val = ui.rate * ent.cur.val;
						} else {
							val = ui.rev_rate/ent.cur.val;
						}
						var inp = number_render (ent.cur.val, ui.fmt, 15);

						ui_smaller = si.units [ui.smaller];
						if (ui_smaller.rate) {
							val += ui_smaller.rate * ent.smaller.val;
						} else {
							val += ui_smaller.rev_rate/ent.smaller.val;
						}
						inp += number_render (ent.smaller.val, ui_smaller.fmt, 15);

						cnv = metric_convert (val, dst_si);
						if (cnv) {
							res = append_line (res, inp, cnv);
						}
					}
				}
			}
			res = check_dbl_units (res, text, si, dst_si)
		}
	}

	return res;
}

//set g_metrics [metric][system].units [unit].suffix_reg
function compile_metrics () {
    for (var m in g_metrics) {
        var mi = g_metrics [m];
        for (var s in mi) {
            var si = mi [s];
            var reg_any = '';
            for (var u in si.units) {
                var ui = si.units [u];
                var reg_str = '\\s*' + g_number_exp + '(\\s*)-?('
                	+ ui.suffixes.join ('|') + ')\\s*';
                ui.suffix_reg = new RegExp ('^' + reg_str + '$', 'i')
                ui.suffix_with_smaller_reg = new RegExp ('^' + reg_str + '(?:\\s*)-?'
                	+ g_number_exp + '$', 'i')
                if (reg_any.length > 0) {
                	reg_any += '|'
                }
                reg_any += '(' + reg_str + ')'
            }
            si.dbl_units_reg = new RegExp ('^(' + reg_any + ')(?:and|[+]| 和 | 加)?('
            	+ reg_any + ')$', 'i')
        }
    }
}
compile_metrics ();

//iso4217
g_defs = {
	aud: {name: {cn: "澳大利亚元", en: "Australian Dollar"}, rate: 477.73/100., fmt: 'A${}', prefixes: ['AUD', 'A$'], suffixes: [' 澳大利亚 [元圆币]', ' 澳 [元圆币]?', 'Australian dollars?', 'aud']},
	cad: {name: {cn: "加拿大元", en: "Canadian Dollar"}, rate: 529.37/100., fmt: 'C${}', prefixes: ['CAD', 'C [$]'], suffixes: [' 加拿大 [元圆币]', ' 加 [元圆币]?', 'Canadian dollars?', 'cad', 'c [$]']},
	dkk: {name: {cn: "丹麦克朗", en: "Denmark Krona"}, rate: 104.44/100., fmt: 'DKK {}', prefixes: ['DKK', 'kr', 'DKR'], suffixes: [' 丹麦克朗 ', ' 丹麦 [元圆币]', 'Denmark krona', 'Denmark kronor', 'dkk']},
	dollar: {name: {cn: "美元", en: 'US Dollar'}, rate: 723.73/100., fmt: '${}', prefixes: ['[$﹩$]', 'US [D$﹩$]'], suffixes: ['[美米][元圆币金刀]', '[刀米]', 'dollars?', '[$﹩$]', 'US [$﹩$D]']},
	euro: {name: {cn: "欧元", en: "Euro"}, rate: 779.64/100., fmt: '€{}', prefixes: ['€', 'EUR'], suffixes: [' 欧 [元圆币]?', 'euros?', '€', 'eur']},
	hkd: {name: {cn: "港币", en: "Hongkong Dollar"}, rate: 92.64/100., fmt: 'HK${}', prefixes: ['HKD', 'HK [$]'], suffixes: [' 香?港 [元圆币刀]', 'HK [D$]', 'Hongkong dollars?']},
	krw: {name: {cn: "韩国元", en: "South Korean Won"}, rate: 0.53/100., fmt: 'KRW {}', prefixes: ['원', 'KRW'], suffixes: [' 韩国?[元圆币]', ' 北韩 [元圆币圜]', '원', 'wons?', 'krw']},
	mop: {name: {cn: "澳门元", en: "Macao Pataca"}, rate: 90.22/100., fmt: 'MOP${}', prefixes: ['MOP', 'MOP$'], suffixes: [' 澳门 [元圆币]', 'patacas?', 'Maca [ou] patacas?', 'mop']},
	nok: {name: {cn: "挪威克朗", en: "Norway Krona"}, rate: 66.55/100., fmt: 'NOK {}', prefixes: ['NOK', 'kr'], suffixes: [' 挪威克朗 ', ' 挪威 [元圆币]', 'Norway krona', 'Norway kronor', 'nok']},
	nzd: {name: {cn: "新西兰元", en: "New Zealand Dollar"}, rate: 435.00/100., fmt: 'NZ${}', prefixes: ['NZ [D$]'], suffixes: ['[纽新] 西兰 [元圆币]', '[纽新][元圆币]', 'kiwi', 'New Zealand dollars?', 'nz [d$]']},
	php: {name: {cn: "菲律宾比索", en: "Philippine Peso"}, rate: 12.68/100., fmt: '₱{}', prefixes: ['PHP', '₱'], suffixes: [' 菲律宾 [比披] 索 ', ' 菲律宾 [元圆币]', ' 菲国?[比披] 索 ', '[比披] 索 ', 'Philippine p [ie] sos?', 'p [ie] sos?', 'php', '₱']},
	pound: {name: {cn: "英镑", en: "British Pound Sterling"}, rate: 908.14/100., fmt: '£{}', prefixes: ['[££]', 'GBP'], suffixes: [' 英?镑 ', 'pounds?', 'GBP', '[££]']},
	rmb: {name: {cn: "人民币", en: "Chinese Yuan"}, rate: 1, fmt: 'RMB {}', prefixes: ['RMB', '[¥¥]'], suffixes: [' 人民币 [元圆]?', '[元圆 ¥¥]', 'rmb', 'cny', 'chinese yuan']},
	rouble: {name: {cn: "卢布", en: "Russian Ruble"}, rate: 7.28/100., fmt: 'RUB {}', prefixes: ['RUB', 'руб'], suffixes: [' 卢布 ', ' 俄罗斯 [元圆币]', 'roubles?', 'рубль', 'rubles?', 'rub']},
	sek: {name: {cn: "瑞典克朗", en: "Swedish Krona"}, rate: 67.09/100., fmt: 'SEK {}', prefixes: ['SEK', 'kr'], suffixes: [' 瑞典克朗 ', ' 瑞朗 ', ' 瑞典 [元圆币]', 'Swedish krona', 'Swedish kronor', 'sek']},
	sfr: {name: {cn: "瑞士法郎", en: "Swiss Franc"}, rate: 799.70/100., fmt: 'CHF {}', prefixes: ['CHF', 'SFR'], suffixes: [' 瑞士法郎 ', ' 瑞士 [元圆币]', 'Swiss francs?', 'sfr']},
	sgd: {name: {cn: "新加坡元", en: "Singapore Dollar"}, rate: 536.49/100., fmt: 'S${}', prefixes: ['S [$]', 'SGD'], suffixes: [' 新加坡 [元圆币]', '[新坡][元圆币]', 'Singapore dollars?', 'SGD', 's [$]']},
	thb: {name: {cn: "泰国铢", en: "Thai Baht"}, rate: 19.67/100., fmt: '฿{}', prefixes: ['THB', '฿', 'บาท'], suffixes: [' 泰国?[铢元圆币]', 'Thai bahts?', 'thb', '฿']},
	yen: {name: {cn: "日元", en: "Japanese Yen"}, rate: 4.73/100., fmt: '{} 円 ', prefixes: ['JPY', '[円 ¥¥]'], suffixes: [' 日本?[元圆币]', '[円 ¥¥]', 'yens?', 'jpy']},
	vnd: {name: {cn: "越南盾", en: "Vietnamese dollar"}, rate: 0.028/100., fmt: '₫{}', prefixes: ['VND', 'vn[dđ₫]', 'đ', '₫'], suffixes: [' 越南 [盾元圆币]', 'Vietnamese Dong?', 'vnd', 'vnđ', 'vn₫', 'đ', '₫']},


}; //g_defs

function save_options () {
	localStorage ['language'] = g_lang;
	localStorage ['system'] = g_dest_sys;
	localStorage ['sig-number'] = g_sig_numbers;
	localStorage ['target-cur'] = g_target_cur;
}

function load () {
    var str = localStorage ['language'];
    switch (str) {
        case 'cn': case 'en':
            g_lang = str;
    }
    str = localStorage ['system'];
    switch (str) {
        case'std': case 'imp': case 'us':
            g_dest_sys = str;
    }
    str = localStorage ['sig-number'];
    var n = parseInt (str);
    if (n) {
		g_sig_numbers = parseInt (str);
    }
    str = localStorage ['target-cur'];
    if (str && g_defs [str]) {
    	g_target_cur = localStorage ['target-cur'];
    }

    g_rates = {};
    str = localStorage ['rates'];
    var rates = {};
    if (str) {
    	rates = JSON.parse (str);
    }

    g_regs = {};

    for (var id in g_defs) {
    	g_rates [id] = rates [id] || g_defs [id].rate;

    	g_regs [id] = {
    		pre: new RegExp ('^\\s*(' + g_defs [id].prefixes.join ('|') + ')\\s*'
    			+ g_number_exp + '\\s*$', 'i'),
    		suf: new RegExp ('^\\s*' + g_number_exp + '(\\s*)('
    			+ g_defs [id].suffixes.join ('|') + ')\\s*$', 'i')
    	};
    }
}

load ();

function save () {
	localStorage ['rates'] = JSON.stringify (g_rates);
}

function update_rates () {
  console.log ('Updating rates ...');
  try {
    var xhr = new XMLHttpRequest ();
    xhr.open ("GET", "https://www.boc.cn/sourcedb/whpj/", true);
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4) {
        console.log ('Rates page fetched.');
        var html = xhr.responseText;

        var col_name = 0;
        var col_rate = 6;

        //try find header
        trths = html.match (/<tr (\s+[^<]*)?>(\s*<th (\s+[^<]*)?>[^<]*<\/th>\s*)+<\/tr>/img);
        if (trths) {
          for (var i = 0; i < trths.length; i ++) {
            var tr = trths [i];
            var ths = tr.match (/<th (\s+[^<]*)?>[^<]*<\/th>/img);
            if (ths) {
              for (var j = 0; j < ths.length; j ++) {
                th = ths [j];
                if (th.match (' 中行折算价 ')) {
                  col_rate = j;
                  console.log ('col_rate: ' + col_rate);
                } else if (th.match (' 货币名称 ')) {
                  col_name = j;
                  console.log ('col_name: ' + col_name);
                }
              }
            }
          }
        }
        //search for rates
        trtds = html.match (/<tr (\s+[^<]*)?>(\s*<td (\s+[^<]*)?>[^<]*<\/td>\s*)+<\/tr>/img);
        if (trtds) {
          for (var i = 0; i < trtds.length; i ++) {
            var tr = trtds [i];
            var tds = tr.match (/<td (\s+[^<]*)?>[^<]*<\/td>/img);
            if (tds && tds.length >= col_name && tds.length >= col_rate) {
              var name = tds [col_name].match (/<td (\s+[^<]*)?>\s*(\S*)\s*<\/td>/i)[2];
              var rate = tds [col_rate].match (/<td (\s+[^<]*)?>\s*(\S*)\s*<\/td>/i)[2];

              for (id in g_defs) {
              	if (g_defs [id].name.cn == name) {
              		g_rates [id] = parseFloat (rate)/100;
              		console.log (name + ': ' + g_rates [id]);
              		save ();
              		break;
              	}
              }
            }
          }
        }
      }
    }
    xhr.send ();
  } catch (e) {
  }
}

if (!IS_TESTING) {
    update_rates ();
}

function safe_to_lower_case (str) {
	if (str) {
		str = str.toLocaleLowerCase ();
	} //if

	return str;
}

function append_line (res, l, r) {
	if (res) {
		res += '<br/>';
	}
	return res + l + ' = <strong>' + r + '</strong>';
}

g_cnv_table = {};

function init_cnv_table () {
	var t = ' 幣國攝萬億歐圓鎊華裏碼體侖麥亞門賓銖紐韓盧蘭羅‑';
	var s = ' 币国摄万亿欧圆镑华里码体仑麦亚门宾铢纽韩卢兰罗 -';

	for (i in t) {
		g_cnv_table [t [i]] = s [i];
	} //for i
}

init_cnv_table ();


function norm_text (text) {
    text1 = '';
	for (i in text) {
		text1 += g_cnv_table [text [i]] || text [i];
	}
	text = text1;
	return text;
}

//check_money tries to convert the normalized text as foreign money (again g_target_cur)
//and convert to g_target_cur
function check_money (res, text) {
	var dst_fmt = g_defs [g_target_cur].fmt;
	for (var id in g_regs) {
		if (id == g_target_cur) {
			continue;
		}
		var succ = false;
		var org, src, mul, ex_digits;
		var v = parse_prefix_entry (text, g_regs [id].pre);
		if (v) {
			succ = true;
			src = v.val;
		} else {
			v = parse_suffix_entry (text, g_regs [id].suf);
			if (v) {
				succ = true;
				src = v.val;
			}
		}
		if (succ) {
			var dst = src * g_rates [id] /g_rates [g_target_cur];

			res = append_line (res, number_render (src, g_defs [id].fmt, 15),
				number_render (dst, dst_fmt, g_sig_numbers));
		}
	}
	return res;
}

g_f_suffixes = [' 华氏度?', '° ?F?', '℉', ' 度 ', 'degrees?', 'degrees? fahrenheit', 'F'];
g_c_suffixes = [' 摄氏度?', '° ?C?', '℃', ' 度 ', 'degrees?', 'degrees? celsius', 'C'];
g_temp_f = new RegExp ('^\\s*(华氏)?(零下 |-|−|minus )?' + g_number_exp + '\\s*('
	+ g_f_suffixes.join ('|') + ')?\\s*$', 'i');
g_temp_c = new RegExp ('^\\s*(摄氏)?(零下 |-|−|minus )?' + g_number_exp + '\\s*('
	+ g_c_suffixes.join ('|') + ')?\\s*$', 'i');

//reg: 1 -> tp_pre, 2 -> sign, 3 -> num, 4-> mul, 5 -> tp_suf
function parse_temp_reg (text, reg) {
    var mat = text.match (reg);
    if (mat) {
    	var tp_pre = mat [1];
    	var tp_suf = mat [5];
    	if (tp_pre || tp_suf) {
			var ent = entry_of_orgmul (mat [3], safe_to_lower_case (mat [4]));
			if (mat [2]) {
				//minus value
				ent.val = -ent.val;
			}
			return ent;
    	}
    }
    return null
}

//text tries to convert the normalized text between Fahrenheit and Celsius
function check_temperature (res, text) {
	var ent_f = parse_temp_reg (text, g_temp_f);
	if (ent_f) {
		var src = ent_f.val;
		dst = (src - 32) * 5. / 9;
		res = append_line (res, number_render (src, "{}°F", 15),
			number_render (dst, "{}°C", g_sig_numbers));
	}
	var ent_c = parse_temp_reg (text, g_temp_c);
	if (ent_c) {
		var src = ent_c.val;
		dst = src*9./5. + 32;
		res = append_line (res, number_render (src, "{}°C", 15),
			number_render (dst, "{}°F", g_sig_numbers));
	}
	return res;
}

var g_timezone_matcher = new RegExp ('\\b (ACDT|ACST|ACT|ADT|AEDT|AEST|AFT|AKDT|AKST|AMST|AMT|ART|AST|AWDT|AWST|AZOST|AZT|BDT|BIOT|BIT|BOT|BRST|BRT|BST|BTT|CAT|CCT|CDT|CDT|CEDT|CEST|CET|CHADT|CHAST|CHOT|ChST|CHUT|CIST|CIT|CKT|CLST|CLT|COST|COT|CST|CT|CVT|CWST|CXT|DAVT|DDUT|DFT|EASST|EAST|EAT|ECT|EDT|EEDT|EEST|EET|EGST|EGT|EIT|EST|FET|FJT|FKST|FKT|FNT|GALT|GAMT|GET|GFT|GILT|GIT|GMT|GST|GYT|HADT|HAEC|HAST|HKT|HMT|HOVT|HST|IBST|ICT|IDT|IOT|IRDT|IRKT|IRST|IST|JST|KGT|KOST|KRAT|KST|LHST|LINT|MAGT|MART|MAWT|MDT|MET|MEST|MHT|MIST|MIT|MMT|MSK|MST|MUT|MVT|MYT|NCT|NDT|NFT|NPT|NST|NT|NUT|NZDT|NZST|OMST|ORAT|PDT|PET|PETT|PGT|PHOT|PKT|PMDT|PMST|PONT|PST|PYST|PYT|RET|ROTT|SAKT|SAMT|SAST|SBT|SCT|SGT|SLST|SRET|SRT|SST|SYOT|TAHT|THA|TFT|TJT|TKT|TLT|TMT|TOT|TVT|UCT|ULAT|USZ1|UTC|UYST|UYT|UZT|VET|VLAT|VOLT|VOST|VUT|WAKT|WAST|WAT|WEDT|WEST|WET|WIT|WST|YAKT|YEKT|Z)\\b',
    'i');

function check_date (res, text) {
  if (!text.match (g_timezone_matcher)) {
    return res;
  }
  var d = new Date (text);
  if (isNaN (d.getDate ())) {
    return res;
  }
  return append_line (res, text, d.toString ());
}

var g_simple_math_re = new RegExp ('^\\s*' + g_number_exp + '\\s*([+*/-])\\s*' + g_number_exp + '\\s*$');

function check_math (res, text) {
	var mat = text.match (g_simple_math_re);
	//console.log (mat);
	if (!mat) {
		return res;
	}
	var a  = entry_of_orgmul (mat [1], safe_to_lower_case (mat [2]));
	var op = mat [3];
	var b  = entry_of_orgmul (mat [4], safe_to_lower_case (mat [5]));
	var c = 0;
	switch (op) {
		case '+':
			c = a.val + b.val;
			break;
		case '-':
			c = a.val - b.val;
			break;
		case '*':
			c = a.val * b.val;
			break;
		case '/':
			c = a.val/b.val;
			break;
		default:
			return res;
	}
	return append_line (res, a.val + op + b.val, c);
}

//check_exchange tries to convert the selected text to the destination
//money/metric/temperature. text will be normalized.
function check_all (text) {
	text = norm_text (text);
	var res = '';

	res = check_money (res, text);
	res = check_metric (res, text);
	res = check_temperature (res, text);
	res = check_date (res, text);
	res = check_math (res, text)

	return res ? res : null;
}

if (!IS_TESTING) {
		window.MagicSel.sendRequest  = function (request, cb){
			if (request.text) {
				//console.log (check_all (request.text));
				cb ({res: check_all (request.text)});
			}
			if (request.options) {
				opt = request.options;
				if (opt.lang) {
					g_lang = opt.lang;
				}
				if (opt.sig_numbers) {
					g_sig_numbers = parseInt (opt.sig_numbers);
				}
				if (opt.dest_sys) {
					g_dest_sys = opt.dest_sys;
				}

				if (opt.target_cur) {
					g_target_cur = opt.target_cur;
				}

				save_options ();

				//console.log ("Options changed:" + JSON.stringify (opt));
				cb ({});
			}
			if (request.get_langs_info) {
				var res = [];
				for (id in g_defs) {
					res.push ({
						id: id,
						name: g_defs [id].name
					});
				}
				cb (res);
			}
			if (request.get_options) {
				cb ({
					lang: g_lang,
					target_cur: g_target_cur,
					dest_sys: g_dest_sys,
					sig_numbers: g_sig_numbers
				});
			}

		};

	setInterval (update_rates, 3600000);
	}

	//expose


}();

(()=>{
	GM_addStyle (`
.sel-text-win {
    font-size: 14px;
    font-weight: strong;
    position: absolute;
    background: rgba(200,200,200,0.8);
    padding: 5px;
    width: auto;
    border-radius: 5px;
    box-shadow: 0px 1px 4px gray;
    text-shadow: 0px -1px 0px white;
    z-index: 10000;
}
`)
	document.body.addEventListener ('mouseup',
	function (e) {
		//console.log ('mouseup: ' + e.clientX + ',' + e.clientY);
		var seltext = window.getSelection ().toString ();
		//console.log ('Selected: ' + window.getSelection ().toString ());

		var get_win = function () {
			var win = document.getElementById ('sel-ext-win');
			if (!win) {
				//console.log ('Create show win');
				win = document.createElement ('div');
				win.id = 'sel-ext-win';
				win.className = 'sel-text-win';
				document.body.appendChild (win);
			}
			return win;
		}
		var win = get_win ();

		if (!seltext) {
			win.style ['display'] = 'none';
			return;
		}


		// 修改
		MagicSel.sendRequest ({text: seltext},
			function (response) {
				res = response.res;
				var win = get_win ();

				if (res) {
					win.style ['display'] = 'block';
					var bodyTop = parseInt (document.defaultView.getComputedStyle (document.body, '').getPropertyValue ('margin-top'));
					var top = e.pageY - bodyTop - win.clientHeight - 1;
					top = Math.max (0, top);
					win.style ['top'] = top + 'px';

					var bodyLeft = parseInt (document.defaultView.getComputedStyle (document.body, '').getPropertyValue ('margin-left'));
					var left = e.pageX - bodyLeft + 30;
					left = Math.max (0, left);
					win.style ['left'] = left + 'px';

					win.innerHTML = res;
				} else {
					win.style ['display'] = 'none';
				}
			}
		);
	}
);//mouseup function END!

})();

//options
(()=>{
	GM_addStyle (`
#mg_popup_setting {
    display:none;
    position:absolute;
    top: 50%;
    left: 50%;
    z-index: 1000;
    transform: translate (-50%, -50%);
    width: 600px;
    background: #fff;
    border: 1px solid #1ac3e4;
    text-align: left;
    box-shadow: 5px 5px 20px 0px #1e8e84;
}
#mg_popup_setting #mg_close {
	font-style: normal;
    display: inline-block;
    color: #e80909;
    font-size: 1.2em;
    width: 24px;
    height: 24px;
    line-height: 24px;
    text-align: center;
    float: right;
    cursor: pointer;
}
#mg_popup_setting a {
  color: black;
  border-bottom:dotted 1px;
  text-decoration: none;
}

#mg_popup_setting h1 {
    margin: 0px;
    padding: 40px 0px 30px 0px;
    text-align: center;
    font-size: 30px;
}

#mg_popup_setting article {
    text-align: left;
    margin: 10px 10px;
}

#mg_popup_setting article.footer {
    margin-top: 30px;
    font-size: 75%;
    text-align: right;
}

#mg_popup_setting span.group-label {
    display: inline-block;
    width: 200px;
    text-align: right;
    padding: 0px 20px 0px 0px;
}

#mg_popup_setting #div-examples {
    display: inline-block;
    width: 340px;
    vertical-align: top;
    line-height: 150%;
    text-shadow: 0px -1px 0px white;
}

#mg_popup_setting img#logo {
  position: relative;
  float: left;
  margin-left: 10px;
  margin-top: -90px;
}`)
	// Element
	function setOptWin (){
		const optionHTML = `
		<i id="mg_close">X</i>
		<h1 id='h1-page-title'></h1>
	        <article>
	            <span id='span-language' class="group-label">UI Language:</span>
	            <input type="radio" name="lang" id="ir-en-lang"><span>English</span></input>
	            <input type="radio" name="lang" id="ir-cn-lang"><span > 中文 </span></input>
	        </article>
	        <article>
	            <span id='span-cur-to' class="group-label"></span>
	            <select id="sel-cur-to">
	            </select>
	        </article>
	        <article>
	            <span id='span-system' class="group-label"></span>
	            <select id="sel-sys">
	                <option value='std' id='vl-std-sys'></option>
	                <option value='imp' id='vl-imp-sys'></option>
	                <option value='us' id='vl-us-sys'></option>
	            </select>
	        </article>
	        <article>
	            <span id='span-sig-number' class="group-label"></span>
	            <select id="sel-sig-number">
	                <option value='2'>2</option>
	                <option value='3'>3</option>
	                <option value='4'>4</option>
	                <option value='5'>5</option>
	                <option value='6'>6</option>
	            </select>
	        </article>
	        <article>
	            <span id='span-examples' class="group-label"></span>
	            <div id="div-examples"></div>
	        </article>
	        <!--webp -->
	        <img id="logo" src="https://lh3.googleusercontent.com/-i7d7bF4KnnK5lndYQDRufDmt2q7ZZ90jZrfobioavGSOgxt6JOhxIimaSdtojQTu7rPQYfcgw=s0"/>
	        <article class="footer">
				  Last updated 2023-09-12
	            | <a href="https://github.com/yzcjd" target="_blank">Github Page</a>
	            | <span id='span-developed-by'></span> <a href="http://t.me/yzc020" target="_blank">电报@yzc020</a>
	        </article>
	    `;
	    const outer = document.createElement ("section");
	    outer.setAttribute ("id","mg_popup_setting");
	    outer.innerHTML = optionHTML;
		document.body.appendChild (outer);
		document.getElementById ('mg_close').addEventListener ('click',(e)=>{
		   outer.style.display="none";
		});
	}
	setOptWin ();

	function ut (id, text) {
    	document.getElementById (id).innerText = text;
	}

function update_examples () {
    document.getElementById ('div-examples').innerHTML = '';
    var func_append = function (response) {
        var div = document.getElementById ('div-examples');
        if (response.res) {
            div.innerHTML = div.innerHTML + response.res + "<br/>";
        }
    }
    var examples = [];
    switch (g_dest_sys) {
        case'std':
            examples = ["$1", "RMB 1", "2 英里", "2 oz", "1000 sqft", "1°", "30 fl oz", "50 MPG", "1'2\"", "Jan 2, 13:45 UTC"];
            break;

        case 'imp':
            examples = ["$1", "RMB 1", "2 公里", "5 克", "100 sqm", "1°", "1 l", "10 个油", "1m50cm", "Jan 2, 13:45 UTC"];
            break;

        case 'us':
            examples = ["$1", "RMB 1", "2 公里", "5 克", "100 sqm", "1°", "1 l", "10 个油", "1m50cm", "Jan 2, 13:45 UTC"];
            break;
    }

    for (i in examples) {
        MagicSel.sendRequest ({text: examples [i]}, func_append);
    }
}

function update_language () {
    switch (g_lang) {
        case 'cn':
            ut ('h1-page-title', ' 单位转换脚本 ' + GM_info.script.version);

            ut ('span-language', ' 显示语言 ');
            ut ('span-cur-to', ' 目标货币 ');

            ut ('span-system', ' 目标计量系统 ');
            ut ('vl-std-sys', ' 公制 ');
            ut ('vl-imp-sys', ' 英制 ');
            ut ('vl-us-sys', ' 美制 ');

            ut ('span-examples', ' 示例 ');

            ut ('span-sig-number', ' 有效数字 ');

            ut ('span-developed-by', ' 开发者:');
            break;

        case 'en':
            ut ('h1-page-title', 'MagicSel Extension ' + GM_info.script.version);

            ut ('span-language', 'UI Language');
            ut ('span-cur-to', 'Target currency');

            ut ('span-system', 'Target system');
            ut ('vl-std-sys', 'Metric');
            ut ('vl-imp-sys', 'Imperial');
            ut ('vl-us-sys', 'US');

            ut ('span-examples', 'Examples');
            ut ('span-sig-number', 'Significants');

            ut ('span-developed-by', 'Developed by');
            break;
    }

    MagicSel.sendRequest ({get_langs_info:{}}, function (infos) {
        var src = '';
        for (i in infos) {
            var info = infos [i];
            src += '<option value="' + info.id + '">' + info.name [g_lang] + '</option>';
        }
        document.getElementById ('sel-cur-to').innerHTML= src;
        document.getElementById ('sel-cur-to').value = g_target_cur;
    })
}

function load () {
    MagicSel.sendRequest ({get_options:{}}, function (opt) {
        g_lang = opt.lang;
        g_target_cur = opt.target_cur;
        g_dest_sys = opt.dest_sys;
        g_sig_numbers = parseInt (opt.sig_numbers);

        document.getElementById ('ir-' + g_lang + '-lang').checked = true;
        document.getElementById ('sel-sys').value = g_dest_sys;
        document.getElementById ('sel-sig-number').value = g_sig_numbers;

        update_language ();
        update_examples ();
    })

    document.getElementById ('ir-en-lang').addEventListener ('change', function (e) {
        g_lang = 'en';
        update_language ();
        send_options ();
    });

    document.getElementById ('ir-cn-lang').addEventListener ('change', function (e) {
        g_lang = 'cn';
        update_language ();
        send_options ();
    });

    document.getElementById ('sel-sys').addEventListener ('change', function (e) {
        g_dest_sys = document.getElementById ('sel-sys').value;
        send_options ();
    });

    document.getElementById ('sel-cur-to').addEventListener ('change', function (e) {
        g_target_cur = document.getElementById ('sel-cur-to').value;
        send_options ();
    });

    document.getElementById ('sel-sig-number').addEventListener ('change', function (e) {
        g_sig_numbers = document.getElementById ('sel-sig-number').value;
        send_options ();
    });
}



function OpenSet () {
  return document.getElementById ('mg_popup_setting').style.display="block";
};

function send_options () {
    MagicSel.sendRequest ({options: {
               lang: g_lang,
           dest_sys: g_dest_sys,
        sig_numbers: g_sig_numbers,
         target_cur: g_target_cur
    }}, function () {
        update_examples ();
    });
}

GM_registerMenuCommand ("设置", OpenSet, 'm');
load ();

})()