246 lines
7.7 KiB
JavaScript
246 lines
7.7 KiB
JavaScript
/*
|
|
* (c) Copyright 2015 Hewlett-Packard Development Company, L.P.
|
|
* Copyright 2015 IBM Corp.
|
|
*
|
|
* Licensed 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';
|
|
|
|
angular
|
|
.module('horizon.framework.widgets.transfer-table')
|
|
.controller('transferTableController', TransferTableController);
|
|
|
|
TransferTableController.$inject = [
|
|
'$scope',
|
|
'$timeout',
|
|
'$parse',
|
|
'$attrs',
|
|
'$log',
|
|
'horizon.framework.widgets.transfer-table.events',
|
|
'horizon.framework.widgets.transfer-table.helpText',
|
|
'horizon.framework.widgets.transfer-table.limits',
|
|
'horizon.framework.util.q.extensions'
|
|
];
|
|
|
|
/**
|
|
* @ngdoc controller
|
|
* @name horizon.framework.widgets.transfer-table.controller:transferTableController
|
|
* @description
|
|
* The `transferTableController` controller provides functions for allocating
|
|
* and deallocating to and from the 'allocated' array, respectively.
|
|
* This controller can be accessed through `trCtrl`.
|
|
*
|
|
* The data model assumes four arrays: allocated, displayedAllocated,
|
|
* available, and displayedAvailable. Smart-Table requires additional
|
|
* 'displayed' arrays for sorting and re-ordering. Of these four arrays, only
|
|
* allocated is required. The remaining arrays are populated for you if they
|
|
* are not present.
|
|
*
|
|
* @example
|
|
* ```
|
|
* var availableItems = [
|
|
* { id: 'u1', username: 'User 1', disabled: true, warnings: { username: 'Invalid!' } },
|
|
* { id: 'u2', username: 'User 2', disabled: true, warningMessage: 'Invalid!' },
|
|
* { id: 'u3', username: 'User 3' }
|
|
* ];
|
|
* $scope.model = { available: availableItems };
|
|
* $scope.limits = { maxAllocation: -1 };
|
|
* ```
|
|
* For usage example, see the transfer-table.example.html file.
|
|
*/
|
|
function TransferTableController(
|
|
$scope,
|
|
$timeout,
|
|
$parse,
|
|
$attrs,
|
|
$log,
|
|
events,
|
|
helpText,
|
|
limits,
|
|
qExtensions
|
|
) {
|
|
var trModel = $parse($attrs.trModel)($scope);
|
|
var trHelpText = $parse($attrs.helpText)($scope);
|
|
var trLimits = $parse($attrs.limits)($scope);
|
|
|
|
var ctrl = this;
|
|
ctrl.allocate = allocate;
|
|
ctrl.deallocate = deallocate;
|
|
ctrl.itemActions = getItemActions();
|
|
ctrl.toggleView = toggleView;
|
|
ctrl.updateAllocated = updateAllocated;
|
|
ctrl.numAllocated = numAllocated;
|
|
|
|
ctrl.helpText = angular.extend({}, helpText, trHelpText);
|
|
ctrl.limits = angular.extend({}, limits, trLimits);
|
|
ctrl.numAvailable = numAvailable;
|
|
ctrl.views = { allocated: true, available: true };
|
|
|
|
// if available transfer table is updated dynamically (e.g. based on a dropdown
|
|
// selection like in Launch Instance Boot Source), we need to update our data accordingly
|
|
var tablesChangedWatcher = $scope.$on(events.TABLES_CHANGED, onTablesChanged);
|
|
|
|
$scope.$on('$destroy', function () {
|
|
tablesChangedWatcher();
|
|
});
|
|
|
|
init(trModel);
|
|
|
|
//////////
|
|
|
|
function getItemActions() {
|
|
return [{
|
|
template: {
|
|
text: '',
|
|
actionClasses: 'fa fa-arrow-up'
|
|
},
|
|
service: {
|
|
allowed: function allocationAllowed(item) {
|
|
var allocatable = item && !ctrl.allocatedIds[item.id];
|
|
return qExtensions.booleanAsPromise(allocatable);
|
|
},
|
|
perform: function performAllocation(item) {
|
|
allocate(item);
|
|
return qExtensions.booleanAsPromise(true);
|
|
}
|
|
}
|
|
}, {
|
|
template: {
|
|
text: '',
|
|
actionClasses: 'fa fa-arrow-down'
|
|
},
|
|
service: {
|
|
allowed: function deallocationAllowed(item) {
|
|
var deallocatable = item && ctrl.allocatedIds[item.id];
|
|
return qExtensions.booleanAsPromise(deallocatable);
|
|
},
|
|
perform: function performDeallocation(item) {
|
|
deallocate(item);
|
|
return qExtensions.booleanAsPromise(true);
|
|
}
|
|
}
|
|
}];
|
|
}
|
|
|
|
function init(model) {
|
|
|
|
if (!angular.isArray(model.available)) {
|
|
$log.error('Available is not an array.');
|
|
}
|
|
|
|
if (model.allocated && !angular.isArray(model.allocated)) {
|
|
$log.error('Allocated is not an array.');
|
|
}
|
|
|
|
ctrl.available = {
|
|
sourceItems: model.available,
|
|
displayedItems: model.displayedAvailable ? model.displayedAvailable : []
|
|
};
|
|
ctrl.allocated = {
|
|
sourceItems: model.allocated ? model.allocated : [],
|
|
displayedItems: model.displayedAllocated ? model.displayedAllocated : []
|
|
};
|
|
|
|
ctrl.allocatedIds = {};
|
|
markAllocatedItems();
|
|
|
|
$scope.$watchCollection(getAllocated, markAllocatedItems);
|
|
}
|
|
|
|
function getAllocated() {
|
|
return ctrl.allocated.sourceItems;
|
|
}
|
|
|
|
function markAllocatedItems() {
|
|
angular.forEach(ctrl.allocated.sourceItems, function flag(item) {
|
|
ctrl.allocatedIds[item.id] = true;
|
|
});
|
|
}
|
|
|
|
function allocate(item) {
|
|
|
|
// we currently don't have to check for item uniqueness
|
|
// because we are using the ng-repeat track by
|
|
|
|
// Add to allocated only if limit not reached
|
|
if (ctrl.limits.maxAllocation < 0 ||
|
|
ctrl.limits.maxAllocation > ctrl.allocated.sourceItems.length) {
|
|
ctrl.allocated.sourceItems.push(item);
|
|
ctrl.allocatedIds[item.id] = true;
|
|
// Swap out items if only one allocation allowed
|
|
} else if (ctrl.limits.maxAllocation === 1) {
|
|
var temp = ctrl.allocated.sourceItems.pop();
|
|
delete ctrl.allocatedIds[temp.id];
|
|
// When swapping out, Smart-Table $watch is
|
|
// not detecting change so timeout is used as workaround.
|
|
$timeout(function() {
|
|
ctrl.allocated.sourceItems.push(item);
|
|
ctrl.allocatedIds[item.id] = true;
|
|
$scope.$apply();
|
|
}, 0, false);
|
|
}
|
|
}
|
|
|
|
// move item from allocated to available
|
|
function deallocate(item) {
|
|
var index = ctrl.allocated.sourceItems.indexOf(item);
|
|
if (index >= 0) {
|
|
ctrl.allocated.sourceItems.splice(index, 1);
|
|
delete ctrl.allocatedIds[item.id];
|
|
}
|
|
}
|
|
|
|
// update allocated when users re-order via drag-and-drop
|
|
function updateAllocated(event, item, orderedItems) {
|
|
ctrl.allocated.sourceItems.splice(0, ctrl.allocated.sourceItems.length);
|
|
Array.prototype.push.apply(ctrl.allocated.sourceItems, orderedItems);
|
|
}
|
|
|
|
function onTablesChanged(e, args) {
|
|
if (args.data.available) {
|
|
ctrl.available.sourceItems = args.data.available;
|
|
}
|
|
if (args.data.displayedAvailable) {
|
|
ctrl.available.displayedItems = args.data.displayedAvailable;
|
|
}
|
|
if (args.data.allocated) {
|
|
ctrl.allocated.sourceItems = args.data.allocated;
|
|
ctrl.allocatedIds = {};
|
|
ctrl.allocated.sourceItems.forEach(function(item) {
|
|
ctrl.allocatedIds[item.id] = true;
|
|
});
|
|
}
|
|
if (args.data.displayedAllocated) {
|
|
ctrl.allocated.displayedItems = args.data.displayedAllocated;
|
|
}
|
|
}
|
|
|
|
/////////////
|
|
|
|
function toggleView(view) {
|
|
ctrl.views[view] = !ctrl.views[view];
|
|
}
|
|
|
|
function numAllocated() {
|
|
return ctrl.allocated.sourceItems.length;
|
|
}
|
|
|
|
function numAvailable() {
|
|
return ctrl.available.sourceItems.length - ctrl.allocated.sourceItems.length;
|
|
}
|
|
}
|
|
|
|
})();
|