Comparing version 2.2.4 to 3.0.0
{ | ||
"name": "tablesort", | ||
"description": "A sorting component for HTML tables", | ||
"version": "2.2.3", | ||
"version": "3.0.0", | ||
"license": "MIT", | ||
"main": "tablesort.min.js", | ||
"authors": [ | ||
"tristen <@fallsemo>" | ||
"tristen" | ||
], | ||
@@ -10,0 +10,0 @@ "homepage": "http://tristen.ca/tablesort/demo", |
14
ender.js
!function ($) { | ||
$.ender({ | ||
tablesort: function (options) { | ||
return this.forEach(function (el) { | ||
new Tablesort(el, options); | ||
}); | ||
} | ||
}, true); | ||
$.ender({ | ||
tablesort: function (options) { | ||
return this.forEach(function (el) { | ||
new Tablesort(el, options); | ||
}); | ||
} | ||
}, true); | ||
}(ender); |
{ | ||
"name": "tablesort", | ||
"description": "A sorting component for HTML tables", | ||
"version": "2.2.4", | ||
"author": "tristen <@fallsemo>", | ||
"version": "3.0.0", | ||
"author": "tristen", | ||
"ender": "./ender.js", | ||
"main": "./src/tablesort.js", | ||
"homepage": "http://tristen.ca/tablesort/demo", | ||
"homepage": "http://tristen.ca/tablesort/demo/", | ||
"scripts": { | ||
@@ -10,0 +10,0 @@ "test": "tape test/test.client.js | tap-spec" |
109
README.md
@@ -8,6 +8,11 @@ tablesort | ||
### Basic usage | ||
### Quick start | ||
``` html | ||
<script src='tablesort.min.js'></script> | ||
<!-- Include sort types you need --> | ||
<script src='tablesort.numeric.js'></script> | ||
<script src='tablesort.date.js'></script> | ||
<script> | ||
@@ -19,8 +24,4 @@ new Tablesort(document.getElementById('table-id')); | ||
* strings | ||
* numbers | ||
* currency | ||
* Basic dates in `dd/mm/yy` or `dd-mm-yy` format. Years can be 4 digits. Days and Months can be 1 or 2 digits. | ||
* Dot separated values. E.g. IP addresses or version numbers. | ||
* Filesizes. E.g. "5.35 K", "10 MB", "12.45 GB", "4.67 TiB" | ||
See all available sort types in the [sorts](https://github.com/tristen/tablesort/tree/gh-pages/src/sorts/) | ||
directory. Defaults to string if no sort types are provided. | ||
@@ -30,3 +31,4 @@ ### Additional options | ||
#### Ascending/Descending | ||
You can pass in options as a second parameter. Currently one option is supported: `descending: true`. By default, sort is set to ascending. | ||
You can pass in options as a second parameter. Currently one option is | ||
supported: `descending: true`. By default, sort is set to ascending. | ||
@@ -40,3 +42,4 @@ ``` js | ||
#### Exclude columns or rows | ||
For columns or rows that do not require sorting, you can add a class of `no-sort` to a columns `th` or a `tr` element. | ||
For columns or rows that do not require sorting, you can add a class of | ||
`no-sort` to a columns `th` or a `tr` element. | ||
``` html | ||
@@ -55,3 +58,4 @@ <th class='no-sort'>Name</th> | ||
#### Override data that is sorted on | ||
Sometimes text inside cells is not normalized. Using a `data-sort` attribute you can use optional data to sort on. | ||
Sometimes text inside cells is not normalized. Using a `data-sort` attribute | ||
you can use optional data to sort on. | ||
@@ -69,4 +73,23 @@ ``` html | ||
#### Specify the sort method for a column | ||
By adding a `data-sort-method` attribute to a table heading you can force | ||
Tablesort to use a specific sorting method rather than guessing it. The value | ||
of `data-sort-method` corresponds to the name of a sort function. | ||
``` html | ||
<th>Number</th> | ||
<th data-sort-method='dotsep'>Version</th> | ||
<tr> | ||
<td>1</td> | ||
<td>1.08.2013</td> | ||
</tr> | ||
<tr> | ||
<td>2</td> | ||
<td>3.7.2004</td> | ||
</tr> | ||
``` | ||
#### Default sort on tablesort initialization | ||
It is possible to automatically sort the table once you create a Tablesort instance by adding `sort-default` class. | ||
It is possible to automatically sort the table once you create a Tablesort | ||
instance by adding `sort-default` class. | ||
@@ -77,4 +100,21 @@ ``` html | ||
#### Events | ||
Tablesort supports two custom events: `beforeSort` & `afterSort`. | ||
``` js | ||
var table = document.getElementById('table-id'); | ||
var sort = new Tablesort(table); | ||
table.addEventListener('beforeSort', function() { | ||
alert('Table is about to be sorted!'); | ||
}); | ||
table.addEventListener('afterSort', function() { | ||
alert('Table sorted!'); | ||
}); | ||
``` | ||
#### Refresh sort on appended data | ||
Tablesort supports sorting when new data has been added. Simply call the refresh method. | ||
Tablesort supports sorting when new data has been added. Simply call the refresh | ||
method. | ||
@@ -101,3 +141,4 @@ ``` js | ||
### Ender support | ||
Add `tablesort` as an internal chain method to your [Ender](https://github.com/ender-js/Ender/) compilation. | ||
Add `tablesort` as an internal chain method to your [Ender](https://github.com/ender-js/Ender/) | ||
compilation. | ||
@@ -110,3 +151,3 @@ ``` js | ||
### Default style | ||
### Default CSS | ||
Add the styling below to your CSS or roll with your own. | ||
@@ -116,3 +157,3 @@ | ||
th.sort-header::-moz-selection { background:transparent; } | ||
th.sort-header::selection { background:transparent; } | ||
th.sort-header::selection { background:transparent; } | ||
th.sort-header { | ||
@@ -149,19 +190,43 @@ cursor:pointer; | ||
### Building | ||
### Extending Tablesort | ||
Tablesort relies on [Grunt](http://gruntjs.com) as its build tool. Simply run `grunt` to package code | ||
from any contributions you make to `src/tablesort.js` before submitting pull requests. | ||
If you require a sort operation that does not exist | ||
in the [sorts](https://github.com/tristen/tablesort/tree/gh-pages/src/sorts/) | ||
directory, you can add your own. | ||
### Licence | ||
``` js | ||
Tablesort.extend('name', function(item) { | ||
MIT | ||
// Regular expression to test against. | ||
// `item` is a table value to evaluate. | ||
return /foo/.test(item); | ||
}, function(a, b) { | ||
### Tests | ||
// Custom sort functionality goes here. | ||
// e.g var n = (a > b) ? -1 : 1; | ||
return n; | ||
}); | ||
``` | ||
If you've made an extend function that others would benifit from pull requests | ||
are gladly accepted! | ||
### Contributing | ||
Tablesort relies on [Grunt](http://gruntjs.com) as its build tool. Simply run | ||
`grunt` to package code from any contributions you make to `src/tablesort.js` | ||
before submitting pull requests. | ||
Tests are run via: | ||
```sh | ||
npm test | ||
npm install && npm test | ||
``` | ||
### Licence | ||
MIT | ||
### Bugs? | ||
[Create an issue](https://github.com/tristen/tablesort/issues) |
;(function() { | ||
function Tablesort(el, options) { | ||
if (!el) throw new Error('Element not found'); | ||
if (el.tagName !== 'TABLE') throw new Error('Element must be a table'); | ||
this.init(el, options || {}); | ||
function Tablesort(el, options) { | ||
if (!el || el.tagName !== 'TABLE') { | ||
throw new Error('Element must be a table'); | ||
} | ||
this.init(el, options || {}); | ||
} | ||
Tablesort.prototype = { | ||
var sortOptions = []; | ||
init: function(el, options) { | ||
var that = this, | ||
firstRow; | ||
this.thead = false; | ||
this.options = options; | ||
var createEvent = function(name) { | ||
var evt; | ||
if (el.rows && el.rows.length > 0) { | ||
if (el.tHead && el.tHead.rows.length > 0) { | ||
firstRow = el.tHead.rows[el.tHead.rows.length - 1]; | ||
that.thead = true; | ||
} else { | ||
firstRow = el.rows[0]; | ||
} | ||
} | ||
if (!window.CustomEvent || typeof window.CustomEvent !== 'function') { | ||
evt = document.createEvent('CustomEvent'); | ||
evt.initCustomEvent(name, false, false, undefined); | ||
} else { | ||
evt = new CustomEvent(name); | ||
} | ||
if (!firstRow) return; | ||
return evt; | ||
}; | ||
var onClick = function() { | ||
if (that.current && that.current !== this) { | ||
if (that.current.classList.contains(classSortUp)) { | ||
that.current.classList.remove(classSortUp); | ||
} | ||
else if (that.current.classList.contains(classSortDown)) { | ||
that.current.classList.remove(classSortDown); | ||
} | ||
} | ||
var getInnerText = function(el) { | ||
return el.getAttribute('data-sort') || el.textContent || el.innerText || ''; | ||
}; | ||
that.current = this; | ||
that.sortTable(this); | ||
}; | ||
// Default sort method if no better sort method is found | ||
var caseInsensitiveSort = function(a, b) { | ||
a = a.toLowerCase(); | ||
b = b.toLowerCase(); | ||
var defaultSort; | ||
if (a === b) return 0; | ||
if (a < b) return 1; | ||
// Assume first row is the header and attach a click handler to each. | ||
for (var i = 0; i < firstRow.cells.length; i++) { | ||
var cell = firstRow.cells[i]; | ||
if (!cell.classList.contains('no-sort')) { | ||
cell.classList.add('sort-header'); | ||
cell.addEventListener('click', onClick, false); | ||
return -1; | ||
}; | ||
if (cell.classList.contains('sort-default')) { | ||
defaultSort = cell; | ||
} | ||
} | ||
} | ||
// Stable sort function | ||
// If two elements are equal under the original sort function, | ||
// then there relative order is reversed | ||
var stabilize = function(sort, antiStabilize) { | ||
return function(a, b) { | ||
var unstableResult = sort(a.td, b.td); | ||
if (defaultSort) { | ||
that.current = defaultSort; | ||
that.sortTable(defaultSort, true); | ||
} | ||
}, | ||
if (unstableResult === 0) { | ||
if (antiStabilize) return b.index - a.index; | ||
return a.index - b.index; | ||
} | ||
getFirstDataRowIndex: function() { | ||
// If table does not have a <thead>, assume that first row is | ||
// a header and skip it. | ||
if (!this.thead) { | ||
return 1; | ||
} else { | ||
return 0; | ||
} | ||
}, | ||
return unstableResult; | ||
}; | ||
}; | ||
sortTable: function(header, update) { | ||
var that = this, | ||
column = header.cellIndex, | ||
sortFunction, | ||
t = getParent(header, 'table'), | ||
item = '', | ||
items = [], | ||
i = that.getFirstDataRowIndex(); | ||
Tablesort.extend = function(name, pattern, sort) { | ||
if (typeof pattern !== 'function' || typeof sort !== 'function') { | ||
throw new Error('Pattern and sort must be a function'); | ||
} | ||
if (t.rows.length <= 1) return; | ||
sortOptions.push({ | ||
name: name, | ||
pattern: pattern, | ||
sort: sort | ||
}); | ||
}; | ||
while (items.length < 3 && i < t.tBodies[0].rows.length) { | ||
item = getInnerText(t.tBodies[0].rows[i].cells[column]); | ||
item = item.trim(); | ||
// Exclude cell values where commented out HTML exists | ||
if (item.substr(0, 4) !== '<!--' && item.length !== 0) { | ||
items.push(item); | ||
} | ||
i++; | ||
} | ||
Tablesort.prototype = { | ||
if (!items) return; | ||
init: function(el, options) { | ||
var that = this, | ||
firstRow, | ||
defaultSort, | ||
i, | ||
cell; | ||
// Possible sortFunction scenarios | ||
var sortCaseInsensitive = function(a, b) { | ||
var aa = getInnerText(a.cells[that.col]).toLowerCase(), | ||
bb = getInnerText(b.cells[that.col]).toLowerCase(); | ||
that.table = el; | ||
that.thead = false; | ||
that.options = options; | ||
if (aa === bb) return 0; | ||
if (aa < bb) return 1; | ||
if (el.rows && el.rows.length > 0) { | ||
if (el.tHead && el.tHead.rows.length > 0) { | ||
firstRow = el.tHead.rows[el.tHead.rows.length - 1]; | ||
that.thead = true; | ||
} else { | ||
firstRow = el.rows[0]; | ||
} | ||
} | ||
return -1; | ||
}; | ||
if (!firstRow) return; | ||
var sortNumber = function(a, b) { | ||
var aa = getInnerText(a.cells[that.col]), | ||
bb = getInnerText(b.cells[that.col]); | ||
var onClick = function() { | ||
if (that.current && that.current !== this) { | ||
that.current.classList.remove('sort-up'); | ||
that.current.classList.remove('sort-down'); | ||
} | ||
aa = cleanNumber(aa); | ||
bb = cleanNumber(bb); | ||
return compareNumber(bb, aa); | ||
}; | ||
that.current = this; | ||
that.sortTable(this); | ||
}; | ||
var sortDate = function(a, b) { | ||
var aa = getInnerText(a.cells[that.col]).toLowerCase(), | ||
bb = getInnerText(b.cells[that.col]).toLowerCase(); | ||
return parseDate(bb) - parseDate(aa); | ||
}; | ||
// Assume first row is the header and attach a click handler to each. | ||
for (i = 0; i < firstRow.cells.length; i++) { | ||
cell = firstRow.cells[i]; | ||
if (!cell.classList.contains('no-sort')) { | ||
cell.classList.add('sort-header'); | ||
cell.addEventListener('click', onClick, false); | ||
var sortDotSep = function(a, b) { | ||
var aa = getInnerText(a.cells[that.col]).split('.'), | ||
bb = getInnerText(b.cells[that.col]).split('.'); | ||
if (cell.classList.contains('sort-default')) { | ||
defaultSort = cell; | ||
} | ||
} | ||
} | ||
for (var i = 0, len = aa.length; i < len; i++) { | ||
var aai = parseInt(aa[i]), | ||
bbi = parseInt(bb[i]); | ||
if (defaultSort) { | ||
that.current = defaultSort; | ||
that.sortTable(defaultSort); | ||
} | ||
}, | ||
if (aai == bbi) continue; | ||
if (aai > bbi) return -1; | ||
if (aai < bbi) return 1; | ||
} | ||
return 0; | ||
}; | ||
sortTable: function(header, update) { | ||
var that = this, | ||
column = header.cellIndex, | ||
sortFunction = caseInsensitiveSort, | ||
item = '', | ||
items = [], | ||
i = that.thead ? 0 : 1, | ||
sortMethod = header.getAttribute('data-sort-method'); | ||
var sortFilesize = function(a, b) { | ||
var aa = filesize2num(getInnerText(a.cells[that.col])) | ||
bb = filesize2num(getInnerText(b.cells[that.col])); | ||
that.table.dispatchEvent(createEvent('beforeSort')); | ||
return compareNumber(bb, aa); | ||
}; | ||
if (that.table.rows.length < 2) return; | ||
// Sort dot separated numbers, e.g. ip addresses or version numbers | ||
if (items.every(testDotSeparatedNumbers)) { | ||
sortFunction = sortDotSep; | ||
} | ||
// sort filesize, e.g. "123.45 MB" | ||
else if (items.every(testFilesize)) { | ||
sortFunction = sortFilesize; | ||
} | ||
// Sort as number if a currency key exists or number | ||
else if (items.every(testNumber)) { | ||
sortFunction = sortNumber; | ||
} else if (items.every(testDate)) { | ||
sortFunction = sortDate; | ||
} else { | ||
sortFunction = sortCaseInsensitive; | ||
} | ||
// If we force a sort method, it is not necessary to check rows | ||
if (!sortMethod) { | ||
while (items.length < 3 && i < that.table.tBodies[0].rows.length) { | ||
item = getInnerText(that.table.tBodies[0].rows[i].cells[column]); | ||
item = item.trim(); | ||
this.col = column; | ||
var newRows = [], | ||
noSorts = {}, | ||
j, | ||
totalRows = 0; | ||
if (item.length > 0) { | ||
items.push(item); | ||
i++; | ||
} | ||
} | ||
for (i = 0; i < t.tBodies.length; i++) { | ||
for (j = 0; j < t.tBodies[i].rows.length; j++) { | ||
var tr = t.tBodies[i].rows[j]; | ||
if (tr.classList.contains('no-sort')) { | ||
// keep no-sorts in separate list to be able to insert | ||
// them back at their original position later | ||
noSorts[totalRows] = tr; | ||
} else { | ||
// Save the index for stable sorting | ||
newRows.push({ | ||
tr: tr, | ||
index: totalRows | ||
}); | ||
} | ||
totalRows++; | ||
} | ||
} | ||
if (!items) return; | ||
} | ||
var sortUp = that.options.descending ? classSortDown : classSortUp, | ||
sortDown = that.options.descending ? classSortUp : classSortDown; | ||
for (i = 0; i < sortOptions.length; i++) { | ||
item = sortOptions[i]; | ||
if (!update) { | ||
if (header.classList.contains(sortUp)) { | ||
header.classList.remove(sortUp); | ||
header.classList.add(sortDown); | ||
} else { | ||
header.classList.remove(sortDown); | ||
header.classList.add(sortUp); | ||
} | ||
} else if (!header.classList.contains(sortUp) && !header.classList.contains(sortDown)) { | ||
header.classList.add(sortUp); | ||
} | ||
if (sortMethod) { | ||
if (item.name === sortMethod) { | ||
sortFunction = item.sort; | ||
break; | ||
} | ||
} else if (items.every(item.pattern)) { | ||
sortFunction = item.sort; | ||
break; | ||
} | ||
} | ||
// Make a stable sort function | ||
var stabilize = function(sort) { | ||
return function(a, b) { | ||
var unstableResult = sort(a.tr, b.tr); | ||
if (unstableResult === 0) { | ||
return a.index - b.index; | ||
} | ||
return unstableResult; | ||
}; | ||
}; | ||
that.col = column; | ||
var newRows = [], | ||
noSorts = {}, | ||
j, | ||
totalRows = 0, | ||
noSortsSoFar = 0, | ||
sortDir; | ||
// Make an `anti-stable` sort function. If two elements are equal | ||
// under the original sort function, then there relative order is | ||
// reversed. | ||
var antiStabilize = function(sort) { | ||
return function(a, b) { | ||
var unstableResult = sort(a.tr, b.tr); | ||
if (unstableResult === 0) { | ||
return b.index - a.index; | ||
} | ||
return unstableResult; | ||
}; | ||
}; | ||
for (i = 0; i < that.table.tBodies.length; i++) { | ||
for (j = 0; j < that.table.tBodies[i].rows.length; j++) { | ||
item = that.table.tBodies[i].rows[j]; | ||
if (item.classList.contains('no-sort')) { | ||
// keep no-sorts in separate list to be able to insert | ||
// them back at their original position later | ||
noSorts[totalRows] = item; | ||
} else { | ||
// Save the index for stable sorting | ||
newRows.push({ | ||
tr: item, | ||
td: getInnerText(item.cells[that.col]), | ||
index: totalRows | ||
}); | ||
} | ||
totalRows++; | ||
} | ||
} | ||
// Before we append should we reverse the new array or not? | ||
// If we reverse, the sort needs to be `anti-stable` so that | ||
// the double negatives cancel out | ||
if (header.classList.contains(classSortDown)) { | ||
newRows.sort(antiStabilize(sortFunction)); | ||
newRows.reverse(); | ||
} else { | ||
newRows.sort(stabilize(sortFunction)); | ||
} | ||
// append rows that already exist rather than creating new ones | ||
var noSortsSoFar = 0; | ||
for (i = 0; i < totalRows; i++) { | ||
var whatToInsert; | ||
if (noSorts[i]) { | ||
// We have a no-sort row for this position, insert it here. | ||
whatToInsert = noSorts[i]; | ||
noSortsSoFar++; | ||
} else { | ||
whatToInsert = newRows[i - noSortsSoFar].tr; | ||
} | ||
// appendChild(x) moves x if already present somewhere else in the DOM | ||
t.tBodies[0].appendChild(whatToInsert); | ||
} | ||
// callback | ||
if (that.options.callback && typeof that.options.callback === 'function') { | ||
that.options.callback(header); | ||
} | ||
}, | ||
refresh: function() { | ||
if (this.current !== undefined) { | ||
this.sortTable(this.current, true); | ||
} | ||
// If updating an existing sort `sortDir` should remain unchanged. | ||
if (update) { | ||
sortDir = header.classList.contains('sort-up') ? 'sort-up' : 'sort-down'; | ||
} else { | ||
if (header.classList.contains('sort-up')) { | ||
sortDir = 'sort-down'; | ||
} else if (header.classList.contains('sort-down')) { | ||
sortDir = 'sort-up'; | ||
} else { | ||
sortDir = that.options.descending ? 'sort-up' : 'sort-down'; | ||
} | ||
}; | ||
var classSortUp = 'sort-up', | ||
classSortDown = 'sort-down'; | ||
header.classList.remove(sortDir === 'sort-down' ? 'sort-up' : 'sort-down'); | ||
header.classList.add(sortDir); | ||
} | ||
var week = /(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\.?\,?\s*/i, | ||
commonDate = /\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/, | ||
month = /(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)/i; | ||
// Before we append should we reverse the new array or not? | ||
// If we reverse, the sort needs to be `anti-stable` so that | ||
// the double negatives cancel out | ||
if (sortDir === 'sort-down') { | ||
newRows.sort(stabilize(sortFunction, true)); | ||
newRows.reverse(); | ||
} else { | ||
newRows.sort(stabilize(sortFunction, false)); | ||
} | ||
var testDotSeparatedNumbers = function(item){ | ||
return /^(\d+\.)+\d+$/.test(item); | ||
}; | ||
// append rows that already exist rather than creating new ones | ||
for (i = 0; i < totalRows; i++) { | ||
if (noSorts[i]) { | ||
// We have a no-sort row for this position, insert it here. | ||
item = noSorts[i]; | ||
noSortsSoFar++; | ||
} else { | ||
item = newRows[i - noSortsSoFar].tr; | ||
} | ||
var testFilesize = function(item){ | ||
return /^\d+(\.\d+)? ?(k|M|G|T|P|E|Z|Y)?i?B?$/i.test(item); | ||
}; | ||
// appendChild(x) moves x if already present somewhere else in the DOM | ||
that.table.tBodies[0].appendChild(item); | ||
} | ||
var testNumber = function(item){ | ||
return item.match(/^-?[£\x24Û¢´€]?\d+\s*([,\.]\d{0,2})/) || // prefixed currency | ||
item.match(/^-?\d+\s*([,\.]\d{0,2})?[£\x24Û¢´€]/) || // suffixed currency | ||
item.match(/^-?(\d)*-?([,\.]){0,1}-?(\d)+([E,e][\-+][\d]+)?%?$/); // number | ||
}; | ||
that.table.dispatchEvent(createEvent('afterSort')); | ||
}, | ||
var testDate = function(date) { | ||
return ( | ||
date.search(week) !== -1 || | ||
date.search(commonDate) !== -1 || | ||
date.search(month !== -1) | ||
) !== -1 && !isNaN(parseDate(date)); | ||
}, | ||
refresh: function() { | ||
if (this.current !== undefined) { | ||
this.sortTable(this.current, true); | ||
} | ||
} | ||
}; | ||
parseDate = function(date) { | ||
date = date.replace(/\-/g, '/'); | ||
date = date.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/, '$1/$2/$3'); // format before getTime | ||
return new Date(date).getTime(); | ||
}, | ||
getParent = function(el, pTagName) { | ||
if (el === null) { | ||
return null; | ||
} else if (el.nodeType === 1 && el.tagName.toLowerCase() === pTagName.toLowerCase()) { | ||
return el; | ||
} else { | ||
return getParent(el.parentNode, pTagName); | ||
} | ||
}, | ||
getInnerText = function(el) { | ||
if (typeof el === 'string' || typeof el === 'undefined') return el; | ||
return el.getAttribute('data-sort') || el.textContent || el.innerText || ''; | ||
}, | ||
compareNumber = function(a, b) { | ||
var aa = parseFloat(a), | ||
bb = parseFloat(b); | ||
a = isNaN(aa) ? 0 : aa; | ||
b = isNaN(bb) ? 0 : bb; | ||
return a - b; | ||
}, | ||
cleanNumber = function(i) { | ||
return i.replace(/[^\-?0-9.]/g, ''); | ||
}; | ||
// Converts filesize to bytes | ||
// Ex. filesize2num("123 KB") -> 123000 | ||
// Ex. filesize2num("123 KiB") -> 125952 | ||
filesize2num = function(filesize) { | ||
var matches = filesize.match(/^(\d+(\.\d+)?) ?((k|M|G|T|P|E|Z|Y)?i?B?)$/i); | ||
var num = parseFloat(cleanNumber(matches[1])), | ||
suffix = matches[3]; | ||
return num * suffix2num(suffix); | ||
}; | ||
// Returns suffix multiplier | ||
// Ex. suffix2num("KB") -> 1000 | ||
// Ex. suffix2num("KiB") -> 1024 | ||
suffix2num = function(suffix) { | ||
suffix = suffix.toLowerCase(); | ||
var base = suffix[1] === "i" ? 1024 : 1000; | ||
switch(suffix[0]) { | ||
case "k": | ||
return Math.pow(base, 2); | ||
case "m": | ||
return Math.pow(base, 3); | ||
case "g": | ||
return Math.pow(base, 4); | ||
case "t": | ||
return Math.pow(base, 5); | ||
case "p": | ||
return Math.pow(base, 6); | ||
case "e": | ||
return Math.pow(base, 7); | ||
case "z": | ||
return Math.pow(base, 8); | ||
case "y": | ||
return Math.pow(base, 9); | ||
default: | ||
return base; | ||
} | ||
}; | ||
if (typeof module !== 'undefined' && module.exports) { | ||
module.exports = Tablesort; | ||
} else { | ||
window.Tablesort = Tablesort; | ||
} | ||
if (typeof module !== 'undefined' && module.exports) { | ||
module.exports = Tablesort; | ||
} else { | ||
window.Tablesort = Tablesort; | ||
} | ||
})(); |
/*! | ||
* tablesort v2.2.4 (2015-02-03) | ||
* http://tristen.ca/tablesort/demo | ||
* tablesort v3.0.0 (2015-02-22) | ||
* http://tristen.ca/tablesort/demo/ | ||
* Copyright (c) 2015 ; Licensed MIT | ||
*/!function(){function a(a,b){if(!a)throw new Error("Element not found");if("TABLE"!==a.tagName)throw new Error("Element must be a table");this.init(a,b||{})}a.prototype={init:function(a,d){var e,f=this;if(this.thead=!1,this.options=d,a.rows&&a.rows.length>0&&(a.tHead&&a.tHead.rows.length>0?(e=a.tHead.rows[a.tHead.rows.length-1],f.thead=!0):e=a.rows[0]),e){for(var g,h=function(){f.current&&f.current!==this&&(f.current.classList.contains(b)?f.current.classList.remove(b):f.current.classList.contains(c)&&f.current.classList.remove(c)),f.current=this,f.sortTable(this)},i=0;i<e.cells.length;i++){var j=e.cells[i];j.classList.contains("no-sort")||(j.classList.add("sort-header"),j.addEventListener("click",h,!1),j.classList.contains("sort-default")&&(g=j))}g&&(f.current=g,f.sortTable(g,!0))}},getFirstDataRowIndex:function(){return this.thead?0:1},sortTable:function(a,d){var e,f=this,p=a.cellIndex,q=l(a,"table"),r="",s=[],t=f.getFirstDataRowIndex();if(!(q.rows.length<=1)){for(;s.length<3&&t<q.tBodies[0].rows.length;)r=m(q.tBodies[0].rows[t].cells[p]),r=r.trim(),"<!--"!==r.substr(0,4)&&0!==r.length&&s.push(r),t++;if(s){var u=function(a,b){var c=m(a.cells[f.col]).toLowerCase(),d=m(b.cells[f.col]).toLowerCase();return c===d?0:d>c?1:-1},v=function(a,b){var c=m(a.cells[f.col]),d=m(b.cells[f.col]);return c=o(c),d=o(d),n(d,c)},w=function(a,b){var c=m(a.cells[f.col]).toLowerCase(),d=m(b.cells[f.col]).toLowerCase();return k(d)-k(c)},x=function(a,b){for(var c=m(a.cells[f.col]).split("."),d=m(b.cells[f.col]).split("."),e=0,g=c.length;g>e;e++){var h=parseInt(c[e]),i=parseInt(d[e]);if(h!=i){if(h>i)return-1;if(i>h)return 1}}return 0},y=function(a,b){var c=filesize2num(m(a.cells[f.col]));return bb=filesize2num(m(b.cells[f.col])),n(bb,c)};e=s.every(g)?x:s.every(h)?y:s.every(i)?v:s.every(j)?w:u,this.col=p;var z,A=[],B={},C=0;for(t=0;t<q.tBodies.length;t++)for(z=0;z<q.tBodies[t].rows.length;z++){var D=q.tBodies[t].rows[z];D.classList.contains("no-sort")?B[C]=D:A.push({tr:D,index:C}),C++}var E=f.options.descending?c:b,F=f.options.descending?b:c;d?a.classList.contains(E)||a.classList.contains(F)||a.classList.add(E):a.classList.contains(E)?(a.classList.remove(E),a.classList.add(F)):(a.classList.remove(F),a.classList.add(E));var G=function(a){return function(b,c){var d=a(b.tr,c.tr);return 0===d?b.index-c.index:d}},H=function(a){return function(b,c){var d=a(b.tr,c.tr);return 0===d?c.index-b.index:d}};a.classList.contains(c)?(A.sort(H(e)),A.reverse()):A.sort(G(e));var I=0;for(t=0;C>t;t++){var J;B[t]?(J=B[t],I++):J=A[t-I].tr,q.tBodies[0].appendChild(J)}f.options.callback&&"function"==typeof f.options.callback&&f.options.callback(a)}}},refresh:function(){void 0!==this.current&&this.sortTable(this.current,!0)}};var b="sort-up",c="sort-down",d=/(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\.?\,?\s*/i,e=/\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/,f=/(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)/i,g=function(a){return/^(\d+\.)+\d+$/.test(a)},h=function(a){return/^\d+(\.\d+)? ?(k|M|G|T|P|E|Z|Y)?i?B?$/i.test(a)},i=function(a){return a.match(/^-?[£\x24Û¢´€]?\d+\s*([,\.]\d{0,2})/)||a.match(/^-?\d+\s*([,\.]\d{0,2})?[£\x24Û¢´€]/)||a.match(/^-?(\d)*-?([,\.]){0,1}-?(\d)+([E,e][\-+][\d]+)?%?$/)},j=function(a){return-1!==(-1!==a.search(d)||-1!==a.search(e)||a.search(-1!==f))&&!isNaN(k(a))},k=function(a){return a=a.replace(/\-/g,"/"),a=a.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/,"$1/$2/$3"),new Date(a).getTime()},l=function(a,b){return null===a?null:1===a.nodeType&&a.tagName.toLowerCase()===b.toLowerCase()?a:l(a.parentNode,b)},m=function(a){var b=this;if("string"==typeof a||"undefined"==typeof a)return a;var c=a.getAttribute("data-sort")||"";if(c)return c;if(a.textContent)return a.textContent;if(a.innerText)return a.innerText;for(var d=a.childNodes,e=d.length,f=0;e>f;f++)switch(d[f].nodeType){case 1:c+="IMG"===d[f].tagName||"SPAN"===d[f].tagName?d[f].alt||d[f].title||"":b.getInnerText(d[f]);break;case 3:c+=d[f].nodeValue}return c},n=function(a,b){var c=parseFloat(a),d=parseFloat(b);return a=isNaN(c)?0:c,b=isNaN(d)?0:d,a-b},o=function(a){return a.replace(/[^\-?0-9.]/g,"")};filesize2num=function(a){var b=a.match(/^(\d+(\.\d+)?) ?((k|M|G|T|P|E|Z|Y)?i?B?)$/i),c=parseFloat(o(b[1])),d=b[3];return c*suffix2num(d)},suffix2num=function(a){a=a.toLowerCase();var b="i"===a[1]?1024:1e3;switch(a[0]){case"k":return Math.pow(b,2);case"m":return Math.pow(b,3);case"g":return Math.pow(b,4);case"t":return Math.pow(b,5);case"p":return Math.pow(b,6);case"e":return Math.pow(b,7);case"z":return Math.pow(b,8);case"y":return Math.pow(b,9);default:return b}},"undefined"!=typeof module&&module.exports?module.exports=a:window.Tablesort=a}(); | ||
*/!function(){function a(a,b){if(!a||"TABLE"!==a.tagName)throw new Error("Element must be a table");this.init(a,b||{})}var b=[],c=function(a){var b;return window.CustomEvent&&"function"==typeof window.CustomEvent?b=new CustomEvent(a):(b=document.createEvent("CustomEvent"),b.initCustomEvent(a,!1,!1,void 0)),b},d=function(a){return a.getAttribute("data-sort")||a.textContent||a.innerText||""},e=function(a,b){return a=a.toLowerCase(),b=b.toLowerCase(),a===b?0:b>a?1:-1},f=function(a,b){return function(c,d){var e=a(c.td,d.td);return 0===e?b?d.index-c.index:c.index-d.index:e}};a.extend=function(a,c,d){if("function"!=typeof c||"function"!=typeof d)throw new Error("Pattern and sort must be a function");b.push({name:a,pattern:c,sort:d})},a.prototype={init:function(a,b){var c,d,e,f,g=this;if(g.table=a,g.thead=!1,g.options=b,a.rows&&a.rows.length>0&&(a.tHead&&a.tHead.rows.length>0?(c=a.tHead.rows[a.tHead.rows.length-1],g.thead=!0):c=a.rows[0]),c){var h=function(){g.current&&g.current!==this&&(g.current.classList.remove("sort-up"),g.current.classList.remove("sort-down")),g.current=this,g.sortTable(this)};for(e=0;e<c.cells.length;e++)f=c.cells[e],f.classList.contains("no-sort")||(f.classList.add("sort-header"),f.addEventListener("click",h,!1),f.classList.contains("sort-default")&&(d=f));d&&(g.current=d,g.sortTable(d))}},sortTable:function(a,g){var h=this,i=a.cellIndex,j=e,k="",l=[],m=h.thead?0:1,n=a.getAttribute("data-sort-method");if(h.table.dispatchEvent(c("beforeSort")),!(h.table.rows.length<2)){if(!n){for(;l.length<3&&m<h.table.tBodies[0].rows.length;)k=d(h.table.tBodies[0].rows[m].cells[i]),k=k.trim(),k.length>0&&(l.push(k),m++);if(!l)return}for(m=0;m<b.length;m++)if(k=b[m],n){if(k.name===n){j=k.sort;break}}else if(l.every(k.pattern)){j=k.sort;break}h.col=i;var o,p,q=[],r={},s=0,t=0;for(m=0;m<h.table.tBodies.length;m++)for(o=0;o<h.table.tBodies[m].rows.length;o++)k=h.table.tBodies[m].rows[o],k.classList.contains("no-sort")?r[s]=k:q.push({tr:k,td:d(k.cells[h.col]),index:s}),s++;for(g?p=a.classList.contains("sort-up")?"sort-up":"sort-down":(p=a.classList.contains("sort-up")?"sort-down":a.classList.contains("sort-down")?"sort-up":h.options.descending?"sort-up":"sort-down",a.classList.remove("sort-down"===p?"sort-up":"sort-down"),a.classList.add(p)),"sort-down"===p?(q.sort(f(j,!0)),q.reverse()):q.sort(f(j,!1)),m=0;s>m;m++)r[m]?(k=r[m],t++):k=q[m-t].tr,h.table.tBodies[0].appendChild(k);h.table.dispatchEvent(c("afterSort"))}},refresh:function(){void 0!==this.current&&this.sortTable(this.current,!0)}},"undefined"!=typeof module&&module.exports?module.exports=a:window.Tablesort=a}(); |
@@ -6,23 +6,23 @@ var page = require('webpage').create(); | ||
page.onConsoleMessage = function(msg) { | ||
system.stdout.writeLine(msg); | ||
if (msg.indexOf('# ok') === 0) { | ||
phantom.exit(0); | ||
} else if (msg.indexOf('# fail') === 0) { | ||
phantom.exit(1); | ||
} | ||
system.stdout.writeLine(msg); | ||
if (msg.indexOf('# ok') === 0) { | ||
phantom.exit(0); | ||
} else if (msg.indexOf('# fail') === 0) { | ||
phantom.exit(1); | ||
} | ||
}; | ||
page.onError = function(msg) { | ||
system.stderr.writeLine(msg); | ||
phantom.exit(1); | ||
system.stderr.writeLine(msg); | ||
phantom.exit(1); | ||
}; | ||
page.open(url, function(status) { | ||
if (status !== 'success') { | ||
system.stderr.writeLine('failed to open ' + url); | ||
phantom.exit(1); | ||
} | ||
if (status !== 'success') { | ||
system.stderr.writeLine('failed to open ' + url); | ||
phantom.exit(1); | ||
} | ||
}); | ||
setTimeout(function() { | ||
phantom.exit(1); | ||
phantom.exit(1); | ||
}, 60000); | ||
@@ -12,31 +12,31 @@ #!/usr/bin/env node | ||
var staticHandler = serveStatic(path.join(__dirname, '/../'), { | ||
'index': ['index.html'] | ||
'index': ['index.html'] | ||
}); | ||
var server = http.createServer(function(req, res) { | ||
var done = finalhandler(req, res); | ||
staticHandler(req, res, done); | ||
var done = finalhandler(req, res); | ||
staticHandler(req, res, done); | ||
}); | ||
server.listen(0, function() { | ||
var port = server.address().port; | ||
var uri = url.format({ | ||
protocol: 'http', | ||
hostname: 'localhost', | ||
port: port, | ||
pathname: '/test/', | ||
}); | ||
var port = server.address().port; | ||
var uri = url.format({ | ||
protocol: 'http', | ||
hostname: 'localhost', | ||
port: port, | ||
pathname: '/test/', | ||
}); | ||
var opts = { env: { url: uri } }; | ||
var script = path.join(__dirname, 'test-phantom.js'); | ||
var exit = 0; | ||
execFile(phantombin, [script], opts, function(err, stdout, stderr) { | ||
if (err && err.code) { | ||
exit = err.code; | ||
console.error(err); | ||
console.error(err.stack); | ||
} | ||
console.log(stdout); | ||
console.warn(stderr); | ||
server.close(); | ||
process.exit(exit); | ||
}); | ||
var opts = { env: { url: uri } }; | ||
var script = path.join(__dirname, 'test-phantom.js'); | ||
var exit = 0; | ||
execFile(phantombin, [script], opts, function(err, stdout, stderr) { | ||
if (err && err.code) { | ||
exit = err.code; | ||
console.error(err); | ||
console.error(err.stack); | ||
} | ||
console.log(stdout); | ||
console.warn(stderr); | ||
server.close(); | ||
process.exit(exit); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
260212
28
6764
222