UNPKG

backbone.facetr

Version:

A library to perform faceted search on Backbone collections

428 lines (372 loc) 21.2 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="description" content="Backbone Facetr"> <meta name="author" content="Francesco Macri @ Arillo GmbH"> <meta name="viewport" content="width=device-width"> <title>Backbone.Facetr - Todos Example</title> <style> a { text-decoration: none } a:hover { text-decoration: underline } #TestContainer { width: 1000px; margin: 0 auto } #Facets, #Items { display: inline-block; vertical-align: top } #Facets { width: 250px } #Facets .facet .values .value .active { color: #f00 } #Facets .facet .values .value .unavailable { text-decoration: line-through; color: #000 } #Items { width: 600px; } #Items ul { height: 450px; overflow: auto } </style> </head> <body> <div id="TestContainer"> <h1>Facetr test</h1> <div> <label for="SortAttr">Sort by</label> <select id="SortAttr"> <option>Country</option> <option>Age</option> </select> <select id="SortDir"> <option>ASC</option> <option>DESC</option> </select> </div> <div> <label for="Search">Search by FirstName</label> <input id="Search" type="text" size="20" placeholder="insert regex"/> </div> <div id="Facets"> </div> <div id="Items"> <h2>Items (<span> </span> of <span> </span>)</h2> <div> <span id="ExecTime">Exec (ms): <span> </span>&nbsp;<img src=""/></span> - <span id="RenderTime">Render (ms): <span></span>&nbsp;<img src=""/></span> </div> <ul> </ul> </div> </div> <!-- templates --> <script type="text/html" id="Facets_template"> <% _.each(facets, function(facet) { %> <div class="facet" id="<%= facet.data.name %>"> <h4><%= facet.data.label %></h4> <% if(!facet.data.hierarchical){ %> <ul class="values"> <% for(var i = 0, len = facet.values.length, value = facet.values[i]; i < len; i++,value = facet.values[i]) { %> <li class="value"> <%= valueTemplate({value:value}) %> </li> <% } %> </ul> <% } else { %> <ul class="values"> <% for(var i = 0, len = facet.groupedValues.length, value = facet.groupedValues[i]; i < len; i++,value = facet.groupedValues[i]) { %> <li class="value"> <%= valueTemplate({value:value}) %> <% if(value.groups && value.groups.length > 0){ %> <ul> <% for(var j = 0, len2 = value.groups.length, v1 = value.groups[j]; j < len2; j++, v1 = value.groups[j]){ %> <li class="value"> <%= valueTemplate({value:v1}) %> <% if(v1.groups && v1.groups.length > 0) { %> <ul> <% for(var k = 0, len3 = v1.groups.length, v2 = v1.groups[k]; k < len3; k++, v2 = v1.groups[k]){ %> <li class="value"> <%= valueTemplate({value:v2}) %> </li> <% } %> </ul> <% } %> </li> <% } %> </ul> <% } %> </li> <% } %> </ul> <% } %> </div> <% }); %> </script> <script type="text/html" id="FacetValue_template"> <a href="#" class="<%= (value.active) ? 'active' : ((value.count === 0) ? 'unavailable':'available') %>"> <span data-value="<%= value.value %>"><%= value.label || value.value %></span> <span>(<%= value.activeCount %>/<%= value.count %>)</span> </a> </script> <script type="text/html" id="Item_template"> <li> <span><%= Name.FirstName+' '+Name.LastName %>, </span> <span><%= Age %>, </span> <span><%= Country %>, </span> <span><%= Profession %>,</span> <span>Hobbies: <%= Hobbies %></span> </li> </script> <!-- include custom libs --> <script src="http://code.jquery.com/jquery-latest.min.js"></script> <!-- include Backbone.Facetr dependencies --> <script src="../node_modules/underscore/underscore.js"></script> <script src="../node_modules/backbone/backbone.js"></script> <!-- include Backbone.Facetr code --> <script src="../dist/backbone.facetr.js"></script> <script> (function($, _, Backbone, undefined) { // generate dataset var dataSetSize = parseInt(location.hash.replace('#','')) || 15, items = window.items = (function(size) { var dataSet = [], i = 0, names = 'Michael,Sonny,Fredo,Tom,Connie,Vito,Carmela,Vincent,Kay'.split(','), surnames = 'Corleone,Hagen,Mancini,Adams'.split(','), countries = 'Italy,USA,Canada,UK,Ireland,New Zealand,Australia'.split(','), hobbies = 'fishing,shopping,painting,singing,drawing,playing the ukulele'.split(','), professions = 'manager,project manager,team manager,fisherman,artist,musician'.split(','), minAge = 15, maxAge = 95; while(i < size) { var item = { Name : { FirstName : names[Math.floor((Math.random()*names.length))], LastName : surnames[Math.floor((Math.random()*surnames.length))] }, Age : Math.floor((Math.random()*(maxAge-minAge))+minAge), Country : countries[Math.floor((Math.random()*countries.length))], Profession: professions[Math.floor((Math.random()*professions.length))], Hobbies : (function(){ var hbs = [], nr = Math.floor((Math.random()*5)+1), taken = []; for(var j = 0; j < nr; j++) { var hobbie = hobbies[Math.floor((Math.random()*hobbies.length))]; while(_.indexOf(taken, hobbie) !== -1) { hobbie = hobbies[Math.floor((Math.random()*hobbies.length))]; } hbs.push(hobbie); taken.push(hobbie); }; return hbs; }()) }; dataSet.push(item); i++; }; return dataSet; }(dataSetSize)); $('#Items h2 span').html(dataSetSize); var execTime = 0, renderTime = 0, images = { loading : "img/loading.gif", done: "img/done.gif" }, $els = { itemsNr: $('#Items h2 span').first(), exec : { span: $('#ExecTime span'), img: $('#ExecTime img') }, render : { span: $('#RenderTime span'), img: $('#RenderTime img') } }; $(function() { var collection = window.collection = new Backbone.Collection(), itemsView = new (Backbone.View.extend({ el: '#Items', collection: new Backbone.Collection(), initialize: function() { this.$ul = this.$('ul'); this.collection.reset(items); this.collection.add({ Name : { FirstName : 'John', LastName : 'Smith' }, Age : 0, Profession: 'team manager', Country : undefined, Hobbies : [ ] }); this.timeout = undefined; this.origLen = false; this.collection.on('add', this.addOne, this); this.collection.on('reset', this.addAll, this); Facetr(this.collection).on('clear change remove sort', this.addAll, this); this.addAll(); }, showRenderTime: function(){ renderTime = (new Date().getTime()) - renderTime; $els.render.span.html(renderTime); $els.render.img.attr('src', images.done); }, addOne: function(model) { var itemHTML = _.template($('#Item_template').html(), model.toJSON()); this.$ul.append(itemHTML); }, addAll: function() { this.$ul.html(''); var i = 0, len = this.collection.length, self = this; this.$('ul').remove(); renderTime = new Date().getTime(); $els.render.span.html(''); $els.render.img.attr('src', images.loading); clearTimeout(this.timeout); if(i !== len) { (function loop() { var model = self.collection.at(i); if(model) { self.addOne(model); } i = i + 1; if(i < len) { if(i % 50 === 0) { self.timeout = setTimeout(loop, 1); } else { loop(); } } else { self.$el.append(self.$ul); self.showRenderTime(); $('#Items h2 span').html(Facetr(self.collection).origLength()); } $els.itemsNr.html(i); })(); } else { $els.itemsNr.html(0); } } }))({ collection: collection }), facetsView = new (Backbone.View.extend({ el: '#Facets', events: { 'click .value a' : 'toggleValue' }, initialize: function() { Facetr(this.collection).facet('Country').label('Country').sortByValue().asc(); Facetr(this.collection).facet('Name.LastName').label('Last Name').sortByCount().desc(); Facetr(this.collection).facet('Hobbies').label('Hobbies').sortByCount().desc(); Facetr(this.collection).facetsOrder(['Name.LastName','Country']); Facetr(this.collection).facet('Profession').sortByActiveCount().desc(); var hierarchySettings = [ { value: "manager", label: "Manager", groups: [ { value: "project manager", label: "Project Manager", groups: [ { value: "team manager", label: "Team Manager" } ] } ] }, { value: "artist", label: "Artist", groups: [ { value: "musician", label: "Musician" }, { value: "painter", label: "Painter" } ] } ]; Facetr(this.collection).facet('Profession').hierarchy(hierarchySettings); this.collection.on('reset change add remove', this.render, this); Facetr(this.collection).on('filter unfilter facetsOrderChange', this.render, this); Facetr(this.collection).on('filter unfilter facetsOrderChange', this.showExecTime, this); execTime = new Date().getTime(); $els.exec.span.html(''); $els.exec.img.attr('src',images.loading); this.render(); this.sort(); var self = this; $("select").on("change", function() { self.sort(); }); var searchEl = $("#Search"); var search = function() { var el = this; execTime = new Date().getTime(); Facetr(self.collection).addFilter('searchByKeyword', function(model) { var regex = new RegExp($(el).val(), 'i'); return regex.test(model.get('Name').FirstName); }); }, searchDeb = _.debounce(search, 500); _.bind(search, searchEl); searchEl.on("keyup", searchDeb); this.showExecTime(); }, sort: function() { this.sortBy($("select#SortAttr").find("option:selected").text(), $("select#SortDir").find("option:selected").text()); }, sortBy: function(attr, dir) { execTime = new Date().getTime(); // dir [ASC|DESC] gets lowercased to match Facetr methods asc and desc Facetr(this.collection).sortBy(attr)[dir.toLowerCase()](); }, toggleValue: function(e) { execTime = new Date().getTime(); $els.exec.span.html(''); $els.exec.img.attr('src',images.loading); e.preventDefault(); var $target = $(e.currentTarget), facet = $target.closest('.facet').attr('id'), value = $target.find('span').first().attr('data-value'); if($target.hasClass('available')) { Facetr(this.collection).facet(facet).value(value); } else if($target.hasClass('active')) { Facetr(this.collection).facet(facet).removeValue(value); } }, showExecTime: function(){ execTime = (new Date().getTime()) - execTime; $els.exec.span.html(execTime); $els.exec.img.attr('src', images.done); }, render: function(facetName, facetValue) { var facetsHTML = _.template($('#Facets_template').html(), { facets : Facetr(this.collection).toJSON(), valueTemplate : _.template($('#FacetValue_template').html()) }); this.$el.html(facetsHTML); } }))({ collection: collection }); }); }(jQuery, _, Backbone)); </script> </body> </html>