294 lines
9.5 KiB
JavaScript
294 lines
9.5 KiB
JavaScript
/**
|
|
* Create a roster view.
|
|
*
|
|
* @type undefined
|
|
* @param {scope} $scope the controller's scope
|
|
* @param {loader} $translatePartialLoader I18N support provider
|
|
* @param {angularService} $http Angular HTTP provider
|
|
* @param {angularService} $log Angular logger
|
|
* @param {angularService} jmriWebSocket JMRI web socket provider
|
|
* @param {angularService} pfViewUtils Patternfly utilities for handling data views
|
|
* @param {angularService} $filter Patternfly filter service
|
|
*/
|
|
angular.module('jmri.app').controller('RosterCtrl', function RosterCtrl($scope, $translate, $translatePartialLoader, $http, $log, jmriWebSocket, pfViewUtils, $filter) {
|
|
|
|
// load translations
|
|
$translatePartialLoader.addPart('web/roster');
|
|
|
|
// true if loading indicator should be shown; false otherwise
|
|
$scope.loading = true;
|
|
|
|
// columns for table view with default text
|
|
$scope.columns = [
|
|
{header: 'ID', itemField: 'name'},
|
|
{header: 'DCC Address', itemField: 'address'},
|
|
{header: 'Road Name', itemField: 'road'},
|
|
{header: 'Road Number', itemField: 'number'},
|
|
{header: 'Owner', itemField: 'owner'}
|
|
];
|
|
// translate column headers
|
|
for (var i in $scope.columns) {
|
|
var c = $scope.columns[i];
|
|
$translate('ROSTER.FIELD.' + c.itemField).then(function(translation) {
|
|
c.header = translation;
|
|
}, function(translationId) {
|
|
$log.error('Unable to translate ' + translationId);
|
|
});
|
|
$scope.columns[i] = c;
|
|
}
|
|
|
|
// the roster items, initially an empty list
|
|
$scope.allItems = [];
|
|
$scope.items = $scope.allItems;
|
|
|
|
//
|
|
// Cards/List/Table Views
|
|
//
|
|
|
|
$scope.listConfig = {
|
|
selectionMatchProp: 'name',
|
|
checkDisabled: false,
|
|
itemsAvailable: true,
|
|
onCheckBoxChange: handleCheckBoxChange
|
|
};
|
|
|
|
$scope.emptyStateConfig = {
|
|
icon: 'pficon-warning-triangle-o', // replace with pficon-add-circle-o once patternfly/angular-patterfly#510 is addressed
|
|
title: 'No Roster Entries',
|
|
info: 'There are no roster entries to show. If this is unexpected, review the roster preferences in JMRI.',
|
|
helpLink: {
|
|
label: 'For more information please see',
|
|
urlLabel: 'JMRI: DecoderPro User Guide',
|
|
url: '/help/en/html/apps/DecoderPro/Roster.shtml'
|
|
}
|
|
};
|
|
$scope.emptyStateActions = [
|
|
{name: 'Upload Roster Entry', title: 'Upload a roster entry.', actionFn: uploadEntry, type: 'main'}
|
|
];
|
|
$translate(['ROSTER.EMPTY.TITLE', 'ROSTER.EMPTY.INFO', 'ROSTER.EMPTY.HELP.LABEL', 'ROSTER.EMPTY.HELP.URL_LABEL', 'ROSTER.ACTION.UPLOAD.FULLNAME', 'ROSTER.ACTION.UPLOAD.TITLE'])
|
|
.then(function(translations) {
|
|
$scope.emptyStateConfig.title = translations['ROSTER.EMPTY.TITLE'];
|
|
$scope.emptyStateConfig.info = translations['ROSTER.EMPTY.INFO'];
|
|
$scope.emptyStateConfig.helpLink.label = translations['ROSTER.EMPTY.HELP.LABEL'];
|
|
$scope.emptyStateConfig.helpLink.urlLabel = translations['ROSTER.EMPTY.HELP.URL_LABEL'];
|
|
$scope.emptyStateActions[0].name = translations['ROSTER.ACTION.UPLOAD.FULLNAME'];
|
|
$scope.emptyStateActions[0].title = translations['ROSTER.ACTION.UPLOAD.TITLE'];
|
|
}, function(translationIds) {
|
|
$log.error('Unable to translate emptyStateConfig elements');
|
|
});
|
|
|
|
$scope.tableConfig = {
|
|
onCheckBoxChange: handleCheckBoxChange,
|
|
selectionMatchProp: 'name',
|
|
itemsAvailable: true,
|
|
};
|
|
|
|
$scope.dtOptions = {
|
|
dom: 't'
|
|
}
|
|
|
|
//
|
|
// Toolbar
|
|
//
|
|
|
|
// View handling
|
|
|
|
var viewSelected = function(viewId) {
|
|
$scope.viewType = viewId;
|
|
$scope.sortConfig.show = ($scope.viewType === 'tableView' ? false : true);
|
|
};
|
|
|
|
$scope.viewsConfig = {
|
|
views: [pfViewUtils.getListView(), pfViewUtils.getCardView(), pfViewUtils.getTableView()],
|
|
onViewSelect: viewSelected
|
|
};
|
|
|
|
$scope.viewsConfig.currentView = $scope.viewsConfig.views[0].id;
|
|
$scope.viewType = $scope.viewsConfig.currentView;
|
|
|
|
// Filter handling
|
|
|
|
var matchesFilter = function (item, filter) {
|
|
var match = true;
|
|
var re = new RegExp(filter.value, 'i');
|
|
|
|
if (filter.id === 'name') {
|
|
match = item.name.match(re) !== null;
|
|
} else if (filter.id === 'road') {
|
|
match = item.road.match(re) !== null;
|
|
} else if (filter.id === 'number') {
|
|
match = item.number.match(re) !== null;
|
|
} else if (filter.id === 'address') {
|
|
match = item.address === parseInt(filter.value);
|
|
} else if (filter.id === 'owner') {
|
|
match = item.owner.match(re) !== null;
|
|
}
|
|
return match;
|
|
};
|
|
|
|
var matchesFilters = function (item, filters) {
|
|
var matches = true;
|
|
|
|
filters.forEach(function(filter) {
|
|
if (!matchesFilter(item, filter)) {
|
|
matches = false;
|
|
return false;
|
|
}
|
|
});
|
|
return matches;
|
|
};
|
|
|
|
var applyFilters = function (filters) {
|
|
$scope.items = [];
|
|
if (filters && filters.length > 0) {
|
|
$scope.allItems.forEach(function (item) {
|
|
if (matchesFilters(item, filters)) {
|
|
$scope.items.push(item);
|
|
}
|
|
});
|
|
} else {
|
|
$scope.items = $scope.allItems;
|
|
}
|
|
};
|
|
|
|
var filterChange = function(filters) {
|
|
applyFilters(filters);
|
|
$scope.toolbarConfig.filterConfig.resultsCount = $scope.items.length;
|
|
};
|
|
|
|
$scope.filterConfig = {
|
|
fields: [
|
|
{id: 'name', title: 'ID', placeholder: 'Filter by ID...', filterType: 'text'},
|
|
{id: 'address', title: 'DCC Address', placeholder: 'Filter by DCC Address...', filterType: 'text'},
|
|
{id: 'road', title: 'Road Name', placeholder: 'Filter by Road Name...', filterType: 'text'},
|
|
{id: 'number', title: 'Road Number', placeholder: 'Filter by Road Number...', filterType: 'text'},
|
|
{id: 'owner', title: 'Owner', placeholder: 'Filter by Owner...', filterType: 'text'}
|
|
],
|
|
resultsCount: $scope.items.length,
|
|
totalCount: $scope.allItems.length,
|
|
appliedFilters: [],
|
|
onFilterChange: filterChange
|
|
};
|
|
for (var i in $scope.filterConfig.fields) {
|
|
var f = $scope.filterConfig.fields[i];
|
|
$translate('ROSTER.FIELD.' + f.id).then(function(translation) {
|
|
f.title = translation;
|
|
}, function(translationId) {
|
|
$log.error('Unable to translate ' + translationId);
|
|
});
|
|
$translate('ROSTER.FILTER_PLACEHOLDER', f.title, 'filterTitle').then(function(translation) {
|
|
f.placeholder = translation;
|
|
}, function(translationId) {
|
|
$log.error('Unable to translate ' + translationId);
|
|
});
|
|
$scope.filterConfig.fields[i] = f;
|
|
}
|
|
|
|
var compareFn = function(item1, item2) {
|
|
var compValue = 0;
|
|
if ($scope.sortConfig.currentField.id === 'name') {
|
|
compValue = item1.name.localeCompare(item2.name);
|
|
} else if ($scope.sortConfig.currentField.id === 'address') {
|
|
compValue = item1.address - item2.address;
|
|
} else if ($scope.sortConfig.currentField.id === 'road') {
|
|
compValue = item1.road.localeCompare(item2.road);
|
|
} else if ($scope.sortConfig.currentField.id === 'number') {
|
|
compValue = item1.number - item2.number;
|
|
} else if ($scope.sortConfig.currentField.id === 'owner') {
|
|
compValue = item1.owner.localeCompare(item2.owner);
|
|
}
|
|
|
|
if (!$scope.sortConfig.isAscending) {
|
|
compValue = compValue * -1;
|
|
}
|
|
|
|
return compValue;
|
|
};
|
|
|
|
var sortChange = function (sortId, isAscending) {
|
|
$scope.items.sort(compareFn);
|
|
};
|
|
|
|
$scope.sortConfig = {
|
|
fields: [
|
|
{id: 'name', title: 'ID', sortType: 'alpha'},
|
|
{id: 'address', title: 'DCC Address', sortType: 'numeric'},
|
|
{id: 'road', title: 'Road Name', sortType: 'alpha'},
|
|
{id: 'number', title: 'Road Number', sortType: 'numeric'},
|
|
{id: 'owner', title: 'Owner', sortType: 'alpha'}
|
|
],
|
|
onSortChange: sortChange
|
|
};
|
|
for (var i in $scope.sortConfig.fields) {
|
|
var c = $scope.sortConfig.fields[i];
|
|
$translate('ROSTER.FIELD.' + c.id).then(function(translation) {
|
|
c.title = translation;
|
|
}, function(translationId) {
|
|
$log.error('Unable to translate ' + translationId);
|
|
});
|
|
$scope.sortConfig.fields[i] = c;
|
|
}
|
|
|
|
$scope.toolbarConfig = {
|
|
viewsConfig: $scope.viewsConfig,
|
|
filterConfig: $scope.filterConfig,
|
|
sortConfig: $scope.sortConfig
|
|
// actionsConfig: $scope.actionsConfig
|
|
};
|
|
|
|
//
|
|
// Handlers
|
|
//
|
|
|
|
function handleCheckBoxChange (item) {
|
|
var selectedItems = $filter('filter')($scope.allItems, {selected: true});
|
|
if (selectedItems) {
|
|
$scope.toolbarConfig.filterConfig.selectedCount = selectedItems.length;
|
|
}
|
|
}
|
|
|
|
function uploadEntry() {
|
|
|
|
}
|
|
|
|
//
|
|
// Websockets
|
|
//
|
|
|
|
// register a listener for sensors with the jmriWebSocket service
|
|
// this listener determines if a notification needs to be shown or cleared
|
|
// this.webSocket = jmriWebSocket.register();
|
|
|
|
$http.get('/json/roster').then(
|
|
// handle a successful get for the roster
|
|
function(response) {
|
|
if (Array.isArray(response.data)) {
|
|
for (var i in response.data) {
|
|
var entry = response.data[i];
|
|
if (entry.type === 'rosterEntry') {
|
|
$scope.allItems.push(entry.data);
|
|
$scope.toolbarConfig.filterConfig.totalCount = $scope.allItems.length;
|
|
}
|
|
}
|
|
$scope.items = $scope.allItems;
|
|
filterChange($scope.toolbarConfig.filterConfig.appliedFilters);
|
|
} else {
|
|
var entry = response.data;
|
|
if (entry.type === 'rosterEntry') {
|
|
$scope.allItems.push(entry.data);
|
|
$scope.toolbarConfig.filterConfig.totalCount = $scope.allItems.length;
|
|
$scope.items = $scope.allItems;
|
|
filterChange($scope.toolbarConfig.filterConfig.appliedFilters);
|
|
}
|
|
}
|
|
jmriWebSocket.get('roster', {});
|
|
$scope.loading = false;
|
|
},
|
|
// handle a failed get for the roster
|
|
function(response) {
|
|
$log.error('Unable to query JMRI web server for roster.');
|
|
$scope.loading = false;
|
|
}
|
|
);
|
|
});
|