Clean sort code.

This commit is contained in:
Lars Jung 2016-07-01 19:26:17 +02:00
parent 73e74bb887
commit 8485905901
4 changed files with 51 additions and 78 deletions

View file

@ -345,7 +345,7 @@
"column": 0,
"reverse": false,
"ignorecase": true,
"natural": false,
"natural": true,
"folders": 0
},
@ -390,7 +390,7 @@
"enabled": true,
"show": true,
"maxSubfolders": 50,
"naturalSort": false,
"naturalSort": true,
"ignorecase": true
}
}

View file

@ -13,51 +13,25 @@ const settings = Object.assign({
folders: 0
}, allsettings.sort);
const storekey = 'ext/sort';
const template = '<img src="' + resource.image('sort') + '" class="sort" alt="sort order"/>';
const template = `<img src="${resource.image('sort')}" class="sort" alt="sort order"/>`;
const getTypeOrder = item => item.isFolder() ? settings.folders : 1;
const columnProps = {0: 'label', 1: 'time', 2: 'size'};
const columnClasses = {0: 'label', 1: 'date', 2: 'size'};
const getType = item => {
const $item = dom(item);
const cmpFn = (prop, reverse, ignorecase, natural) => {
return (el1, el2) => {
const item1 = el1._item;
const item2 = el2._item;
if ($item.hasCls('folder-parent')) {
return 0;
}
if ($item.hasCls('folder')) {
if (settings.folders === 1) {
return 2;
} else if (settings.folders === 2) {
return 3;
}
return 1;
}
return 2;
};
const columnGetters = {
0: el => el._item.label,
1: el => el._item.time,
2: el => el._item.size
};
const columnClasses = {
0: 'label',
1: 'date',
2: 'size'
};
const cmpFn = (getValue, reverse, ignorecase, natural) => {
return (item1, item2) => {
let res;
let val1;
let val2;
res = getType(item1) - getType(item2);
let res = getTypeOrder(item1) - getTypeOrder(item2);
if (res !== 0) {
return res;
}
val1 = getValue(item1);
val2 = getValue(item2);
let val1 = item1[prop];
let val2 = item2[prop];
if (isNaN(val1) || isNaN(val2)) {
val1 = String(val1);
@ -77,14 +51,14 @@ const cmpFn = (getValue, reverse, ignorecase, natural) => {
const sortItems = (column, reverse) => {
const $headers = dom('#items li.header a');
const $header = dom('#items li.header a.' + columnClasses[column]);
const fn = cmpFn(columnGetters[column], reverse, settings.ignorecase, column === 0 && settings.natural);
const fn = cmpFn(columnProps[column], reverse, settings.ignorecase, settings.natural);
store.put(storekey, {column, reverse});
$headers.rmCls('ascending').rmCls('descending');
$header.addCls(reverse ? 'descending' : 'ascending');
dom(toArray(dom('#items .item')).sort(fn)).appTo('#items');
dom(toArray(dom('#items .item:not(.folder-parent)')).sort(fn)).appTo('#items');
};
const onContentChanged = () => {
@ -101,11 +75,11 @@ const addToggles = () => {
each(columnClasses, (cls, idx) => {
const pos = idx === '0' ? 'app' : 'pre';
$header
.find('a.' + cls)[pos](template)
.on('click', ev => {
sortItems(idx, dom(ev.currentTarget).hasCls('ascending'));
ev.preventDefault();
});
.find('a.' + cls)[pos](template)
.on('click', ev => {
sortItems(idx, dom(ev.currentTarget).hasCls('ascending'));
ev.preventDefault();
});
});
};

View file

@ -66,7 +66,7 @@ const cmpItems = (item1, item2) => {
val2 = val2.toLowerCase();
}
return settings.natural ? naturalCmp(val1, val2) : regularCmp(val1, val2);
return settings.naturalSort ? naturalCmp(val1, val2) : regularCmp(val1, val2);
};
const update = item => {

View file

@ -3,58 +3,57 @@
// Modified to make it work with h5ai
const re = /(^-?[0-9]+(\.?[0-9]*)[df]?e?[0-9]?$|^0x[0-9a-f]+$|[0-9]+)/gi;
const reStrip = /(^[ ]*|[ ]*$)/g;
const dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/;
const reToken = /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi;
const reDate = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/;
const reHex = /^0x[0-9a-f]+$/i;
const reLeadingZero = /^0/;
/* eslint-disable complexity */
const naturalCmp = (val1, val2) => {
const naturalCmp = (a, b) => {
// convert all to strings strip whitespace
const x = String(val1).replace(reStrip, '');
const y = String(val2).replace(reStrip, '');
// chunk/tokenize
const xN = x.replace(re, '\0$1\0').replace(/\0$/, '').replace(/^\0/, '').split('\0');
const yN = y.replace(re, '\0$1\0').replace(/\0$/, '').replace(/^\0/, '').split('\0');
// numeric, hex or date detection
const xD = parseInt(x.match(reHex), 10) || xN.length !== 1 && x.match(dre) && Date.parse(x);
const yD = parseInt(y.match(reHex), 10) || xD && y.match(dre) && Date.parse(y) || null;
const x = String(a).trim();
const y = String(b).trim();
let oFxNcL;
let oFyNcL;
// chunk/tokenize
const xTokens = x.replace(reToken, '\0$1\0').replace(/\0$/, '').replace(/^\0/, '').split('\0');
const yTokens = y.replace(reToken, '\0$1\0').replace(/\0$/, '').replace(/^\0/, '').split('\0');
// first try and sort Hex codes or Dates
if (yD) {
if (xD < yD) {
const xDate = parseInt(x.match(reHex), 16) || xTokens.length !== 1 && x.match(reDate) && Date.parse(x);
const yDate = parseInt(y.match(reHex), 16) || xDate && y.match(reDate) && Date.parse(y) || null;
if (yDate) {
if (xDate < yDate) {
return -1;
} else if (xD > yD) {
}
if (xDate > yDate) {
return 1;
}
}
// natural sorting through split numeric strings and default strings
for (let cLoc = 0, numS = Math.max(xN.length, yN.length); cLoc < numS; cLoc += 1) {
for (let idx = 0, len = Math.max(xTokens.length, yTokens.length); idx < len; idx += 1) {
// find floats not starting with '0', string or 0 if not defined (Clint Priest)
oFxNcL = !(xN[cLoc] || '').match(reLeadingZero) && parseFloat(xN[cLoc]) || xN[cLoc] || 0;
oFyNcL = !(yN[cLoc] || '').match(reLeadingZero) && parseFloat(yN[cLoc]) || yN[cLoc] || 0;
let xToken = !(xTokens[idx] || '').match(reLeadingZero) && parseFloat(xTokens[idx]) || xTokens[idx] || 0;
let yToken = !(yTokens[idx] || '').match(reLeadingZero) && parseFloat(yTokens[idx]) || yTokens[idx] || 0;
// handle numeric vs string comparison - number < string - (Kyle Adams)
if (isNaN(oFxNcL) !== isNaN(oFyNcL)) {
return isNaN(oFxNcL) ? 1 : -1;
} else if (typeof oFxNcL !== typeof oFyNcL) {
// rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
oFxNcL = String(oFxNcL);
oFxNcL = String(oFxNcL);
if (isNaN(xToken) !== isNaN(yToken)) {
return isNaN(xToken) ? 1 : -1;
}
if (oFxNcL < oFyNcL) {
// rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
if (typeof xToken !== typeof yToken) {
xToken = String(xToken);
yToken = String(yToken);
}
if (xToken < yToken) {
return -1;
}
if (oFxNcL > oFyNcL) {
if (xToken > yToken) {
return 1;
}
}
return 0;
};
/* eslint-enable */