Parser: support metric base unit case insensitivity

This commit is contained in:
Mottie 2015-06-17 16:38:27 -05:00
parent 9b39a91268
commit 73f5467c1f
3 changed files with 99 additions and 72 deletions

View File

@ -1,2 +1,2 @@
/*! Parser: metric */
!function(a){"use strict";var b={"Y|Yotta|yotta":[1e24,Math.pow(1024,8)],"Z|Zetta|zetta":[1e21,Math.pow(1024,7)],"E|Exa|exa":[1e18,Math.pow(1024,6)],"P|Peta|peta":[1e15,Math.pow(1024,5)],"T|Tera|tera":[1e12,Math.pow(1024,4)],"G|Giga|giga":[1e9,Math.pow(1024,3)],"M|Mega|mega":[1e6,Math.pow(1024,2)],"k|Kilo|kilo":[1e3,1024],"h|hecto":[100,100],"da|deka":[10,10],"d|deci":[.1,.1],"c|centi":[.01,.01],"m|milli":[.001,.001],"µ|micro":[1e-6,1e-6],"n|nano":[1e-9,1e-9],"p|pico":[1e-12,1e-12],"f|femto":[1e-15,1e-15],"a|atto":[1e-18,1e-18],"z|zepto":[1e-21,1e-21],"y|yocto":[1e-24,1e-24]},c="(\\d+)(\\s+)?([Zz]etta|[Ee]xa|[Pp]eta|[Tt]era|[Gg]iga|[Mm]ega|kilo|hecto|deka|deci|centi|milli|micro|nano|pico|femto|atto|zepto|yocto)(",d="(\\d+)(\\s+)?(Z|E|P|T|G|M|k|h|da|d|c|m|µ|n|p|f|a|z|y)(";a.tablesorter.addParser({id:"metric",is:function(){return!1},format:function(e,f,g,h){var i,j,k="m|meter",l=a.tablesorter.formatFloat(e.replace(/[^\w,. \-()]/g,""),f),m=f.config.$headerIndexed[h],n=m.data("metric");if(n||(j=(m.attr("data-metric-name")||k).split("|"),n=[j[1]||j[0].substring(1),j[0]],n[2]=new RegExp(c+n[0]+"|"+n[1]+")"),n[3]=new RegExp(d+n[1]+")"),m.data("metric",n)),j=e.match(n[2])||e.match(n[3]))for(k in b)if(j[3].match(k))return i=/^[b|bit|byte|o|octet]/.test(j[4])?1:0,l*b[k][i];return l},type:"numeric"})}(jQuery);
!function(a){"use strict";var b={"Y|Yotta|yotta":[1e24,Math.pow(1024,8)],"Z|Zetta|zetta":[1e21,Math.pow(1024,7)],"E|Exa|exa":[1e18,Math.pow(1024,6)],"P|Peta|peta":[1e15,Math.pow(1024,5)],"T|Tera|tera":[1e12,Math.pow(1024,4)],"G|Giga|giga":[1e9,Math.pow(1024,3)],"M|Mega|mega":[1e6,Math.pow(1024,2)],"k|Kilo|kilo":[1e3,1024],"h|hecto":[100,100],"da|deka":[10,10],"d|deci":[.1,.1],"c|centi":[.01,.01],"m|milli":[.001,.001],"µ|micro":[1e-6,1e-6],"n|nano":[1e-9,1e-9],"p|pico":[1e-12,1e-12],"f|femto":[1e-15,1e-15],"a|atto":[1e-18,1e-18],"z|zepto":[1e-21,1e-21],"y|yocto":[1e-24,1e-24]},c="(\\d+)(\\s+)?([Zz]etta|[Ee]xa|[Pp]eta|[Tt]era|[Gg]iga|[Mm]ega|kilo|hecto|deka|deci|centi|milli|micro|nano|pico|femto|atto|zepto|yocto)(",d="(\\d+)(\\s+)?(Z|E|P|T|G|M|k|h|da|d|c|m|µ|n|p|f|a|z|y)(",e=/^[b|bit|byte|o|octet]/i;a.tablesorter.addParser({id:"metric",is:function(){return!1},format:function(f,g,h,i){var j,k,l,m,n="m|meter",o=a.tablesorter.formatFloat(f.replace(/[^\w,. \-()]/g,""),g),p=g.config.$headerIndexed[i],q=p.data("metric");if(q||(j=(p.attr("data-metric-name")||n).split("|"),l=p.attr("data-metric-name-full")||"",m=p.attr("data-metric-name-abbr")||"",q=[l||j[1]||j[0].substring(1),m||j[0]],k=e.test(q.join("")),q[2]=new RegExp(c+((""===l?"":l+"|"+m)||(k?q[0].toLowerCase()+"|"+q[0].toUpperCase():q[0])+"|"+(k?q[1].toLowerCase()+"|"+q[1].toUpperCase():q[1]))+")"),q[3]=new RegExp(d+(m||(k?q[1].toLowerCase()+"|"+q[1].toUpperCase():q[1]))+")"),p.data("metric",q)),j=f.match(q[2])||f.match(q[3]))for(n in b)if(j[3].match(n))return k=e.test(j[4])?1:0,o*b[n][k];return o},type:"numeric"})}(jQuery);

View File

@ -43,17 +43,26 @@
<p class="tip">
<em>NOTE!</em>
<ul>
<li>In <span class="version update">v2.22.2</span>,
<ul>
<li>Added header data-attribute <code>data-metric-name-full</code> which will contain the full base unit name, e.g. <code>"byte|Byte|BYTE"</code>. This change should allow for different capitalizations of the base unit name.</li>
<li>Added header data-attribute <code>data-metric-name-abbr</code> which will contain the abbreviated base unit name, e.g. <code>"b|B"</code>. This change also should allow for different capitalizations of the base unit name.</li>
<li>Each name is separated by a pipe, or vertical bar, ("<code>|</code>") without spaces, because it will eventually be used in a regular expression - the vertical bar signifies an "OR" operator.</li>
<li>When using these new data-attributes, the value in <code>data-metric-name</code> (now deprecated) will be ignored; eventually <code>data-metric-name</code> support will be removed.</li>
<li>These additions were made because of <em>common misuse</em> of abbreviated capitalization in the metric units, i.e. "kB" versus "kb". The lower case "b" is for "bit", and upper case "B" is for "byte". I am guilty of this too!</li>
</ul>
</li>
<li>This parser will convert numbers with metric prefixes ("Mega", "Giga", etc) into appropriate values so they are sorted correctly.</li>
<li>The base name must be included in the header:
<ul>
<li>The base is the unit of measure, such as "byte", "meter", "liter", etc.</li>
<li>When saving the base, include both the abbreviation and full name of the base separated by a vertical bar (shift-\) <code>b|byte</code>.</li>
<li>Store this information within the header's data-attribute (<code>data-metric-name="b|byte"</code>).</li>
<li><span class="label alert">deprecated</span> When saving the base, include both the abbreviation and full name of the base separated by a vertical bar (shift-\) <code>b|byte</code>.</li>
<li><span class="label alert">deprecated</span> Store this information within the header's data-attribute (<code>data-metric-name="b|byte"</code>) - this data-attribute should be considered deprecated as of v2.22.2, use <code>data-metric-name-full</code> &amp; <code>data-metric-name-abbr</code> instead.</li>
<li>If no base information is found, it will default to <code>m|meter</code>.</li>
</ul>
</li>
<li>Because metric prefixes can be applied to binary values, the parser will calculate the cached value based on the binary multiple, i.e. <code>"1 kb"</code> is actually <code>"1024 bytes"</code>. See <a href="http://en.wikipedia.org/wiki/Unit_prefix#Binary_prefixes">this article</a> for more details.</li>
<li>This parser does not (yet) support the IEC recommendations for binary prefixes (i.e. "kibibyte (Kib)", "mebibyte (MiB)", etc).</li>
<li>Because metric prefixes can be applied to binary values, the parser will calculate the cached value based on the binary multiple, i.e. <code>"1 kB"</code> is actually <code>"1024 bytes"</code>. See <a href="http://en.wikipedia.org/wiki/Unit_prefix#Binary_prefixes">this article</a> for more details.</li>
<li>This parser does not (yet) support the IEC recommendations for binary prefixes (i.e. "kibibyte (KiB)", "mebibyte (MiB)", etc).</li>
<li>Supported prefixes include: Yotta (10<sup>24</sup>), Zetta (10<sup>21</sup>), Exa (10<sup>18</sup>), Peta (10<sup>15</sup>), Tera (10<sup>12</sup>), Giga (10<sup>9</sup>), Mega (10<sup>6</sup>), kilo (10<sup>3</sup>), hecto (10<sup>2</sup>), deka (10<sup>1</sup>), deci (10<sup>-1</sup>), centi (10<sup>-2</sup>), milli (10<sup>-3</sup>), micro (10<sup>-6</sup>), nano (10<sup>-9</sup>), pico (10<sup>-12</sup>), femto (10<sup>-15</sup>), atto (10<sup>-18</sup>), zepto (10<sup>-21</sup>) and yocto (10<sup>-24</sup>).</li>
<li>This demo includes the stored metric values within the table cells, toggle the view using the button below.</li>
</ul>
@ -63,23 +72,26 @@
<button type="button" class="toggleparsedvalue">Toggle parsed values</button>
<div id="demo"><table class="tablesorter">
<thead>
<tr><th class="sorter-metric" data-metric-name="b|byte">Metric (binary) Size</th>
<tr>
<th class="sorter-metric" data-metric-name-full="byte|Byte|BYTE" data-metric-name-abbr="b|B">Metric (binary) Size</th>
<!-- "data-metric-name" is deprecated in v2.22.2, use "data-metric-name-full" and "data-metric-name-abbr" instead -->
<th class="sorter-metric" data-metric-name="m|meter">Metric Length</th>
</tr>
</thead>
<tbody>
<tr><td>1 byte</td><td>1 nm</td></tr>
<tr><td>1 kb</td><td>1 kilometer</td></tr>
<tr><td>1 kB</td><td>1 kilometer</td></tr>
<tr><td>1 Gigabyte</td><td>1 Gm</td></tr>
<tr><td>10 Mb</td><td>1 Tm</td></tr>
<tr><td>1 Mb</td><td>1,000 mm</td></tr>
<tr><td>1 Tb</td><td>1 meter</td></tr>
<tr><td>10 MB</td><td>1 Tm</td></tr>
<tr><td>1 MB</td><td>1,000 mm</td></tr>
<tr><td>1 TB</td><td>1 meter</td></tr>
<tr><td>1 Petabyte</td><td>1 hm</td></tr>
<tr><td>1 Zb</td><td>1 dam</td></tr>
<tr><td>1,025 Mb</td><td>1 Mm</td></tr>
<tr><td>1 ZB</td><td>1 dam</td></tr>
<tr><td>1 ZettaB</td><td>1 millimeter</td></tr>
<tr><td>1,025 MB</td><td>1 Mm</td></tr>
<tr><td>1,000 kilobytes</td><td>1 dm</td></tr>
<tr><td>1 Eb</td><td>1 µm</td></tr>
<tr><td>1023 Mb</td><td>1 pm</td></tr>
<tr><td>1 EB</td><td>1 µm</td></tr>
<tr><td>1023 MB</td><td>1 pm</td></tr>
</tbody>
</table></div>

View File

@ -1,75 +1,90 @@
/*! Parser: metric *//*
* Demo: http://jsfiddle.net/Mottie/abkNM/382/
* Set the metric name in the header (defaults to "m|meter"), e.g.
* <th data-metric-name="b|byte">HDD Size</th>
* <th data-metric-name="m|meter">Distance</th>
* Set the metric name in the header (defaults to 'm|meter'), e.g.
* <th data-metric-name-abbr="b|B" data-metric-name-full="byte|Byte|BYTE">HDD Size</th>
* <th data-metric-name="m|meter">Distance</th> <!-- data-metric-name is deprecated in v2.22.2 -->
*/
/*jshint jquery:true */
;( function( $ ) {
"use strict";
'use strict';
var prefixes = {
// "prefix" : [ base 10, base 2 ]
// 'prefix' : [ base 10, base 2 ]
// skipping IEEE 1541 defined prefixes: kibibyte, mebibyte, etc, for now.
"Y|Yotta|yotta" : [ 1e24, Math.pow(1024, 8) ], // 1024^8
"Z|Zetta|zetta" : [ 1e21, Math.pow(1024, 7) ], // 1024^7
"E|Exa|exa" : [ 1e18, Math.pow(1024, 6) ], // 1024^6
"P|Peta|peta" : [ 1e15, Math.pow(1024, 5) ], // 1024^5
"T|Tera|tera" : [ 1e12, Math.pow(1024, 4) ], // 1024^4
"G|Giga|giga" : [ 1e9, Math.pow(1024, 3) ], // 1024^3
"M|Mega|mega" : [ 1e6, Math.pow(1024, 2) ], // 1024^2
"k|Kilo|kilo" : [ 1e3, 1024 ], // 1024
'Y|Yotta|yotta' : [ 1e24, Math.pow(1024, 8) ], // 1024^8
'Z|Zetta|zetta' : [ 1e21, Math.pow(1024, 7) ], // 1024^7
'E|Exa|exa' : [ 1e18, Math.pow(1024, 6) ], // 1024^6
'P|Peta|peta' : [ 1e15, Math.pow(1024, 5) ], // 1024^5
'T|Tera|tera' : [ 1e12, Math.pow(1024, 4) ], // 1024^4
'G|Giga|giga' : [ 1e9, Math.pow(1024, 3) ], // 1024^3
'M|Mega|mega' : [ 1e6, Math.pow(1024, 2) ], // 1024^2
'k|Kilo|kilo' : [ 1e3, 1024 ], // 1024
// prefixes below here are rarely, if ever, used in binary
"h|hecto" : [ 1e2, 1e2 ],
"da|deka" : [ 1e1, 1e1 ],
"d|deci" : [ 1e-1, 1e-1 ],
"c|centi" : [ 1e-2, 1e-2],
"m|milli" : [ 1e-3, 1e-3 ],
"µ|micro" : [ 1e-6, 1e-6 ],
"n|nano" : [ 1e-9, 1e-9 ],
"p|pico" : [ 1e-12, 1e-12 ],
"f|femto" : [ 1e-15, 1e-15 ],
"a|atto" : [ 1e-18, 1e-18 ],
"z|zepto" : [ 1e-21, 1e-21 ],
"y|yocto" : [ 1e-24, 1e-24 ]
'h|hecto' : [ 1e2, 1e2 ],
'da|deka' : [ 1e1, 1e1 ],
'd|deci' : [ 1e-1, 1e-1 ],
'c|centi' : [ 1e-2, 1e-2],
'm|milli' : [ 1e-3, 1e-3 ],
'µ|micro' : [ 1e-6, 1e-6 ],
'n|nano' : [ 1e-9, 1e-9 ],
'p|pico' : [ 1e-12, 1e-12 ],
'f|femto' : [ 1e-15, 1e-15 ],
'a|atto' : [ 1e-18, 1e-18 ],
'z|zepto' : [ 1e-21, 1e-21 ],
'y|yocto' : [ 1e-24, 1e-24 ]
},
// the \\d+ will not catch digits with spaces, commas or decimals; so use the value from n instead
RegLong = "(\\d+)(\\s+)?([Zz]etta|[Ee]xa|[Pp]eta|[Tt]era|[Gg]iga|[Mm]ega|kilo|hecto|deka|deci|centi|milli|micro|nano|pico|femto|atto|zepto|yocto)(",
RegAbbr = "(\\d+)(\\s+)?(Z|E|P|T|G|M|k|h|da|d|c|m|µ|n|p|f|a|z|y)(";
RegLong = '(\\d+)(\\s+)?([Zz]etta|[Ee]xa|[Pp]eta|[Tt]era|[Gg]iga|[Mm]ega|kilo|hecto|deka|deci|centi|milli|micro|nano|pico|femto|atto|zepto|yocto)(',
RegAbbr = '(\\d+)(\\s+)?(Z|E|P|T|G|M|k|h|da|d|c|m|µ|n|p|f|a|z|y)(',
// make these case-insensitive because we all forget the case for these binary values
byteTest = /^[b|bit|byte|o|octet]/i;
$.tablesorter.addParser({
id: 'metric',
is: function() {
return false;
},
format: function(s, table, cell, cellIndex) {
var v = 'm|meter',
b, t,
format: function(txt, table, cell, cellIndex) {
var unit, isBinary, nameLong, nameAbbr,
// default base unit name
base = 'm|meter',
// process number here to get a numerical format (us or eu)
n = $.tablesorter.formatFloat(s.replace(/[^\w,. \-()]/g, ""), table),
num = $.tablesorter.formatFloat( txt.replace(/[^\w,. \-()]/g, ''), table ),
$t = table.config.$headerIndexed[ cellIndex ],
m = $t.data('metric');
if (!m) {
regex = $t.data( 'metric' );
if ( !regex ) {
// stored values
t = ($t.attr('data-metric-name') || v).split('|');
m = [ t[1] || t[0].substring(1), t[0] ];
m[2] = new RegExp(RegLong + m[0] + "|" + m[1] + ")");
m[3] = new RegExp(RegAbbr + m[1] + ")");
$t.data('metric', m);
unit = ( $t.attr('data-metric-name') || base ).split( '|' );
nameLong = $t.attr( 'data-metric-name-full' ) || '';
nameAbbr = $t.attr( 'data-metric-name-abbr' ) || '';
regex = [ nameLong || unit[1] || unit[0].substring(1), nameAbbr || unit[0] ];
isBinary = byteTest.test( regex.join( '' ) );
// adding 'data-metric-name-full' which would contain 'byte|BYTE|Byte' etc
regex[2] = new RegExp( RegLong + (
( nameLong === '' ? '' : nameLong + '|' + nameAbbr ) ||
// with data-metric-name='b|byte', we end up with 'b|B|byte|BYTE' - maybe not the best solution for case-insensitivity
( ( isBinary ? regex[0].toLowerCase() + '|' + regex[0].toUpperCase() : regex[0] ) + '|' +
( isBinary ? regex[1].toLowerCase() + '|' + regex[1].toUpperCase() : regex[1] ) ) ) +
')' );
// adding 'data-metric-name-abbr' which would contain 'b|B' etc
regex[3] = new RegExp( RegAbbr + ( nameAbbr ||
( ( isBinary ? regex[1].toLowerCase() + '|' + regex[1].toUpperCase() : regex[1] ) ) ) +
')' );
$t.data( 'metric', regex );
}
// find match to full name or abbreviation
t = s.match(m[2]) || s.match(m[3]);
if (t) {
for (v in prefixes) {
if (t[3].match(v)) {
unit = txt.match( regex[2] ) || txt.match( regex[3] );
if ( unit ) {
for ( base in prefixes ) {
if ( unit[3].match( base ) ) {
// exception when using binary prefix
// change base for binary use
b = /^[b|bit|byte|o|octet]/.test(t[4]) ? 1 : 0;
return n * prefixes[v][b];
isBinary = byteTest.test( unit[4] ) ? 1 : 0;
return num * prefixes[ base ][ isBinary ];
}
}
}
return n;
return num;
},
type: 'numeric'
});