UNPKG

pix-angular-filebrowser

Version:

File browser for Web2

371 lines (327 loc) 12.5 kB
var _ = require("lodash"); function FileBrowserController( $scope, $translate, $q, FileBrowserService, ItemsCollectionModel, NotificationsService, uiGridConstants, PIXFolder, $templateCache, hotkeys) { // our grid api var gridApi; var self = this; // register our templates $templateCache.put('pix.filebrowser.empty.html', require('../template/pix.filebrowser.empty.html')); $templateCache.put('pix.filebrowser.loading.html', require('../template/pix.filebrowser.loading.html')); $templateCache.put('pix.filebrowser.toolbar.html', require('../template/pix.filebrowser.toolbar.html')); // and array to hold the currently selected items self.selection = []; // a way to keep track of our selection direction for keyboard hotkeys var lastSelectionDirection = 0; // set the loading state to true self.isLoading = true; // set up our grid options self.gridOptions = { // sorting options enableSorting: true, useExternalSorting: true, // selection options enableRowSelection: true, // enableSelectAll: true, enableSelectionBatchEvent: true, enableRowHeaderSelection: false, multiSelect: true, modifierKeysToMultiSelect: true, // core setup columnDefs: [], rowTemplate: require('../template/pix.filebrowser.row.html'), data: FileBrowserService.items, excessRows: 50, onRegisterApi: onRegisterApi, enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER }; // setup our columns, first translate the header strings $q.all({ name: $translate('FileBrowser.Column.Name'), description: $translate('FileBrowser.Column.Description'), createdOn: $translate('FileBrowser.Column.CreatedOn'), createdBy: $translate('FileBrowser.Column.CreatedBy'), modifiedOn: $translate('FileBrowser.Column.ModifiedOn'), modifiedBy: $translate('FileBrowser.Column.ModifiedBy') }) .then(function(names) { self.gridOptions.columnDefs = [ { name: names.name, field: 'viewData.fields.name', enableColumnMenu: false, cellTemplate: require('../template/pix.filebrowser.name.html') }, { name: names.description, field: 'viewData.fields.description', enableColumnMenu: false, cellClass: 'text-muted' }, { name: names.createdOn, field: 'viewData.fields.created_on', enableColumnMenu: false, cellTemplate: require('../template/pix.filebrowser.date.html'), cellClass: 'text-muted' }, { name: names.createdBy, field: 'viewData.createdBy.viewData.label', enableColumnMenu: false, cellClass: 'text-muted' }, { displayName: names.modifiedOn, field: 'viewData.fields.modified_on', enableColumnMenu: false, cellTemplate: require('../template/pix.filebrowser.date.html'), cellClass: 'text-muted' }, { displayName: names.modifiedBy, field: 'viewData.modifiedBy.viewData.label', enableColumnMenu: false, cellClass: 'text-muted' } ]}); /** * A callback which is called when the grid API is ready * * @param gridApi {object} an instance of the ui-grid api */ function onRegisterApi(api) { // stash the grid API for later gridApi = api; // register our selection and sort changed handler gridApi.selection.on.rowSelectionChanged($scope, onSelectionChanged); gridApi.selection.on.rowSelectionChangedBatch($scope, onSelectionChanged); gridApi.core.on.sortChanged($scope, onSortChanged); } /** * The selection changed handler */ function onSelectionChanged() { // update our selection array when the selection has changed self.selection = gridApi.selection.getSelectedRows(); } /** * The sort changed handler * * @param grid {object} an instance of the grid * @param sortColumns {array} an array of columns to sort by */ function onSortChanged(grid, sortColumns) { // build out our accessors array (an array of functions that return the cell value for a given column/row var accessors = []; var directions = []; _.each(sortColumns, function(col) { accessors.push(function(item) { return _.result(item, col.field); }) directions.push(col.sort.direction === 'asc'); }); FileBrowserService.sort(accessors, directions); } /** * Moves the current selection or appends to it (this is used for keyboard shortcuts) * * @param direction 1 means forward, -1 means backwards * @param append if true selected items will be appended otherwise they will be replaced */ function moveSelection(direction, append) { if (self.selection.length === 0) { gridApi.selection.selectRowByVisibleIndex(0); } else { // if we are in append mode and we just changed direction, we should unset what we just set if (append && self.selection.length > 1 && lastSelectionDirection !== 0 && lastSelectionDirection != direction) { // grab the end item and unselect it var end = self.selection[direction > 0 ? 0 : self.selection.length -1]; gridApi.selection.unSelectRow(end); return; } else { // otherwise just keep track of our direction lastSelectionDirection = direction; } // grab the first or last item depending on the direction we are moving var item = self.selection[direction < 0 ? 0 : self.selection.length -1]; // if we are not appending unselect everything if (!append) { _.each(self.selection, gridApi.selection.unSelectRow); } // get the next or prev item index var index = _.findIndex(FileBrowserService.items, function(i) { return i.id === item.id; }); index += direction; // keep index in range index = Math.min(Math.max(index, 0), FileBrowserService.items.length-1); var nextItem = FileBrowserService.items[index]; // select the row gridApi.selection.selectRow(nextItem); } } // set up our hotkeys hotkeys.bindTo($scope) .add({ combo: 'up', description: 'Move up', callback: function() { moveSelection(-1, false); } }) .add({ combo: 'shift+up', description: "Move down", callback: function() { moveSelection(-1, true); } }) .add({ combo: 'down', description: 'Move down', callback: function() { moveSelection(1, false); } }) .add({ combo: 'shift+down', description: 'Move down', callback: function() { moveSelection(1, true); } }) .add({ combo: 'enter', description: "Open in viewer", callback: function() { openInViewer(); } }) .add({ combo: 'left', description: 'collapse', callback: function() { _.each(self.selection, function(item) { if (item.isContainer) { self.collapse(item); } }) } }) .add({ combo: 'right', description: 'collapse', callback: function() { _.each(self.selection, function(item) { if (item.isContainer) { self.expand(item); } }) } }); // add our expand function to the scope self.expand = function(item, $event) { // stop the mouse event (an expand doesn't mean we are selecting that item) if ($event) { $event.stopImmediatePropagation(); } // set the loading state item.$$loading = true; // call expand on our service FileBrowserService.expand(item) .then(function() { // on success set expanded to true item.$$expanded = true; }, function() { // on failure flash an error NotificationsService.flashWarnings($translate('FileBrowser.Error.Expand', item)); item.$$expanded = false; }) .finally(function() { // either way set our loading state to false item.$$loading = false; }) }; // add our collapse function to the scope self.collapse = function(item, $event) { // stop the event propagation (collapse does not mean selection) if ($event) { $event.stopImmediatePropagation(); } FileBrowserService.collapse(item); item.$$expanded = false; }; /** * Open an item (or the current selection in the viewer) * * @param item {PIXItem} the item open. If no item is passed, we'll use the current selection */ function openInViewer(item) { // if we have an item wrap it in an array, otherwise just grab the selection var collection = item ? [item] : self.selection; // create a new ItemsCollectionModel using our selected items var collectionModel = new ItemsCollectionModel(); collectionModel.initializeFromExistingData(collection); // dispatch an event with our collection to open the viewer $scope.emitBusEvent('PIX.VIEWER.OPEN', { items: collectionModel, current: collectionModel.collection[0], skipUnpackCurrent: true }); } // add open in viewer to the scope self.openInViewer = openInViewer; /** * Shares the currently selected item(s) */ function share() { // create a collection from our selection var collectionModel = new ItemsCollectionModel(); collectionModel.initializeFromExistingData(self.selection); // set the attachments to our collection and show the message dialog self.sendAttachments = collectionModel; self.sendVisible = true; } self.share = share; // register a listener for the share close event and upon i hide the message-send directive $scope.onBusEvent('PIX.SHARE.CLOSE', function() { self.sendVisible = false; }); self.isLoading = true; FileBrowserService.init().then(function() { /** * Check if the item is a container and already expanded. If it is, update the UI. * @param item */ function checkDeepExpansion(item) { if (item.contentsCollectionModel && item.$$expanded) { FileBrowserService.expand(item); item.contentsCollectionModel.collection.forEach(function(innerItem) { checkDeepExpansion(innerItem); }); } } self.isLoading = false; FileBrowserService.items.forEach(function(item) { checkDeepExpansion(item); }); }); Object.defineProperty(self, 'canShare', { get: function () { if (!self.selection || self.selection.length === 0) { return false; } return _.every(self.selection, function (item) { return item.viewData.permissions.canSend && !(item instanceof PIXFolder); }); } }); } module.exports = angular .module('PIX.FileBrowser.Controller', [ 'angularMoment', 'cfp.hotkeys' ]) .controller('FileBrowserController', FileBrowserController);