US to Metric

By Michal Wojciechowski Last update May 3, 2009 — Installed 3,382 times.

There are 6 previous versions of this script.

// ==UserScript==
// @name           US to Metric
// @namespace      http://odyniec.net/
// @description    Convert US measurement units to their metric counterparts
// @include        http://*
// @include        https://*
// ==/UserScript==

var _US_to_Metric_regexps = {
    miles_per_hour: [
        /((?:\.[0-9]|[0-9])[0-9., /]*)(\s|-)*m\.?p\.?h\.?(?=\W|$)/i,    /* 12.34 mph */
        /* 12.34 miles per hour */
        /((?:\.[0-9]|[0-9])[0-9., /]*)(\s|-)*miles?\s+per\s+hour(?=\W|$)/i
    ],
    inches: [
        /((?:\.[0-9]|[0-9])[0-9., /x]*)\s*(")/,                         /* 12.34" */
        /((?:\.[0-9]|[0-9])[0-9., /x]*)(\s|-)*in(ch)?(es)?(?=\W|$)/i    /* 12.34 inches */
    ],
    feet: [
        /((?:\.[0-9]|[0-9])[0-9., /x]*)(\s|-)*f(oo|ee)?t(?=\W|$)/i      /* 12.34 ft, 12-feet */
    ],
    yards: [
        /((?:\.[0-9]|[0-9])[0-9., /x]*)(\s|-)*y(ar)?ds?(?=\W|$)/i       /* 12.34 yds, 12.34 yards */
    ],
    miles: [
        /((?:\.[0-9]|[0-9])[0-9., /x]*)(\s|-)*mi(le)?s?(?=\W|$)/i       /* 12.34 miles */
    ],
    ounces: [
        /((?:\.[0-9]|[0-9])[0-9., /]*)(\s|-)*o(z|unces?)(?=\W|$)/i      /* 12 oz, 12 ounces */
    ],
    pounds: [
        /((?:\.[0-9]|[0-9])[0-9., /]*)(\s|-)*lbs?(?=\W|$)/i,            /* 12.34 lbs */
        /((?:\.[0-9]|[0-9])[0-9., /]*)(\s|-)*pounds?(?=\W|$)/i          /* 12.34 pounds */
    ],
    fluid_ounces: [
        /* 12 fl oz, 12 fluid ounces */
        /((?:\.[0-9]|[0-9])[0-9., /]*)(\s|-)*(u\.?s\.?\s)?fl(uid)?(\s|\.\s?)o(z|unces?)(?=\W|$)/i
    ],
    gallons: [
        /* 12.34 gal, 12.34 US gallon */
        /((?:\.[0-9]|[0-9])[0-9., /x]*)(\s|-)*(u\.?s\.?\s)?gal(lon)?(?=\W|$)/i
    ],
    fahrenheit: [
        /([-−]?[ ]*(?:\.[0-9]|[0-9])[0-9., /]*)\s*°\s*F(?=\W|$)/,       /* 34 °F */
        /* 34 degrees Fahrenheit */
        /([-−]?[ ]*(?:\.[0-9]|[0-9])[0-9., /]*)\s*deg(rees)?\s+f(ahrenheit)?(?=\W|$)/i
    ],
    next: [ ]
};

function _US_to_Metric_click(event)
{
    if (event.ctrlKey) {
        var t, nodes, switched = /_US_to_Metric_switched/.test(this.className);

        if (event.shiftKey)
            nodes = document.getElementsByClassName('_US_to_Metric_value');
        else
            nodes = [ this ];
            
        for (var i = 0; i < nodes.length; i++) 
            if (switched) {
                nodes[i].className = nodes[i].className.replace(' _US_to_Metric_switched', '');
                nodes[i].childNodes[0].nodeValue = nodes[i].title.split(/ = /)[0];
            }
            else {
                nodes[i].className = nodes[i].className.replace(' _US_to_Metric_switched', '');
                nodes[i].childNodes[0].nodeValue = nodes[i].title.split(/ = /)[1];
                nodes[i].className += ' _US_to_Metric_switched';
            }
        
        event.preventDefault();
        return false;
    }
}

function _US_to_Metric()
{
    var nodes, textNodes = [ ];
    var text, mode, r, pre, post, parent, span, t, tt, n, i;
    var regexps = _US_to_Metric_regexps;
    var excluded = { option: 1, script: 1, textarea: 1 };

    nodes = document.evaluate('//body//text()', document, null,
        XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
        
    for (i = 0; i < nodes.snapshotLength; i++)
        textNodes.push(nodes.snapshotItem(i));

    i = 0;

    while (i < textNodes.length) {
        if (textNodes[i].parentNode &&
            excluded[textNodes[i].parentNode.tagName.toLowerCase()])
        {
            i++;
            continue;
        }
    
        text = textNodes[i].nodeValue;

        if (!text || !text.match(/[0-9]/)) {
            i++;
            continue;
        }
        
        LOOP:
        for (mode in regexps)
            for (var j = 0; j < regexps[mode].length; j++)
                if (t = regexps[mode][j].exec(text))
                    break LOOP;

        if (mode == 'next') {
            i++;
            continue;
        }

        if (tt = t[1].match(/([0-9]+)\s+([0-9]+)\/([0-9]+)/))
            t[1] = (parseFloat(tt[1]) + tt[2] / tt[3]).toString();
            
        t[1] = t[1].replace(/\s+/g, '');
        t[1] = t[1].replace(',', '');
        t[1] = t[1].replace('−', '-');
        n = t[1].split(/x/);

        for (j = 0; j < n.length; j++)
            if (tt = n[j].match(/([0-9]+)\/([0-9]+)/))
                n[j] = tt[1] / tt[2];
                
        switch (mode) {
        case 'miles_per_hour':
            for (j = 0; j < n.length; j++)
                n[j] = (parseFloat(n[j]) * 1.609344).toFixed(2);
                
            r = n.join(' x ') + ' km/h';                
            break;            
        case 'inches':
            for (j = 0; j < n.length; j++)
                n[j] = (parseFloat(n[j]) * 2.54).toFixed(2);
                
            r = n.join(' x ') + ' cm';
            break;
        case 'feet':
            for (j = 0; j < n.length; j++)
                n[j] = (parseFloat(n[j]) * 0.3048).toFixed(2);
                
            r = n.join(' x ') + ' m';
            break;
        case 'yards':
            for (j = 0; j < n.length; j++)
                n[j] = (parseFloat(n[j]) * 0.9144).toFixed(2);
                
            r = n.join(' x ') + ' m';
            break;
        case 'miles':
            for (j = 0; j < n.length; j++)
                n[j] = (parseFloat(n[j]) * 1.609344).toFixed(2);
                
            r = n.join(' x ') + ' km';
            break;
        case 'ounces':
            for (j = 0; j < n.length; j++)
                n[j] = (parseFloat(n[j]) * 28.349523125).toFixed(2);
                
            r = n.join(' x ') + ' g';
            break;
        case 'pounds':
            for (j = 0; j < n.length; j++)
                n[j] = (parseFloat(n[j]) * 0.45359237).toFixed(2);
                
            r = n.join(' x ') + ' kg';
            break;
        case 'fluid_ounces':
            for (j = 0; j < n.length; j++)
                n[j] = (parseFloat(n[j]) * 29.57353).toFixed(2);
                
            r = n.join(' x ') + ' mL';
            break;
        case 'gallons':
            for (j = 0; j < n.length; j++)
                n[j] = (parseFloat(n[j]) * 3.78541178).toFixed(2);
                
            r = n.join(' x ') + ' L';
            break;
        case 'fahrenheit':
            for (j = 0; j < n.length; j++)
                n[j] = ((parseFloat(n[j]) - 32) * 5 / 9).toFixed(2);
            
            r = n.join(' x ') + ' °C';
            break;
        }
        
        pre = document.createTextNode(text.slice(0, text.indexOf(t[0])));
        post = document.createTextNode(text.slice(text.indexOf(t[0]) + t[0].length));

        span = document.createElement('span');
        span.appendChild(document.createTextNode(t[0]));
        t[0] = t[0].replace(/\s+/g, ' ');
        span.setAttribute('title', t[0] + ' = ' + r);
        span.className = '_US_to_Metric_value';
        span.style.cursor = 'pointer';
        span.addEventListener('click', _US_to_Metric_click, false);
        span.style.color = 'inherit';
        span.style.fontSize = 'inherit';
        span.style.fontWeight = 'inherit';

        parent = textNodes[i].parentNode;
        parent.replaceChild(post, textNodes[i]);
        parent.insertBefore(span, post);
        parent.insertBefore(pre, span);

        textNodes[i] = pre;
        textNodes.push(post);
    }
}

_US_to_Metric();