1 | /*
|
---|
2 | angular-tablesort v1.0.7
|
---|
3 | (c) 2013-2015 Mattias Holmlund, http://mattiash.github.io/angular-tablesort
|
---|
4 | License: MIT
|
---|
5 | */
|
---|
6 |
|
---|
7 | var tableSortModule = angular.module('tableSort', []);
|
---|
8 |
|
---|
9 | tableSortModule.directive('tsWrapper', ['$log', '$parse', function ($log, $parse) {
|
---|
10 | 'use strict';
|
---|
11 | return {
|
---|
12 | scope: true,
|
---|
13 | controller: ['$scope', function ($scope) {
|
---|
14 | $scope.sortExpression = [];
|
---|
15 | $scope.headings = [];
|
---|
16 |
|
---|
17 | var parse_sortexpr = function (expr) {
|
---|
18 | return [$parse(expr), null, false];
|
---|
19 | };
|
---|
20 |
|
---|
21 | this.setSortField = function (sortexpr, element) {
|
---|
22 | var i;
|
---|
23 | var expr = parse_sortexpr(sortexpr);
|
---|
24 | if ($scope.sortExpression.length === 1
|
---|
25 | && $scope.sortExpression[0][0] === expr[0]) {
|
---|
26 | if ($scope.sortExpression[0][2]) {
|
---|
27 | element.removeClass("tablesort-desc");
|
---|
28 | element.addClass("tablesort-asc");
|
---|
29 | $scope.sortExpression[0][2] = false;
|
---|
30 | }
|
---|
31 | else {
|
---|
32 | element.removeClass("tablesort-asc");
|
---|
33 | element.addClass("tablesort-desc");
|
---|
34 | $scope.sortExpression[0][2] = true;
|
---|
35 | }
|
---|
36 | }
|
---|
37 | else {
|
---|
38 | for (i = 0; i < $scope.headings.length; i = i + 1) {
|
---|
39 | $scope.headings[i]
|
---|
40 | .removeClass("tablesort-desc")
|
---|
41 | .removeClass("tablesort-asc");
|
---|
42 | }
|
---|
43 | element.addClass("tablesort-asc");
|
---|
44 | $scope.sortExpression = [expr];
|
---|
45 | }
|
---|
46 | };
|
---|
47 |
|
---|
48 | this.addSortField = function (sortexpr, element) {
|
---|
49 | var i;
|
---|
50 | var toggle_order = false;
|
---|
51 | var expr = parse_sortexpr(sortexpr);
|
---|
52 | for (i = 0; i < $scope.sortExpression.length; i = i + 1) {
|
---|
53 | if ($scope.sortExpression[i][0] === expr[0]) {
|
---|
54 | if ($scope.sortExpression[i][2]) {
|
---|
55 | element.removeClass("tablesort-desc");
|
---|
56 | element.addClass("tablesort-asc");
|
---|
57 | $scope.sortExpression[i][2] = false;
|
---|
58 | }
|
---|
59 | else {
|
---|
60 | element.removeClass("tablesort-asc");
|
---|
61 | element.addClass("tablesort-desc");
|
---|
62 | $scope.sortExpression[i][2] = true;
|
---|
63 | }
|
---|
64 | toggle_order = true;
|
---|
65 | }
|
---|
66 | }
|
---|
67 | if (!toggle_order) {
|
---|
68 | element.addClass("tablesort-asc");
|
---|
69 | $scope.sortExpression.push(expr);
|
---|
70 | }
|
---|
71 | };
|
---|
72 |
|
---|
73 | this.setTrackBy = function (trackBy) {
|
---|
74 | $scope.trackBy = trackBy;
|
---|
75 | };
|
---|
76 |
|
---|
77 | this.registerHeading = function (headingelement) {
|
---|
78 | $scope.headings.push(headingelement);
|
---|
79 | };
|
---|
80 |
|
---|
81 | $scope.sortFun = function (a, b) {
|
---|
82 | var i, aval, bval, descending, filterFun;
|
---|
83 | for (i = 0; i < $scope.sortExpression.length; i = i + 1) {
|
---|
84 | aval = $scope.sortExpression[i][0](a);
|
---|
85 | bval = $scope.sortExpression[i][0](b);
|
---|
86 | filterFun = b[$scope.sortExpression[i][1]];
|
---|
87 | if (filterFun) {
|
---|
88 | aval = filterFun(aval);
|
---|
89 | bval = filterFun(bval);
|
---|
90 | }
|
---|
91 | if (aval === undefined || aval === null) {
|
---|
92 | aval = "";
|
---|
93 | }
|
---|
94 | if (bval === undefined || bval === null) {
|
---|
95 | bval = "";
|
---|
96 | }
|
---|
97 | descending = $scope.sortExpression[i][2];
|
---|
98 | if (aval > bval) {
|
---|
99 | return descending ? -1 : 1;
|
---|
100 | }
|
---|
101 | else if (aval < bval) {
|
---|
102 | return descending ? 1 : -1;
|
---|
103 | }
|
---|
104 | }
|
---|
105 |
|
---|
106 | // All the sort fields were equal. If there is a "track by" expression,
|
---|
107 | // use that as a tiebreaker to make the sort result stable.
|
---|
108 | if ($scope.trackBy) {
|
---|
109 | aval = a[$scope.trackBy];
|
---|
110 | bval = b[$scope.trackBy];
|
---|
111 | if (aval === undefined || aval === null) {
|
---|
112 | aval = "";
|
---|
113 | }
|
---|
114 | if (bval === undefined || bval === null) {
|
---|
115 | bval = "";
|
---|
116 | }
|
---|
117 | if (aval > bval) {
|
---|
118 | return descending ? -1 : 1;
|
---|
119 | }
|
---|
120 | else if (aval < bval) {
|
---|
121 | return descending ? 1 : -1;
|
---|
122 | }
|
---|
123 | }
|
---|
124 | return 0;
|
---|
125 | };
|
---|
126 | }]
|
---|
127 | };
|
---|
128 | }]);
|
---|
129 |
|
---|
130 | tableSortModule.directive('tsCriteria', function () {
|
---|
131 | return {
|
---|
132 | require: "^tsWrapper",
|
---|
133 | link: function (scope, element, attrs, tsWrapperCtrl) {
|
---|
134 | var clickingCallback = function (event) {
|
---|
135 | scope.$apply(function () {
|
---|
136 | if (event.shiftKey) {
|
---|
137 | tsWrapperCtrl.addSortField(attrs.tsCriteria, element);
|
---|
138 | }
|
---|
139 | else {
|
---|
140 | tsWrapperCtrl.setSortField(attrs.tsCriteria, element);
|
---|
141 | }
|
---|
142 | });
|
---|
143 | };
|
---|
144 | element.bind('click', clickingCallback);
|
---|
145 | element.addClass('tablesort-sortable');
|
---|
146 | if ("tsDefault" in attrs && attrs.tsDefault !== "0") {
|
---|
147 | tsWrapperCtrl.addSortField(attrs.tsCriteria, element);
|
---|
148 | if (attrs.tsDefault == "descending") {
|
---|
149 | tsWrapperCtrl.addSortField(attrs.tsCriteria, element);
|
---|
150 | }
|
---|
151 | }
|
---|
152 | tsWrapperCtrl.registerHeading(element);
|
---|
153 | }
|
---|
154 | };
|
---|
155 | });
|
---|
156 |
|
---|
157 | tableSortModule.directive("tsRepeat", ['$compile', function ($compile) {
|
---|
158 | return {
|
---|
159 | terminal: true,
|
---|
160 | require: "^tsWrapper",
|
---|
161 | priority: 1000000,
|
---|
162 | link: function (scope, element, attrs, tsWrapperCtrl) {
|
---|
163 | var clone = element.clone();
|
---|
164 | var tdcount = element[0].childElementCount;
|
---|
165 | var ngRepeatDirective = "ng-repeat";
|
---|
166 | if (typeof (clone.attr(ngRepeatDirective)) === "undefined") {
|
---|
167 | ngRepeatDirective = "data-ng-repeat";
|
---|
168 | }
|
---|
169 | var repeatExpr = clone.attr(ngRepeatDirective);
|
---|
170 | var trackBy = null;
|
---|
171 | var trackByMatch = repeatExpr.match(/\s+track\s+by\s+\S+?\.(\S+)/);
|
---|
172 | if (trackByMatch) {
|
---|
173 | trackBy = trackByMatch[1];
|
---|
174 | tsWrapperCtrl.setTrackBy(trackBy);
|
---|
175 | }
|
---|
176 |
|
---|
177 | if (repeatExpr.search(/tablesort/) != -1) {
|
---|
178 | repeatExpr = repeatExpr.replace(/tablesort/, "tablesortOrderBy:sortFun");
|
---|
179 | } else {
|
---|
180 | repeatExpr = repeatExpr.replace(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(\s+track\s+by\s+[\s\S]+?)?\s*$/,
|
---|
181 | "$1 in $2 | tablesortOrderBy:sortFun$3");
|
---|
182 | }
|
---|
183 |
|
---|
184 |
|
---|
185 |
|
---|
186 | while (element[0].firstChild) {
|
---|
187 | element[0].removeChild(element[0].firstChild);
|
---|
188 | }
|
---|
189 | var td = document.createElement("td");
|
---|
190 | td.colSpan = tdcount;
|
---|
191 | element[0].appendChild(td);
|
---|
192 |
|
---|
193 | element[0].className += " showIfLast";
|
---|
194 | clone.removeAttr("ts-repeat");
|
---|
195 |
|
---|
196 | clone.attr(ngRepeatDirective, repeatExpr);
|
---|
197 | var clonedElement = $compile(clone)(scope);
|
---|
198 | element.after(clonedElement);
|
---|
199 | }
|
---|
200 | };
|
---|
201 | }]);
|
---|
202 |
|
---|
203 | tableSortModule.filter('tablesortOrderBy', function () {
|
---|
204 | return function (array, sortfun) {
|
---|
205 | if (!array) return;
|
---|
206 | var arrayCopy = [];
|
---|
207 | for (var i = 0; i < array.length; i++) { arrayCopy.push(array[i]); }
|
---|
208 | return arrayCopy.sort(sortfun);
|
---|
209 | };
|
---|
210 | });
|
---|
211 |
|
---|
212 | tableSortModule.filter('parseInt', function () {
|
---|
213 | return function (input) {
|
---|
214 | return parseInt(input) || null;
|
---|
215 | };
|
---|
216 | });
|
---|
217 |
|
---|
218 | tableSortModule.filter('parseFloat', function () {
|
---|
219 | return function (input) {
|
---|
220 | return parseFloat(input) || null;
|
---|
221 | };
|
---|
222 | }); |
---|