blob: 8e748240471ae0fea1de244f6c57cb52f20427af [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
(function() {
'use strict';
var eagleComponents = angular.module('eagle.components');
eagleComponents.directive('sortTable', function($compile) {
return {
restrict: 'AE',
scope: true,
//terminal: true,
priority: 1001,
/**
* @param $scope
* @param $element
* @param {{}} $attrs
* @param {string} $attrs.sortTable Data source
* @param {string?} $attrs.isSorting Will bind parent variable of sort state
* @param {string?} $attrs.scope Will bind parent variable of current scope
* @param {string?} $attrs.sortpath Default sort path
* @param {[]?} $attrs.searchPathList Filter search path list
* @param {string?} $attrs.maxSize Set max display size of page
*/
controller: function($scope, $element, $attrs) {
var sortmatch;
var worker;
var worker_id = 0;
if(typeof(Worker) !== "undefined") {
worker = new Worker("public/js/worker/sortTableWorker.js?_=" + window._TRS());
}
// Initialization
$scope.pageNumber = 1;
$scope.pageSize = 10;
$scope.maxSize = $attrs.maxSize || 10;
$scope.search = "";
$scope.orderKey = "";
$scope.orderAsc = true;
if($attrs.sortpath) {
sortmatch = $attrs.sortpath.match(/^(-)?(.*)$/);
if(sortmatch[1]) {
$scope.orderAsc = false;
}
$scope.orderKey = sortmatch[2];
}
// UI - Column sort
$scope.doSort = function(path) {
if($scope.orderKey === path) {
$scope.orderAsc = !$scope.orderAsc;
} else {
$scope.orderKey = path;
$scope.orderAsc = true;
}
};
$scope.checkSortClass = function(key) {
if($scope.orderKey === key) {
return "fa sort-mark " + ($scope.orderAsc ? "fa-sort-asc" : "fa-sort-desc");
}
return "fa fa-sort sort-mark";
};
// List filter & sort
function setState(bool) {
if(!$attrs.isSorting) return;
$scope.$parent[$attrs.isSorting] = bool;
}
var cacheSearch = "";
var cacheOrder = "";
var cacheOrderAsc = null;
var cacheFilteredList = null;
$scope.getFilteredList = function () {
if(
cacheSearch !== $scope.search ||
cacheOrder !== $scope.orderKey ||
cacheOrderAsc !== $scope.orderAsc ||
!cacheFilteredList
) {
cacheSearch = $scope.search;
cacheOrder = $scope.orderKey;
cacheOrderAsc = $scope.orderAsc;
var fullList = $scope.$parent[$attrs.sortTable] || [];
if(!cacheFilteredList) cacheFilteredList = fullList;
if(!worker) {
cacheFilteredList = __sortTable_generateFilteredList(fullList, cacheSearch, cacheOrder, cacheOrderAsc, $scope.$parent[$attrs.searchPathList]);
setState(false);
} else {
worker_id += 1;
setState(true);
var list = JSON.stringify(fullList);
worker.postMessage({
search: cacheSearch,
order: cacheOrder,
orderAsc: cacheOrderAsc,
searchPathList: $scope.$parent[$attrs.searchPathList],
list: list,
id: worker_id
});
}
}
return cacheFilteredList;
};
// Week watch. Will not track each element
$scope.$watch($attrs.sortTable + ".length", function () {
cacheFilteredList = null;
});
$scope.$watch($attrs.sortTable + ".___SORT_TABLE___", function () {
var fullList = $scope.$parent[$attrs.sortTable];
if(fullList && !fullList.___SORT_TABLE___) {
fullList.___SORT_TABLE___ = +new Date();
cacheFilteredList = null;
}
});
function workMessage(event) {
var data = event.data;
if(worker_id !== data.id) return;
setState(false);
cacheFilteredList = data.list;
$scope.$apply();
}
worker.addEventListener("message", workMessage);
$scope.$on('$destroy', function() {
worker.removeEventListener("message", workMessage);
});
// Scope bind
if($attrs.scope) {
$scope.$parent[$attrs.scope] = $scope;
}
},
compile: function ($element) {
var contents = $element.contents().remove();
return {
post: function preLink($scope, $element) {
$scope.defaultPageSizeList = [10, 25, 50, 100];
$element.append(contents);
// Tool Container
var $toolContainer = $(
'<div class="tool-container clearfix">' +
'</div>'
).insertBefore($element.find("table"));
// Search Box
var $search = $(
'<div class="search-box">' +
'<input type="search" class="form-control input-sm" placeholder="Search" ng-model="search" />' +
'<span class="fa fa-search" />' +
'</div>'
).appendTo($toolContainer);
$compile($search)($scope);
// Page Size
var $pageSize = $(
'<div class="page-size">' +
'Show' +
'<select class="form-control" ng-model="pageSize" convert-to-number>' +
'<option ng-repeat="size in pageSizeList || defaultPageSizeList track by $index">{{size}}</option>' +
'</select>' +
'Entities' +
'</div>'
).appendTo($toolContainer);
$compile($pageSize)($scope);
// Non-Sort Column
$element.find("table thead th:not([sortpath])").each(function () {
var $this = $(this);
$compile($this)($scope);
});
// Sort Column
$element.find("table [sortpath]").each(function () {
var $this = $(this);
var _sortpath = $this.attr("sortpath");
$this.attr("ng-click", "doSort('" + _sortpath + "')");
$this.prepend('<span ng-class="checkSortClass(\'' + _sortpath + '\')"></span>');
$compile($this)($scope);
});
// Repeat Items
var $tr = $element.find("table [ts-repeat], table > tbody > tr").filter(":first");
$tr.attr("ng-repeat", 'item in getFilteredList().slice((pageNumber - 1) * pageSize, pageNumber * pageSize) track by $index');
$compile($tr)($scope);
// Page Navigation
var $navigation = $(
'<div class="navigation-bar clearfix">' +
'<span>' +
'show {{(pageNumber - 1) * pageSize + 1}} to {{pageNumber * pageSize}} of {{getFilteredList().length}} items' +
'</span>' +
'<uib-pagination total-items="getFilteredList().length" ng-model="pageNumber" boundary-links="true" items-per-page="pageSize" max-size="maxSize"></uib-pagination>' +
'</div>'
).appendTo($element);
$compile($navigation)($scope);
}
};
}
};
});
eagleComponents.directive('convertToNumber', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
ngModel.$parsers.push(function(val) {
return parseInt(val, 10);
});
ngModel.$formatters.push(function(val) {
return '' + val;
});
}
};
});
})();