backbone.facetr
Version:
A library to perform faceted search on Backbone collections
6 lines • 11.4 kB
JavaScript
// backbone.facetr 0.4.3
// Copyright (c)2012 Arillo GmbH
// Author: Francesco Macri
// Distributed under MIT license
// https://github.com/arillo/Backbone.Facetr
!function(a,b){if("object"==typeof exports){var c=require("underscore"),d=require("backbone");module.exports=b(c,d)}else"function"==typeof define&&define.amd?define(["underscore","backbone"],b):a.Facetr=b(_,Backbone)}(this,function(a,b,c){"use strict";b.Facetr=function(a,c){return a instanceof b.Collection?f(a,c):e(a)},b.Facetr.VERSION="0.4.3";var d={},e=function(a){var b=d[a];return b?b:c},f=function(a,b){var c=a.facetrid||b||"fctr"+(new Date).getTime()+Math.floor(99*Math.random()+1),f=e(c);return f?f:(a.facetrid=c,d[c]=new i(a),d[c])},g=function(a,d){var e,f=d.split("."),g=f.length,h=0;for(e=a.get(f[h]),h=1;g>h;h+=1){if(e===c)return e;if(e instanceof Array)return e;e=e instanceof b.Model?e.get(f[h]):"[object Object]"===Object.prototype.toString.call(e)?e[f[h]]:e}return e},h=function(d,e,f,h){a.extend(this,b.Events);var i=this,j=d,k=d,l="value",m="asc",n=[],o=[],p=[],q={},r=h,s="or",t=!1,u={},v=!1,w=[],x=[],y={},z={},A=function(d,e,f){var g=e!==c&&null!==e?e:"undefined",h=!1;if(null!=typeof g&&"object"==typeof g){var i=j.split(".")[1];g=i&&(g instanceof b.Model&&g.get(i)||g[i])||"undefined",h=!0}var k=a.find(d,function(a){return a.value===g});if(k)k.count=k.count+1,k.activeCount=k.activeCount+1;else{var l=a.sortedIndex(a.pluck(n,"value"),g);n.splice(l,0,{value:g,count:1,activeCount:1,active:!1}),q[g]=[]}return h&&q[g].push(f),g},B=function(b){var c,d=g(b,j);if(d instanceof Array)0===d.length?(c=A(n,"undefined",b.cid),q[c].push(b.cid)):a.each(d,function(a){c=A(n,a,b.cid),q[c]&&q[c].push(b.cid)});else{if(null!=d&&"object"==typeof d)throw i.remove(),new Error("Model property can only be a value (string,number,boolean) or Array of values, not an object");c=A(n,d),q[c].push(b.cid)}},C=function(b){a(b).each(function(a){B(a)})},D=function(a,b){return"value"===l?"asc"===m?(a.value>b.value)-(a.value<b.value):(a.value<b.value)-(a.value>b.value):"activeCount"===l?"asc"===m?a.activeCount<b.activeCount?-1:a.activeCount>b.activeCount?1:(a.value>b.value)-(a.value<b.value):a.activeCount<b.activeCount?1:a.activeCount>b.activeCount?-1:(a.value<b.value)-(a.value>b.value):"asc"===m?a.count<b.count?-1:a.count>b.count?1:(a.value>b.value)-(a.value<b.value):a.count<b.count?1:a.count>b.count?-1:(a.value<b.value)-(a.value>b.value)},E=function(){n.sort(D),v&&x.sort(D)},F=function(){return 0!==o.length},G=function(b){for(var c=0,d=n.length;d>c;c+=1){var e=a.intersection(q[n[c].value],b).length;0!==e?n[c].activeCount=e:n[c].activeCount=0}},H=function(a){var b=o.splice(0,o.length);n.splice(0,n.length),p.splice(0,p.length),q={},C(a);for(var c=0,d=b.length;d>c;c+=1)i.value(b[c])},I=function(a){B(a);for(var b=0,c=o.length;c>b;b+=1)i.value(o[b])},J=function(b){var c,d,e=b.cid,f=function(b){for(c=n.length-1;-1!==c;){var d=n[c];if(d.value===b){if(d.count-=1,d.activeCount-=1,0===d.count){n.splice(c,1);var e=a.indexOf(o,d.value);-1!==e&&(o.splice(e,1),t=F())}break}c-=1}};for(var h in q)q.hasOwnProperty(h)&&(c=a.indexOf(q[h],e),-1!==c&&q[h].splice(c,1));if(d=g(b,j))if(d instanceof Array)for(var i=0,k=d.length;k>i;i++)f(d[i]);else f(d);c=a.indexOf(p,e),-1!==c&&p.splice(c,1)},K=function(a){var c,d;g(new b.Model(a.changedAttributes()),j)&&(c=new b.Model(a.previousAttributes()),d=g(c,j),c.cid=a.cid,J(c),I(a))},L=function(b){var c,d;null==y[b.value]&&(y[b.value]=[]),c=[],d=function(e){e.value!==b.value&&c.push(e.value),e.groups&&a.each(e.groups,d)},d(b),y[b.value]=a.union(y[b.value],c)},M=function(b){var d=function(b,c,e){null==z[e.value]&&(z[e.value]=[]),c&&(b.push(c.value),z[e.value]=a.union(z[e.value],b)),e.groups&&a.each(e.groups,function(a){return d(b,e,a)})};d([],c,b)},N=function(b){var c,d,e,f,g;if(f=b.groups,e={value:b.value,label:b.label,active:!1,activeCount:0,count:0},g=a.find(n,function(a){return a.value===e.value}),g&&a.extend(e,g),f&&"[object Array]"===Object.prototype.toString.call(f)&&(d=f.length)>0){for(e.groups=[],c=0;d>c;c+=1)e.groups.push(N(f[c]));e.activeCount=a.reduce(e.groups,function(a,b){return a+b.activeCount},e.activeCount),e.count=a.reduce(e.groups,function(a,b){return a+b.count},e.count)}return L(e),e},O=function(){var a,b;for(x.length=0,a=0,b=w.length;b>a;a+=1)x.push(N(w[a])),M(w[a]);x.sort(D)},P=function(){this.and=function(a,b){return s="and",i.value(a,b),this},this.or=function(a,b){return s="or",i.value(a,b),this}};this.label=function(a){return k=a,this},this.asc=function(){return m="asc",E(),this},this.desc=function(){return m="desc",E(),this},this.sortByValue=function(){return l="value",E(),this},this.sortByCount=function(){return l="count",E(),this},this.sortByActiveCount=function(){return l="activeCount",E(),this},this.toJSON=function(){var a;return a={data:{name:j,hierarchical:v,label:k,extOperator:r,intOperator:s,sort:{by:l,direction:m},selected:t,customData:u},values:n},v&&(a.groupedValues=x),a},this.remove=function(a){f.off("resetCollection",G),f.off("resetOrigCollection",H),f.off("addModel",I),f.off("removeModel",J),f.off("changeModel",K),f.trigger("removeFacet",j,a)},this.value=function(b,c,d){var e,g,h,i,k,l;if(c&&(s=c),i=a.chain(n).pluck("value").indexOf(b).value(),-1!==i){if(k=n[i],k.active||(k.active=!0,o.push(k.value)),h="or"===s||0===p.length?a.union:a.intersection,p=h(p,q[b]),v&&null!=y[k.value]&&(l=y[k.value]).length>0)for(o.concat(l),e=0,g=l.length;g>e;e+=1)p=h(p,q[l[e]])}else-1===o.indexOf(b)&&(o.push(b),"and"===s&&(p=[]));return t=F(),f.trigger("value",j,b,p,d),d||this.trigger("value",b),new P(this,s)},this.removeValue=function(b,c){var d,e,g,h=a.chain(n).pluck("value").indexOf(b).value();if(-1!==h&&(d=n[h],d.active=!1),o.splice(a.indexOf(o,d&&d.value||b),1),g=a.filter(q[b],function(b){for(var c in q)if(q.hasOwnProperty(c)&&-1!==a.indexOf(o,c)&&-1!==a.indexOf(q[c],b))return!1;return!0}),p=a.difference(p,g),"and"===s){e=[];for(var i=0,k=o.length;k>i;i+=1)e=0===e.length?a.union(e,q[o[i]]):a.intersection(e,q[o[i]]);p=a.union(p,e)}if(v&&null!=z[b]){var l=a.intersection(z[b],o);l.length>0&&(p=a.union(p,q[b]))}return t=F(),f.trigger("removeValue",j,b,p,c),c||this.trigger("removeValue",b),this},this.clear=function(a){for(;o.length>0;)this.removeValue(o[0],!0);return a||this.trigger("clear"),this},this.customData=function(a,b){return b!==c?(u[a]=b,this):u[a]},this.isSelected=function(){return t},this.hierarchy=function(a){if("[object Array]"!==Object.prototype.toString.call(a))throw new Error("Facet.hierarchy: wrong settings object. Check the documentation for the right format");return w=a,v=!0,O(),f.on("resetCollection addModel removeModel changeModel",O),this.trigger("hierarchy",w),this},C(e),f.on("resetCollection",G),f.on("resetCollection",E),f.on("resetOrigCollection",H),f.on("addModel",I),f.on("removeModel",J),f.on("changeModel",K)},i=function(c){a.extend(this,b.Events);var e,f,i=this,j={},k={},l={},m=a.extend({},b.Events),n={},o="asc",p=!1,q=function(){for(var a in k)k.hasOwnProperty(a)&&delete k[a];c.each(function(a){var b=a.clone();b.cid=a.cid,k[a.cid]=b})},r=function(a,b){delete j[a],delete l[a],w(),b!==!0&&i.trigger("removeFacet",a)},s=function(a,b){var c=j[a];if(c&&c.operator===b)return c;var d=new h(a,k,m,b);return l[a]=[],{facet:d,operator:b}},t=function(a,b){l[a]=b,w()},u=function(a,b,c,d){t(a,c),d!==!0&&i.trigger("filter",a,b)},v=function(a,b,c,d){t(a,c),d!==!0&&i.trigger("unfilter",a,b)},w=function(){var b,d,e,f,g=[],h=[];for(b in k)k.hasOwnProperty(b)&&g.push(b);for(d in l)l.hasOwnProperty(d)&&j[d].facet.toJSON().data.selected&&(g="or"===j[d].operator?a.union(g,l[d]):a.intersection(g,l[d]));f=function(a){return i(k[a])};for(e in n)if(n.hasOwnProperty(e)){var i=n[e];i instanceof Function&&(g=a.filter(g,f))}g.sort();for(var o=0,q=g.length;q>o;o+=1)h.push(k[g[o]]);m.trigger("resetCollection",g),p=!0,c.reset(h),p=!1},x=function(){p||(q(),m.trigger("resetOrigCollection",k))},y=function(a){var b=a.clone();b.cid=a.cid,k[a.cid]=b,m.trigger("addModel",a)},z=function(b){delete k[b.cid],m.trigger("removeModel",b);var c=a.any(j,function(a){return a.facet.toJSON().data.selected});c||w()},A=function(b){delete k[b.cid];var c=b.clone();c.cid=b.cid,k[b.cid]=c,m.trigger("changeModel",b);var d=a.any(j,function(a){return a.facet.toJSON().data.selected});d||w()},B=function(a){c.comparator=function(a,b){var c,d,f=g(a,e),h=g(b,e);if(isNaN(f)||isNaN(h)?(c=Date.parse(f),d=Date.parse(h),(isNaN(c)||isNaN(d))&&(c=f,d=h)):(c=parseFloat(f,10),d=parseFloat(h,10)),"asc"===o){if(c&&d)return(c>d)-(d>c);if(c)return 1;if(d)return-1}else{if(c&&d)return(d>c)-(c>d);if(c)return-1;if(d)return 1}},c.sort(),a!==!0&&i.trigger("sort",e,o)};this.facet=function(a,b,c){var d=!b||"and"!==b&&"or"!==b?"and":b;return j[a]=s(a,d),w(),c!==!0&&this.trigger("facet",a),j[a].facet},this.toJSON=function(){var b,c,d,e,g=[],h=[];for(b in j)j.hasOwnProperty(b)&&(c=j[b],d=c.facet.toJSON(),d.data.operator=c.operator,f&&f instanceof Array?(e=a.indexOf(f,d.data.name),-1!==e?h[e]=d:g.push(d)):g.push(d));return h.concat(g)},this.clear=function(a){var b;for(b in j)j.hasOwnProperty(b)&&(j[b].facet.remove(),delete j[b]);var d=[];for(b in k)k.hasOwnProperty(b)&&d.push(k[b]);return c.reset(d),l={},a!==!0&&this.trigger("clear"),this},this.clearValues=function(a){var b;for(b in j)j.hasOwnProperty(b)&&j[b].facet.clear();var d=[];for(b in k)k.hasOwnProperty(b)&&d.push(k[b]);return c.reset(d),l={},a!==!0&&this.trigger("clearValues"),this},this.remove=function(){var a=c.facetrid;this.clear(!0),c.off("reset",x),c.off("add",y),c.off("remove",z),c.off("change",A),delete c.facetrid,delete d[a]},this.facetsOrder=function(a,b){return f=a,b!==!0&&this.trigger("facetsOrderChange",a),this},this.sortBy=function(a,b){return e=a,B(b),this},this.asc=function(a){return o="asc",B(a),this},this.desc=function(a){return o="desc",B(a),this},this.addFilter=function(a,b,c){return b&&a&&(n[a]=b,w(c)),this},this.removeFilter=function(a,b){return a&&(delete n[a],w(b)),this},this.clearFilters=function(a){for(var b in n)n.hasOwnProperty(b)&&delete n[b];return w(a),this},this.collection=function(){return c},this.origLength=function(){return a.size(k)},this.facets=function(){return a.pluck(j,"facet")},this.initFromSettingsJSON=function(a){var d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u;if(e=b.Facetr,d=e(c),f=a.facets,g=a.sort,null!=f)for(q=0,t=f.length;t>q;q+=1){switch(h=f[q],i=h.attr,j=h.lab,k=h.eop,l=h.iop,m=h.sort,n=h.cust,o=h.vals,p=d.facet(i,k),j&&p.label(j),m.by){case"count":p.sortByCount();break;case"activeCount":p.sortByActiveCount();break;default:p.sortByValue()}if(p[m.direction](),n)for(s in n)n.hasOwnProperty(s)&&p.customData(s,n[s]);for(r=0,u=o.length;u>r;r+=1)p.value(o[r],l)}if(null!=g){var v=g.by,w=g.dir;v&&e(c).sortBy(v),w&&e(c)[w]()}return this.trigger("initFromSettingsJSON"),this},this.settingsJSON=function(){var b,c,d,f,g;if(b={},e&&o&&(b.sort={by:e,dir:o}),0!==a.size(j)){b.facets=[];for(c in j)if(j.hasOwnProperty(c)){d=j[c].facet.toJSON(),f=a.pluck(d.values,"active"),g=[];for(var h=0,i=f.length;i>h;h+=1)f[h]&&g.push(d.values[h].value);b.facets.push({attr:d.data.name,lab:d.data.label,eop:d.data.extOperator,iop:d.data.intOperator,sort:d.data.sort,cust:d.data.customData,vals:g})}}return b},q(),m.on("removeFacet",r,this),m.on("value",u,this),m.on("removeValue clear",v,this),c.on("reset",x),c.on("add",y),c.on("remove",z),c.on("change",A)};return b.Facetr});