diff --git a/js/h5p-data-view.js b/js/h5p-data-view.js index 6e65e98..669e4d7 100644 --- a/js/h5p-data-view.js +++ b/js/h5p-data-view.js @@ -50,14 +50,13 @@ var H5PDataView = (function ($) { self.limit = 20; self.offset = 0; self.filterOn = []; + self.facets = {}; self.loadData(); } /** * Load data from source URL. - * - * @public */ H5PDataView.prototype.loadData = function () { var self = this; @@ -85,6 +84,22 @@ var H5PDataView = (function ($) { url += '&filters[' + i + ']=' + encodeURIComponent(self.filterOn[i]); } + // Add facets + for (var col in self.facets) { + if (!self.facets.hasOwnProperty(col)) { + continue; + } + + var facets = self.facets[col]; + for (var facet in facets) { + if (!facets.hasOwnProperty(facet)) { + continue; + } + + url += '&facets[' + col + '][]=' + facet; + } + } + // Fire ajax request $.ajax({ dataType: 'json', @@ -114,7 +129,6 @@ var H5PDataView = (function ($) { /** * Display the given message to the user. * - * @public * @param {jQuery} $message wrapper with message */ H5PDataView.prototype.setMessage = function ($message) { @@ -131,7 +145,6 @@ var H5PDataView = (function ($) { /** * Update table data. * - * @public * @param {Array} rows */ H5PDataView.prototype.updateTable = function (rows) { @@ -144,6 +157,12 @@ var H5PDataView = (function ($) { // Add filters self.addFilters(); + // Add facets + self.$facets = $('
', { + 'class': 'h5p-facet-wrapper', + appendTo: self.$container + }); + // Create new table self.table = new H5PUtils.Table(self.classes, self.headers); self.table.setHeaders(self.headers, function (order) { @@ -154,14 +173,119 @@ var H5PDataView = (function ($) { self.table.appendTo(self.$container); } + // Process cell data before updating table + for (var i = 0; i < self.headers.length; i++) { + if (self.headers[i].facet === true) { + // Process rows for col, expect object or array + for (var j = 0; j < rows.length; j++) { + rows[j][i] = self.createFacets(rows[j][i], i); + } + } + } + // Add/update rows - self.table.setRows(rows); + var $tbody = self.table.setRows(rows); + + // Add event handlers for facets + $('.h5p-facet', $tbody).click(function () { + var $facet = $(this); + self.filterByFacet($facet.data('col'), $facet.data('id'), $facet.text()); + }).keypress(function (event) { + if (event.which === 32) { + var $facet = $(this); + self.filterByFacet($facet.data('col'), $facet.data('id'), $facet.text()); + } + }); + }; + + /** + * Create button for adding facet to filter. + * + * @param (object|Array) input + * @param number col ID of column + */ + H5PDataView.prototype.createFacets = function (input, col) { + var self = this; + var facets = ''; + + if (input instanceof Array) { + // Facet can be filtered on multiple values at the same time + for (var i = 0; i < input.length; i++) { + if (facets !== '') { + facets += ', '; + } + facets += '' + input[i].title + ''; + } + } + else { + // Single value facet filtering + facets += '' + input.title + ''; + } + + return facets; + }; + + /** + * Adds a filter based on the given facet. + * + * @param number col ID of column we're filtering + * @param number id ID to filter on + * @param string text Human readable label for the filter + */ + H5PDataView.prototype.filterByFacet = function (col, id, text) { + var self = this; + + if (self.facets[col] === undefined) { + self.facets[col] = {}; + } + + // Only add if it isn't already added + if (self.facets[col][id] === undefined) { + self.facets[col][id] = text; + + // Add to UI + var $tag = $('', { + 'class': 'h5p-facet-tag', + text: text, + appendTo: self.$facets, + }); + + /** + * Callback for removing filter + * + * @private + */ + var remove = function () { + delete self.facets[col][id]; + $tag.remove(); + self.loadData(); + }; + + // Remove button + $('', { + role: 'button', + tabindex: 0, + appendTo: $tag, + text: self.l10n.remove, + title: self.l10n.remove, + on: { + click: remove, + keypress: function (event) { + if (event.which === 32) { + remove(); + } + } + } + }); + + // Load data with new filter + self.loadData(); + } }; /** * Update pagination widget. * - * @public * @param {Number} num size of data collection */ H5PDataView.prototype.updatePagination = function (num) { @@ -187,8 +311,6 @@ var H5PDataView = (function ($) { /** * Add filters. - * - * @public */ H5PDataView.prototype.addFilters = function () { var self = this; @@ -203,8 +325,7 @@ var H5PDataView = (function ($) { /** * Add text filter for given col num. - - * @public + * * @param {Number} col */ H5PDataView.prototype.addTextFilter = function (col) { diff --git a/js/h5p-utils.js b/js/h5p-utils.js index 423eb30..f47d1b6 100644 --- a/js/h5p-utils.js +++ b/js/h5p-utils.js @@ -303,6 +303,8 @@ var H5PUtils = H5PUtils || {}; $tbody.replaceWith($newTbody); $tbody = $newTbody; + + return $tbody; }; /** diff --git a/styles/h5p-admin.css b/styles/h5p-admin.css index 0122206..f8155dd 100644 --- a/styles/h5p-admin.css +++ b/styles/h5p-admin.css @@ -257,6 +257,8 @@ button.h5p-admin.disabled:hover { } .h5p-data-view input[type="text"] { margin-bottom: 0.5em; + float: left; + margin-right: 10px; } .h5p-data-view input[type="text"]::-ms-clear { display: none; @@ -283,3 +285,54 @@ button.h5p-admin.disabled:hover { .h5p-data-view th[role="button"].h5p-sort:hover:after { color: #999; } +.h5p-data-view .h5p-facet { + cursor: pointer; + color: #0073aa; + outline: none; +} +.h5p-data-view .h5p-facet:hover, +.h5p-data-view .h5p-facet:active { + color: #00a0d2; +} +.h5p-data-view .h5p-facet:focus { + color: #124964; + box-shadow: 0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8); +} +.h5p-data-view .h5p-facet-wrapper { + line-height: 27px; +} +.h5p-data-view .h5p-facet-tag { + margin-left: 10px; + background: #e8e8e8; + border: 1px solid #cbcbcc; + border-radius: 5px; + color: #5d5d5d; + padding: 0 24px 0 10px; + display: inline-block; + position: relative; +} +.h5p-data-view .h5p-facet-tag > span { + position: absolute; + right: 0; + top: auto; + bottom: auto; + font-size: 18px; + color: #a2a2a2; + outline: none; + width: 21px; + text-indent: 4px; + letter-spacing: 10px; + overflow: hidden; + cursor: pointer; +} +.h5p-data-view .h5p-facet-tag > span:before { + content: "×"; + font-weight: bold; +} +.h5p-data-view .h5p-facet-tag > span:hover, +.h5p-data-view .h5p-facet-tag > span:focus { + color: #a20000; +} +.h5p-data-view .h5p-facet-tag > span:active { + color: #d20000; +}