TinySort is a small script that sorts HTMLElements. It sorts by text- or attribute value, or by that of one of it's children. The examples below should help getting you on your way.
If you find a bug, have a feature request or a code improvement you can file them here. Please provide code examples where applicable.
TinySort used to be a jQuery plugin but was rewritten to remove the jQuery dependency. It is now smaller *and* faster (and has no dependencies). Functionality is the same but changes have been made to the parameters and options.
The first (and only required) argument is a NodeList, an array of HTMLElements or a string (which is converted to a NodeList using document.querySelectorAll).
tinysort(NodeList);
The other arguments can be an an options object.
tinysort(NodeList,{place:'end'});
If the option object only contains a selector
you can suffice by using the selector string instead of the object.
tinysort(NodeList,'span.surname');
For multiple criteria you can just overload.
tinysort(NodeList,'span.surname','span.name',{data:'age'});
Default settings can be changed
tinysort.defaults.order = 'desc';
tinysort.defaults.attr = 'title';
The options object can have the following settings:
options.selector (String) A CSS selector to select the element to sort to.
options.order (String='asc') The order of the sorting method. Possible values are 'asc', 'desc' and 'rand'.
options.attr (String=null) Order by attribute value (ie title, href, class)
options.data (String=null) Use the data attribute for sorting.
options.place (String='org') Determines the placement of the ordered elements in respect to the unordered elements. Possible values 'start', 'end', 'first', 'last' or 'org'.
options.useVal (Boolean=false) Use element value instead of text.
options.cases (Boolean=false) A case sensitive sort (orders [aB,aa,ab,bb])
options.natural (Boolean=false) Use natural sort order.
options.forceStrings (Boolean=false) If false the string '2' will sort with the value 2, not the string '2'.
options.ignoreDashes (Boolean=false) Ignores dashes when looking for numerals.
options.sortFunction (function=null) Override the default sort function. The parameters are of a type {elementObject}.
options.useFlex (Boolean=true) If one parent and display flex, ordering is done by CSS (instead of DOM)
options.emptyEnd (Boolean=true) Sort empty values to the end instead of the start
The default sort simply sorts the text of each element
tinysort('ul#xdflt>li');
TinySort works on any nodeType. The following is a div with spans.
tinysort('div#xany>span');
TinySort also works on numbers.
tinysort('ul#xnum>li');
In a normal sort the order would be a1,a11,a2 while you'd really want it to be a1,a2,a11. TinySort corrects this:
tinysort('ul#xmix>li');
Sort by attribute value by adding the 'attr' option. This will sort by attribute of, either the selection, or of the sub-selection (if provided). In this case sort is by href on the anchor sub-selection.
tinysort('ul#xval>li',{selector:'a',attr:'href'});
Another example: images sorted by attribute title value.
tinysort('div#ximg>img',{attr:'title'});
You can provide an additional subselection by setting the selector
option. If no other options are set you can also just pass the selector string instead of the options object.
In this example the list elements are sorted to the text of the second span.
tinysort('ul#xsub>li','span:nth-child(2)');
The following example will only sort the non-striked elements.
tinysort('ul#xattr>li','span:not([class=striked])');
By default, all the elements are returned, even the ones excluded by your sub-selection. By parsing the additional parameter 'returns=true' only the sorted elements are returned. You can also adjust the placement of the sorted values by adding the 'place' attribute. In this case the original positions are maintained.
tinysort('ul#xret>li','span:not([class=striked])',{returns:true,place:'org'})
.forEach(function(elm){
elm.style.color = 'red';
})
;
Sometimes multiple sorting criteria are required. For instance: you might want to sort a list of people first by surname then by name.
For multiple sorting rules you can just overload the parameters. So tinysort(selector,options) becomes tsort(selector,options1,options2,options3...). Note that in the next example the second parameter 'span.name'
will be rewritten internally to {selector:'span.name'}
.
tinysort('ul#xmul>li','span.name',{selector:'span.date',data:'timestamp'});
A normal array sorts according to Unicode, which is wrong for most languages. For correct ordering you can use the charorder plugin to parse a rule with the 'charOrder' parameter. This is a string that consist of exceptions, not the entire alfabet. For characters that should sort equally use brackets. For characters that consist of multiple characters use curly braces. For example:
-
cčć sorts c č and ć in that order
-
æøå in absence of a latin character æ ø and å are sorted after z
-
ι[ίϊΐ] ί ϊ and ΐ are sorted equally to ι
-
d{dž} dž is sorted as one character after d
-
å[{Aa}] Aa is sorted as one character, equal to å, after z
Here some real examples:
tinysort('ul#greek>li',{charOrder:'α[ά]βγδε[έ]ζη[ή]θι[ίϊΐ]κλμνξο[ό]πρστυ[ύϋΰ]φχψω[ώ]'});
tinysort('ul#danish>li',{charOrder:'æøå[{Aa}]'});
tinysort('ul#serb>li',{charOrder:'cčćd{dž}đl{lj}n{nj}sšzž'});
Here are some example languages:
Language | charOrder |
---|---|
since only one of these is my native language please feel free to contact me if you think corrections are in order | |
Cyrilic | абвгдђежзијклљмнњопрстћуфхцчџш |
Czech | a[á]cčd[ď]e[éě]h{ch}i[í]n[ň]o[ó]rřsšt[ť]u[úů]y[ý]zž |
Danish and Norwegian | æøå[{Aa}] |
Dutch | a[áàâä]c[ç]e[éèêë]i[íìîï]o[óòôö]u[úùûü] |
French | a[àâ]c[ç]e[éèêë]i[ïî]o[ôœ]u[ûù] |
German | a[ä]o[ö]s{ss}u[ü] |
Greek | α[ά]βγδε[έ]ζη[ή]θι[ίϊΐ]κλμνξο[ό]πρστυ[ύϋΰ]φχψω[ώ] |
Icelandic | a[á]dðe[é]i[í]o[ó]u[ú]y[ý]zþæö |
Polish | aąbcćeęlłnńoósśuúzźż |
Russian | абвгдеёжзийклмнопрстуфхцчшщъыьэюя |
Serbo-Croatian | cčćd{dž}đl{lj}n{nj}sšzž |
Spanish | a[á]c{ch}e[é]i[í]l{ll}nño[ó]u[ú]y[ý] |
Swedish | åäö |
Machines read differently than you do. Natural sorting makes your machine more like you by enabling it to differentiate between numeric values within a string.
tinysort('ul#xnat>li',{natural:true});
The value property is primarily used to get the values of form elements, but list-elements also have the value property. By setting the useVal option you can also sort by this form element value.
tinysort('ul#xinp>li',{selector:'input',useVal:true});
Sort by data attribute by setting the data
option.
tinysort('ul#xdta>li',{selector:'a',data:'foo'});
Sort in ascending or descending order by setting the order
option to asc
or desc
.
tinysort('ul#xdesc>li',{order:'desc'});
TinySort can also order randomly (or is that a contradiction).
tinysort('ul#xrnd>li',{order:'rand'});
Custom sort functions are similar to those you use with regular Javascript arrays with the exception that the parameters a and b are objects of a similar type {elementObject}, an object with the following properties:
- elm {HTMLElement}: The element
- pos {number}: original position
- posn {number}: original position on the partial list
tinysort('ul#xcst>li',{sortFunction:function(a,b){
var lenA = a.elm.textContent.length
,lenB = b.elm.textContent.length;
return lenA===lenB?0:(lenA>lenB?1:-1);
}});
With a little extra code you can create a sortable table:
var table = document.getElementById('xtable')
,tableHead = table.querySelector('thead')
,tableHeaders = tableHead.querySelectorAll('th')
,tableBody = table.querySelector('tbody')
;
tableHead.addEventListener('click',function(e){
var tableHeader = e.target
,textContent = tableHeader.textContent
,tableHeaderIndex,isAscending,order
;
if (textContent!=='add row') {
while (tableHeader.nodeName!=='TH') {
tableHeader = tableHeader.parentNode;
}
tableHeaderIndex = Array.prototype.indexOf.call(tableHeaders,tableHeader);
isAscending = tableHeader.getAttribute('data-order')==='asc';
order = isAscending?'desc':'asc';
tableHeader.setAttribute('data-order',order);
tinysort(
tableBody.querySelectorAll('tr')
,{
selector:'td:nth-child('+(tableHeaderIndex+1)+')'
,order: order
}
);
}
});
word | int | float | mixed | add row |
---|
Tinysort has no built in animating features but it can quite easily be accomplished through regular js/jQuery.
<style type="text/css"> ul#xanim { position: relative; display: block; } ul#xanim li { transition: top 500ms; -webkit-transition: top 500ms; } </style>var ul = document.getElementById('xanim')
,lis = ul.querySelectorAll('li')
,liHeight = lis[0].offsetHeight
;
ul.style.height = ul.offsetHeight+'px';
for (var i= 0,l=lis.length;i<l;i++) {
var li = lis[i];
li.style.position = 'absolute';
li.style.top = i*liHeight+'px';
}
tinysort('ul#xanim>li').forEach(function(elm,i){
setTimeout((function(elm,i){
elm.style.top = i*liHeight+'px';
}).bind(null,elm,i),40);
});