A jQuery plugin to sort child nodes by (sub) contents or attributes.
Script này sẽ không được không được cài đặt trực tiếp. Nó là một thư viện cho các script khác để bao gồm các chỉ thị meta
// @require https://update.greasyfork.org/scripts/6883/27466/TinySorttsort.js
/*! TinySort.tsort * Copyright (c) 2008-2013 Ron Valstar http://tinysort.sjeiti.com/ * * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html *//* * Description: * A jQuery plugin to sort child nodes by (sub) contents or attributes. * * Contributors: * [email protected] * [email protected] * * Usage: * $("ul#people>li").tsort(); * $("ul#people>li").tsort("span.surname"); * $("ul#people>li").tsort("span.surname",{order:"desc"}); * $("ul#people>li").tsort({place:"end"}); * $("ul#people>li").tsort("span.surname",{order:"desc"},span.name"); * * Change default like so: * $.tinysort.defaults.order = "desc"; * */ ;(function($,undefined) { 'use strict'; // private vars var fls = !1 // minify placeholder ,nll = null // minify placeholder ,prsflt = parseFloat // minify placeholder ,mathmn = Math.min // minify placeholder ,rxLastNr = /(-?\d+\.?\d*)$/g // regex for testing strings ending on numbers ,rxLastNrNoDash = /(\d+\.?\d*)$/g // regex for testing strings ending on numbers ignoring dashes ,aPluginPrepare = [] ,aPluginSort = [] ,isString = function(o){return typeof o=='string';} ,loop = function(array,func){ var l = array.length ,i = l ,j; while (i--) { j = l-i-1; func(array[j],j); } } // Array.prototype.indexOf for IE (issue #26) (local variable to prevent unwanted prototype pollution) ,fnIndexOf = Array.prototype.indexOf||function(elm) { var len = this.length ,from = Number(arguments[1])||0; from = from<0?Math.ceil(from):Math.floor(from); if (from<0) from += len; for (;from<len;from++){ if (from in this && this[from]===elm) return from; } return -1; } ; // // init plugin $.tinysort = { id: 'TinySort' ,version: '1.5.6' ,copyright: 'Copyright (c) 2008-2013 Ron Valstar' ,uri: 'http://tinysort.sjeiti.com/' ,licensed: { MIT: 'http://www.opensource.org/licenses/mit-license.php' ,GPL: 'http://www.gnu.org/licenses/gpl.html' } ,plugin: (function(){ var fn = function(prepare,sort){ aPluginPrepare.push(prepare); // function(settings){doStuff();} aPluginSort.push(sort); // function(valuesAreNumeric,sA,sB,iReturn){doStuff();return iReturn;} }; // expose stuff to plugins fn.indexOf = fnIndexOf; return fn; })() ,defaults: { // default settings order: 'asc' // order: asc, desc or rand ,attr: nll // order by attribute value ,data: nll // use the data attribute for sorting ,useVal: fls // use element value instead of text ,place: 'start' // place ordered elements at position: start, end, org (original position), first ,returns: fls // return all elements or only the sorted ones (true/false) ,cases: fls // a case sensitive sort orders [aB,aa,ab,bb] ,forceStrings:fls // if false the string '2' will sort with the value 2, not the string '2' ,ignoreDashes:fls // ignores dashes when looking for numerals ,sortFunction: nll // override the default sort function } }; $.fn.extend({ tinysort: function() { var i,j,l ,oThis = this ,aNewOrder = [] // sortable- and non-sortable list per parent ,aElements = [] ,aElementsParent = [] // index reference for parent to aElements // multiple sort criteria (sort===0?iCriteria++:iCriteria=0) ,aCriteria = [] ,iCriteria = 0 ,iCriteriaMax // ,aFind = [] ,aSettings = [] // ,fnPluginPrepare = function(_settings){ loop(aPluginPrepare,function(fn){ fn.call(fn,_settings); }); } // ,fnPrepareSortElement = function(settings,element){ if (typeof element=='string') { // if !settings.cases if (!settings.cases) element = toLowerCase(element); element = element.replace(/^\s*(.*?)\s*$/i, '$1'); } return element; } // ,fnSort = function(a,b) { var iReturn = 0; if (iCriteria!==0) iCriteria = 0; while (iReturn===0&&iCriteria<iCriteriaMax) { var oPoint = aCriteria[iCriteria] ,oSett = oPoint.oSettings ,rxLast = oSett.ignoreDashes?rxLastNrNoDash:rxLastNr ; // fnPluginPrepare(oSett); // if (oSett.sortFunction) { // custom sort iReturn = oSett.sortFunction(a,b); } else if (oSett.order=='rand') { // random sort iReturn = Math.random()<0.5?1:-1; } else { // regular sort var bNumeric = fls // prepare sort elements ,sA = fnPrepareSortElement(oSett,a.s[iCriteria]) ,sB = fnPrepareSortElement(oSett,b.s[iCriteria]) ; // maybe force Strings if (!oSett.forceStrings) { // maybe mixed var aAnum = isString(sA)?sA&&sA.match(rxLast):fls ,aBnum = isString(sB)?sB&&sB.match(rxLast):fls; if (aAnum&&aBnum) { var sAprv = sA.substr(0,sA.length-aAnum[0].length) ,sBprv = sB.substr(0,sB.length-aBnum[0].length); if (sAprv==sBprv) { bNumeric = !fls; sA = prsflt(aAnum[0]); sB = prsflt(aBnum[0]); } } } iReturn = oPoint.iAsc*(sA<sB?-1:(sA>sB?1:0)); } loop(aPluginSort,function(fn){ iReturn = fn.call(fn,bNumeric,sA,sB,iReturn); }); if (iReturn===0) iCriteria++; } return iReturn; } ; // fill aFind and aSettings but keep length pairing up for (i=0,l=arguments.length;i<l;i++){ var o = arguments[i]; if (isString(o)) { if (aFind.push(o)-1>aSettings.length) aSettings.length = aFind.length-1; } else { if (aSettings.push(o)>aFind.length) aFind.length = aSettings.length; } } if (aFind.length>aSettings.length) aSettings.length = aFind.length; // todo: and other way around? // fill aFind and aSettings for arguments.length===0 iCriteriaMax = aFind.length; if (iCriteriaMax===0) { iCriteriaMax = aFind.length = 1; aSettings.push({}); } for (i=0,l=iCriteriaMax;i<l;i++) { var sFind = aFind[i] ,oSettings = $.extend({}, $.tinysort.defaults, aSettings[i]) // has find, attr or data ,bFind = !(!sFind||sFind==='') // since jQuery's filter within each works on array index and not actual index we have to create the filter in advance ,bFilter = bFind&&sFind[0]===':' ; aCriteria.push({ // todo: only used locally, find a way to minify properties sFind: sFind ,oSettings: oSettings // has find, attr or data ,bFind: bFind ,bAttr: !(oSettings.attr===nll||oSettings.attr==='') ,bData: oSettings.data!==nll // filter ,bFilter: bFilter ,$Filter: bFilter?oThis.filter(sFind):oThis ,fnSort: oSettings.sortFunction ,iAsc: oSettings.order=='asc'?1:-1 }); } // // prepare oElements for sorting oThis.each(function(i,el) { var $Elm = $(el) ,mParent = $Elm.parent().get(0) ,mFirstElmOrSub // we still need to distinguish between sortable and non-sortable elements (might have unexpected results for multiple criteria) ,aSort = [] ; for (j=0;j<iCriteriaMax;j++) { var oPoint = aCriteria[j] // element or sub selection ,mElmOrSub = oPoint.bFind?(oPoint.bFilter?oPoint.$Filter.filter(el):$Elm.find(oPoint.sFind)):$Elm; // text or attribute value aSort.push(oPoint.bData?mElmOrSub.data(oPoint.oSettings.data):(oPoint.bAttr?mElmOrSub.attr(oPoint.oSettings.attr):(oPoint.oSettings.useVal?mElmOrSub.val():mElmOrSub.text()))); if (mFirstElmOrSub===undefined) mFirstElmOrSub = mElmOrSub; } // to sort or not to sort var iElmIndex = fnIndexOf.call(aElementsParent,mParent); if (iElmIndex<0) { iElmIndex = aElementsParent.push(mParent) - 1; aElements[iElmIndex] = {s:[],n:[]}; // s: sort, n: not sort } if (mFirstElmOrSub.length>0) aElements[iElmIndex].s.push({s:aSort,e:$Elm,n:i}); // s:string/pointer, e:element, n:number else aElements[iElmIndex].n.push({e:$Elm,n:i}); }); // // sort loop(aElements, function(oParent) { oParent.s.sort(fnSort); }); // // order elements and fill new order loop(aElements, function(oParent) { var aSorted = oParent.s ,aUnsorted = oParent.n ,iSorted = aSorted.length ,iUnsorted = aUnsorted.length ,iNumElm = iSorted+iUnsorted ,aOriginal = [] // list for original position ,iLow = iNumElm ,aCount = [0,0] // count how much we've sorted for retrieval from either the sort list or the non-sort list (oParent.s/oParent.n) ; switch (oSettings.place) { case 'first': loop(aSorted,function(obj) { iLow = mathmn(iLow,obj.n); }); break; case 'org': loop(aSorted,function(obj) { aOriginal.push(obj.n); }); break; case 'end': iLow = iUnsorted; break; default: iLow = 0; } for (i=0;i<iNumElm;i++) { var bFromSortList = contains(aOriginal,i)?!fls:i>=iLow&&i<iLow+iSorted ,iCountIndex = bFromSortList?0:1 ,mEl = (bFromSortList?aSorted:aUnsorted)[aCount[iCountIndex]].e; mEl.parent().append(mEl); if (bFromSortList||!oSettings.returns) aNewOrder.push(mEl.get(0)); aCount[iCountIndex]++; } }); oThis.length = 0; Array.prototype.push.apply(oThis,aNewOrder); return oThis; } }); // toLowerCase // todo: dismantle, used only once function toLowerCase(s) { return s&&s.toLowerCase?s.toLowerCase():s; } // array contains function contains(a,n) { for (var i=0,l=a.length;i<l;i++) if (a[i]==n) return !fls; return fls; } // set functions $.fn.TinySort = $.fn.Tinysort = $.fn.tsort = $.fn.tinysort; })(jQuery);