1/*! TinySort 1.5.3 2* Copyright (c) 2008-2013 Ron Valstar http://tinysort.sjeiti.com/ 3* 4* Dual licensed under the MIT and GPL licenses: 5* http://www.opensource.org/licenses/mit-license.php 6* http://www.gnu.org/licenses/gpl.html 7*//* 8* Description: 9* A jQuery plugin to sort child nodes by (sub) contents or attributes. 10* 11* Contributors: 12* [email protected] 13* [email protected] 14* 15* Usage: 16* $("ul#people>li").tsort(); 17* $("ul#people>li").tsort("span.surname"); 18* $("ul#people>li").tsort("span.surname",{order:"desc"}); 19* $("ul#people>li").tsort({place:"end"}); 20* $("ul#people>li").tsort("span.surname",{order:"desc"},span.name"); 21* 22* Change default like so: 23* $.tinysort.defaults.order = "desc"; 24* 25*/ 26;(function($,undefined) { 27 // private vars 28 var fls = !1 // minify placeholder 29 ,nll = null // minify placeholder 30 ,prsflt = parseFloat // minify placeholder 31 ,mathmn = Math.min // minify placeholder 32 ,rxLastNr = /(-?\d+\.?\d*)$/g // regex for testing strings ending on numbers 33 ,rxLastNrNoDash = /(\d+\.?\d*)$/g // regex for testing strings ending on numbers ignoring dashes 34 ,aPluginPrepare = [] 35 ,aPluginSort = [] 36 ,isString = function(o){return typeof o=='string';} 37 // Array.prototype.indexOf for IE (issue #26) (local variable to prevent unwanted prototype pollution) 38 ,fnIndexOf = Array.prototype.indexOf||function(elm) { 39 var len = this.length 40 ,from = Number(arguments[1])||0; 41 from = from<0?Math.ceil(from):Math.floor(from); 42 if (from<0) from += len; 43 for (;from<len;from++){ 44 if (from in this && this[from]===elm) return from; 45 } 46 return -1; 47 } 48 ; 49 // 50 // init plugin 51 $.tinysort = { 52 id: 'TinySort' 53 ,version: '1.5.2' 54 ,copyright: 'Copyright (c) 2008-2013 Ron Valstar' 55 ,uri: 'http://tinysort.sjeiti.com/' 56 ,licensed: { 57 MIT: 'http://www.opensource.org/licenses/mit-license.php' 58 ,GPL: 'http://www.gnu.org/licenses/gpl.html' 59 } 60 ,plugin: (function(){ 61 var fn = function(prepare,sort){ 62 aPluginPrepare.push(prepare); // function(settings){doStuff();} 63 aPluginSort.push(sort); // function(valuesAreNumeric,sA,sB,iReturn){doStuff();return iReturn;} 64 }; 65 // expose stuff to plugins 66 fn.indexOf = fnIndexOf; 67 return fn; 68 })() 69 ,defaults: { // default settings 70 71 order: 'asc' // order: asc, desc or rand 72 73 ,attr: nll // order by attribute value 74 ,data: nll // use the data attribute for sorting 75 ,useVal: fls // use element value instead of text 76 77 ,place: 'start' // place ordered elements at position: start, end, org (original position), first 78 ,returns: fls // return all elements or only the sorted ones (true/false) 79 80 ,cases: fls // a case sensitive sort orders [aB,aa,ab,bb] 81 ,forceStrings:fls // if false the string '2' will sort with the value 2, not the string '2' 82 83 ,ignoreDashes:fls // ignores dashes when looking for numerals 84 85 ,sortFunction: nll // override the default sort function 86 } 87 }; 88 $.fn.extend({ 89 tinysort: function() { 90 var i,l 91 ,oThis = this 92 ,aNewOrder = [] 93 // sortable- and non-sortable list per parent 94 ,aElements = [] 95 ,aElementsParent = [] // index reference for parent to aElements 96 // multiple sort criteria (sort===0?iCriteria++:iCriteria=0) 97 ,aCriteria = [] 98 ,iCriteria = 0 99 ,iCriteriaMax 100 // 101 ,aFind = [] 102 ,aSettings = [] 103 // 104 ,fnPluginPrepare = function(_settings){ 105 $.each(aPluginPrepare,function(i,fn){ 106 fn.call(fn,_settings); 107 }); 108 } 109 // 110 ,fnSort = function(a,b) { 111 var iReturn = 0; 112 if (iCriteria!==0) iCriteria = 0; 113 while (iReturn===0&&iCriteria<iCriteriaMax) { 114 var oPoint = aCriteria[iCriteria] 115 ,oSett = oPoint.oSettings 116 ,rxLast = oSett.ignoreDashes?rxLastNrNoDash:rxLastNr 117 ; 118 // 119 fnPluginPrepare(oSett); 120 // 121 if (oSett.sortFunction) { // custom sort 122 iReturn = oSett.sortFunction(a,b); 123 } else if (oSett.order=='rand') { // random sort 124 iReturn = Math.random()<.5?1:-1; 125 } else { // regular sort 126 var bNumeric = fls 127 // maybe toLower 128 ,sA = !oSett.cases?toLowerCase(a.s[iCriteria]):a.s[iCriteria] 129 ,sB = !oSett.cases?toLowerCase(b.s[iCriteria]):b.s[iCriteria]; 130 // maybe force Strings 131 if (!oSettings.forceStrings) { 132 // maybe mixed 133 var aAnum = isString(sA)?sA&&sA.match(rxLast):fls 134 ,aBnum = isString(sB)?sB&&sB.match(rxLast):fls; 135 if (aAnum&&aBnum) { 136 var sAprv = sA.substr(0,sA.length-aAnum[0].length) 137 ,sBprv = sB.substr(0,sB.length-aBnum[0].length); 138 if (sAprv==sBprv) { 139 bNumeric = !fls; 140 sA = prsflt(aAnum[0]); 141 sB = prsflt(aBnum[0]); 142 } 143 } 144 } 145 iReturn = oPoint.iAsc*(sA<sB?-1:(sA>sB?1:0)); 146 } 147 148 $.each(aPluginSort,function(i,fn){ 149 iReturn = fn.call(fn,bNumeric,sA,sB,iReturn); 150 }); 151 152 if (iReturn===0) iCriteria++; 153 } 154 155 return iReturn; 156 } 157 ; 158 // fill aFind and aSettings but keep length pairing up 159 for (i=0,l=arguments.length;i<l;i++){ 160 var o = arguments[i]; 161 if (isString(o)) { 162 if (aFind.push(o)-1>aSettings.length) aSettings.length = aFind.length-1; 163 } else { 164 if (aSettings.push(o)>aFind.length) aFind.length = aSettings.length; 165 } 166 }
167 if (aFind.length>aSettings.length) aSettings.length = aFind.length; // todo: and other way around? 168 169 // fill aFind and aSettings for arguments.length===0 170 iCriteriaMax = aFind.length; 171 if (iCriteriaMax===0) { 172 iCriteriaMax = aFind.length = 1; 173 aSettings.push({}); 174 } 175 176 for (i=0,l=iCriteriaMax;i<l;i++) { 177 var sFind = aFind[i] 178 ,oSettings = $.extend({}, $.tinysort. defaults, aSettings[i]) 179 // has find, attr or data 180 ,bFind = !(!sFind||sFind=='') 181 // since jQuery's filter within each works on array index and not actual index we have to create the filter in advance 182 ,bFilter = bFind&&sFind[0]==':' 183 ; 184 aCriteria.push({ // todo: only used locally, find a way to minify properties 185 sFind: sFind 186 ,oSettings: oSettings 187 // has find, attr or data 188 ,bFind: bFind 189 ,bAttr: !(oSettings.attr===nll||oSettings.attr=='') 190 ,bData: oSettings.data!==nll 191 // filter 192 ,bFilter: bFilter 193 ,$Filter: bFilter?oThis.filter(sFind):oThis 194 ,fnSort: oSettings.sortFunction 195 ,iAsc: oSettings.order=='asc'?1:-1 196 }); 197 } 198 // 199 // prepare oElements for sorting 200 oThis.each(function(i,el) { 201 var $Elm = $(el) 202 ,mParent = $Elm.parent().get(0) 203 ,mFirstElmOrSub // we still need to distinguish between sortable and non-sortable elements (might have unexpected results for multiple criteria) 204 ,aSort = [] 205 ; 206 for (j=0;j<iCriteriaMax;j++) { 207 var oPoint = aCriteria[j] 208 // element or sub selection 209 ,mElmOrSub = oPoint.bFind?(oPoint.bFilter?oPoint.$Filter.filter(el):$Elm.find(oPoint.sFind)):$Elm; 210 // text or attribute value 211 aSort.push(oPoint.bData?mElmOrSub.data(oPoint.oSettings.data):(oPoint.bAttr?mElmOrSub.attr(oPoint.oSettings.attr):(oPoint.oSettings.useVal?mElmOrSub.val():mElmOrSub.text()))); 212 if (mFirstElmOrSub===undefined) mFirstElmOrSub = mElmOrSub; 213 } 214 // to sort or not to sort 215 var iElmIndex = fnIndexOf.call(aElementsParent,mParent); 216 if (iElmIndex<0) { 217 iElmIndex = aElementsParent.push(mParent) - 1; 218 aElements[iElmIndex] = {s:[],n:[]}; // s: sort, n: not sort 219 } 220 if (mFirstElmOrSub.length>0) aElements[iElmIndex].s.push({s:aSort,e:$Elm,n:i}); // s:string/pointer, e:element, n:number 221 else aElements[iElmIndex].n.push({e:$Elm,n:i}); 222 }); 223 // 224 // sort 225 $.each(aElements, function(j,oParent) { oParent.s.sort(fnSort); }); 226 // 227 // order elements and fill new order 228 $.each(aElements, function(j,oParent) { 229// var oParent = aElements[j] 230 var iNumElm = oParent.s.length 231 ,aOrg = [] // list for original position 232 ,iLow = iNumElm 233 ,aCnt = [0,0] // count how much we've sorted for retreival from either the sort list or the non-sort list (oParent.s/oParent.n) 234 ; 235 switch (oSettings.place) { 236 case 'first': $.each(oParent.s,function(i,obj) { iLow = mathmn(iLow,obj.n) }); break; 237 case 'org': $.each(oParent.s,function(i,obj) { aOrg.push(obj.n) }); break; 238 case 'end': iLow = oParent.n.length; break; 239 default: iLow = 0; 240 } 241 for (i=0;i<iNumElm;i++) { 242 var bSList = contains(aOrg,i)?!fls:i>=iLow&&i<iLow+oParent.s.length 243 ,mEl = (bSList?oParent.s:oParent.n)[aCnt[bSList?0:1]].e; 244 mEl.parent().append(mEl); 245 if (bSList||!oSettings.returns) aNewOrder.push(mEl.get(0)); 246 aCnt[bSList?0:1]++; 247 } 248 }); 249 oThis.length = 0; 250 Array.prototype.push.apply(oThis,aNewOrder); 251 return oThis; 252 } 253 }); 254 // toLowerCase 255 function toLowerCase(s) { 256 return s&&s.toLowerCase?s.toLowerCase():s; 257 } 258 // array contains 259 function contains(a,n) { 260 for (var i=0,l=a.length;i<l;i++) if (a[i]==n) return !fls; 261 return fls; 262 } 263 // set functions 264 $.fn.TinySort = $.fn.Tinysort = $.fn.tsort = $.fn.tinysort; 265})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.