diff --git a/server/src/main/resources/html/static/custom.css b/server/src/main/resources/html/static/custom.css index d055d9a5..820f8651 100644 --- a/server/src/main/resources/html/static/custom.css +++ b/server/src/main/resources/html/static/custom.css @@ -34,4 +34,30 @@ color: black; text-decoration: none; cursor: pointer; -} \ No newline at end of file +} + +.asc:after, .desc:after { + font-family: 'FontAwesome'; + padding-left: .5rem; + vertical-align: middle; +} + +.asc:after { + content: "\f0de"; /* unicode sort up */ +} + +.desc:after { + content: "\f0dd"; /* unicode sort down */ +} + +th a { + display: block; +} + +th a:hover { + text-decoration: none; +} + + + + diff --git a/server/src/main/resources/html/static/index.html b/server/src/main/resources/html/static/index.html index 1daddb5b..dc5c0150 100644 --- a/server/src/main/resources/html/static/index.html +++ b/server/src/main/resources/html/static/index.html @@ -107,7 +107,7 @@
Model | -Paused | -Online | -Recording | +Model | +Paused | +Online | +Recording | Actions |
---|---|---|---|---|---|---|---|---|
- | - | - | + | + | + | + | First Name | + +Default field to sort can also be provided: + +Age | + +It's also possible to sort by nested attibutes by separating the attribute names with a dot (should work with array indices too): + +Pet name | + +See full examples in examples folder. + +##Dependencies + - [jQuery](http://jquery.com/) + - [Knockout](http://knockoutjs.com/) + +##License +MIT license - [http://www.opensource.org/licenses/mit-license.php](http://www.opensource.org/licenses/mit-license.php) diff --git a/server/src/main/resources/html/static/vendor/knockout-orderable/knockout.bindings.orderable.js b/server/src/main/resources/html/static/vendor/knockout-orderable/knockout.bindings.orderable.js new file mode 100644 index 00000000..0c6936c6 --- /dev/null +++ b/server/src/main/resources/html/static/vendor/knockout-orderable/knockout.bindings.orderable.js @@ -0,0 +1,112 @@ +ko.bindingHandlers.orderable = { + getProperty: function(o, s) { + // copied from http://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-with-string-key + s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties + s = s.replace(/^\./, ''); // strip a leading dot + var a = s.split('.'); + while (a.length) { + var n = a.shift(); + if (n in o) { + o = o[n]; + } else { + return; + } + } + return o; + }, + + compare: function (left, right) { + if (typeof left === 'string' || typeof right === 'string') { + return left ? left.localeCompare(right) : 1; + } + if (left > right) + return 1; + + return left < right ? -1 : 0; + }, + + sort: function (viewModel, collection, field) { + //make sure we sort only once and not for every binding set on table header + if (viewModel[collection].orderField() == field) { + viewModel[collection].sort(function (left, right) { + var left_field = ko.bindingHandlers.orderable.getProperty(left, field); + var right_field = ko.bindingHandlers.orderable.getProperty(right, field); + var left_val = (typeof left_field === 'function') ? left_field() : left_field; + right_val = (typeof right_field === 'function') ? right_field() : right_field; + if (viewModel[collection].orderDirection() == "desc") { + return ko.bindingHandlers.orderable.compare(right_val, left_val); + } else { + return ko.bindingHandlers.orderable.compare(left_val, right_val); + } + }); + } + }, + + init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { + //get provided options + var collection = valueAccessor().collection; + var field = valueAccessor().field; + + //add a few observables to ViewModel to track order field and direction + if (viewModel[collection].orderField == undefined) { + viewModel[collection].orderField = ko.observable(); + } + if (viewModel[collection].orderDirection == undefined) { + viewModel[collection].orderDirection = ko.observable("asc"); + } + + var defaultField = valueAccessor().defaultField; + var defaultDirection = valueAccessor().defaultDirection || "asc"; + if (defaultField) { + viewModel[collection].orderField(field); + viewModel[collection].orderDirection(defaultDirection); + ko.bindingHandlers.orderable.sort(viewModel, collection, field); + } + + //set order observables on table header click + $(element).click(function (e) { + e.preventDefault(); + + //flip sort direction if current sort field is clicked again + if (viewModel[collection].orderField() == field) { + if (viewModel[collection].orderDirection() == "asc") { + viewModel[collection].orderDirection("desc"); + } else { + viewModel[collection].orderDirection("asc"); + } + } + + viewModel[collection].orderField(field); + }); + + //order records when observables changes, so ordering can be changed programmatically + viewModel[collection].orderField.subscribe(function () { + ko.bindingHandlers.orderable.sort(viewModel, collection, field); + }); + viewModel[collection].orderDirection.subscribe(function () { + ko.bindingHandlers.orderable.sort(viewModel, collection, field); + }); + }, + + update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { + //get provided options + var collection = valueAccessor().collection; + var field = valueAccessor().field; + var isOrderedByThisField = viewModel[collection].orderField() == field; + + //apply css binding programmatically + ko.bindingHandlers.css.update( + element, + function () { + return { + sorted: isOrderedByThisField, + asc: isOrderedByThisField && viewModel[collection].orderDirection() == "asc", + desc: isOrderedByThisField && viewModel[collection].orderDirection() == "desc" + }; + }, + allBindingsAccessor, + viewModel, + bindingContext + ); + } +};