1+function ($) { 2 'use strict'; 3 4 $.fn.filterable = function (options) { 5 return this.each(function () { 6 var $root = $(this); 7 8 var defaults = { 9 params: [] 10 }; 11 12 var settings = $.extend({}, defaults, options); 13 14 if (typeof $root.data('params') !== "undefined") { 15 settings.params = $root.data('params').split(' '); 16 } 17 18 var filters = settings.params; 19 var currentFilters = {}; 20 21 var readUrl = function () { 22 for (var i = 0; i < filters.length; i++) { 23 currentFilters[filters[i]] = $.QueryString[filters[i]] || ''; 24 } 25 }; 26 var buildUrl = function () { 27 var qstring = ''; 28 for (var i = 0; i < filters.length; i++) { 29 if (currentFilters[filters[i]] !== '') { 30 if (qstring !== '') { 31 qstring += '&'; 32 } 33 qstring += encodeURIComponent(filters[i]) + '=' + encodeURIComponent(currentFilters[filters[i]]); 34 } 35 } 36 var newUrl = window.location.pathname; 37 if (qstring !== '') { 38 newUrl += '?' + qstring; 39 } 40 return newUrl; 41 }; 42 var updateUrl = function () { 43 var url = buildUrl(); 44 history.pushState(currentFilters, '', url); 45 }; 46 47 var escapeForSelector = function (text) { 48 // FIXME - use CSS.escape polyfill or similar 49 return text; 50 }; 51 52 var readForm = function () { 53 for (var i = 0; i < filters.length; i++) { 54 currentFilters[filters[i]] = $root.find('.filterform :input[name="' + escapeForSelector(filters[i]) + '"]').val() || ''; 55 } 56 }; 57 var updateForm = function () { 58 for (var i = 0; i < filters.length; i++) { 59 $root.find('.filterform :input[name="' + escapeForSelector(filters[i]) + '"]').val(currentFilters[filters[i]]); 60 } 61 }; 62 63 var readLink = function ($el) { 64 for (var i = 0; i < filters.length; i++) { 65 currentFilters[filters[i]] = $el.attr('data-' + escapeForSelector(filters[i])) || ''; 66 } 67 }; 68 69 var applyFilters = function () { 70 var $filts = $root.find('.filterable'); 71 $filts.show(); 72 for (var i = 0; i < filters.length; i++) { 73 var v = currentFilters[filters[i]]; 74 if (v !== '') { 75 $filts.not('[data-' + escapeForSelector(filters[i]) + '~="' + escapeForSelector(v) + '"]').hide(); 76 } 77 } 78 var count = $filts.filter(':visible').length; 79 $root.find('.filtercount').text(count.toLocaleString('en-US')); 80 }; 81 82 // init 83 readUrl(); 84 updateForm(); 85 applyFilters(); 86 87 $root.find('.filterform').submit(function (event) { 88 event.preventDefault(); 89 readForm(); 90 applyFilters(); 91 updateUrl(); 92 }); 93 $root.find('.filterlink').click(function (event) { 94 event.preventDefault(); 95 readLink($(this)); 96 updateForm(); 97 applyFilters(); 98 updateUrl(); 99 $root[0].scrollIntoView(); 100 }); 101 window.onpopstate = function (event) { 102 currentFilters = {}; 103 for (var i = 0; i < filters.length; i++) { 104 if (history.state && history.state[filters[i]] !== null) { 105 currentFilters[filters[i]] = history.state[filters[i]]; 106 } else { 107 currentFilters[filters[i]] = ''; 108 } 109 } 110 updateForm(); 111 applyFilters(); 112 }; 113 114 }); 115 }; 116}(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.