UNPKG

pix-angular-filebrowser

Version:

File browser for Web2

289 lines (243 loc) 11 kB
var _ = require("lodash"); function FileBrowserService( $http, $q, $translate, $log, APP_SETTINGS, LOADING_OBJECT, PIXFolder, ItemsCollectionModel, NotificationsService, SessionService) { // PRIVATE variables var items = []; var isInitialized = false; var root; /** * Sets the items list in place so our scope reference stays intact * * @param val {array} Array of items to set the items array to */ function setItems(val) { items.length = 0; addItems(val); } function addItems(val, index) { index = index || 0; var args = [index, 0].concat(val); Array.prototype.splice.apply(items, args); } function replaceItems(val, index) { index = index || 0; var args = [index, val.length].concat(val); Array.prototype.splice.apply(items, args); } /** * Expands a given object and places it in the proper place of the data array. * * @param item {PIXContainer} the item to expand */ function expand(item) { // set the parent state to loading. // call expand on the item to load the initial set of data return item.expand() .then(function() { // set up the attributes that are needed for the children (tree depth and parent) var childAttrs = { '$$level': (item.$$level + 1) || 1, '$$parentId': item.id } // grab the index of the parent var parentIndex = items.indexOf(item); // stores the current index our list is at var index = 0; // create a copy of the data that has come in so we can safely manipuate the array var results = _.clone(item.contentsCollectionModel.collection); // walk through the list of all children for this item (both currently loaded and that to be loaded) var children = _.map(Array(item.contentsCollectionModel.info.total), function() { // if we still have data from the initial load use it if (results.length > 0) { index++; return _.defaults(results.shift(), childAttrs); } // otherwise add a loading object else { return _.defaults({ id: _.uniqueId('tmpFile') }, childAttrs, LOADING_OBJECT) } }); // add the children to the grid data array addItems(children, parentIndex + 1); /** * Checks if we have the entire set of children and if not kicks off another request * * @returns {boolean} whether or not more data is available */ function loadMoreIfNeeded() { // if there are more items we need to request if (item.contentsCollectionModel.cacheSettings.hasOutstandingRecords) { // set our page size to the max item.contentsCollectionModel.cacheSettings.pageSize = 500; //requests the next page of data item.contentsCollectionModel.cache.getNextPage().then(onNextPage); return true; } return false; } /** * The callback for a successful load of the next page of data */ function onNextPage() { // grab the grid index of the last item we added from our children collection var scopeIndex = items.indexOf(item.contentsCollectionModel.collection[index - 1]) + 1; // loop through the new items in the collection and add our tree specific attributes var newItems = _.map(item.contentsCollectionModel.collection.slice(index), function(child) { return _.defaults(child, childAttrs); }); // set the index pointer to the end of the child collection index = item.contentsCollectionModel.collection.length; // splice our new data onto the main grid data array using the scopeIndex we calculated replaceItems(newItems, scopeIndex); // see if we need to load more loadMoreIfNeeded(); } // try to load page 2 of data (and start the lazy load chain) loadMoreIfNeeded(); }); } /** * Collapses an item by removing it's children from the grid data array * * @param item {PIXContainer} the item to collapse */ function collapse(item) { // grab the level of the parent var parentLevel = item.$$level || 0; // two variables to track the indexes of where the children start and end var index; var startIndex; // grab the index of the first child and stash it for latter index = startIndex = items.indexOf(item) + 1; // grab the first child item var nextItem = items[index]; // walk through the list until we hit a sibling of the parent (or the end of the list) while (nextItem && nextItem.$$level > parentLevel) { // incr our index to keep track of the end index++; // if this child is expanded, collapse it if (nextItem.$$expanded) { nextItem.$$expanded = false; } // grab the next item and go back around nextItem = items[index]; } // remove our children using our calculated indexes items.splice(startIndex, index - startIndex); } /** * Sorts the internal items list * * @param accessors {function[]} an array of functions to access the data for the sort * @param directions {boolean[]} an array of sort directions for each column */ function sort(accessors, directions) { // build an object of rows group by their parent var hierarchy = _.groupBy(items, function(item) { return item.$$parentId || 'root'; }); // first sort by the root elements var sorted = _.sortByOrder(hierarchy.root, accessors, directions); // remove the root from our list delete hierarchy.root; // deal with the children for (var parentId in hierarchy) { // grab the list of children under the current parent var children = hierarchy[parentId]; // sort the child list children = _.sortByOrder(children, accessors, directions); // find our parent in the currently sorted list var parentIndex = _.findIndex(sorted, function(item) { return item.id === parentId; }); // add our children after their parent var args = [parentIndex + 1, 0].concat(children); Array.prototype.splice.apply(sorted, args) } setItems(sorted); } /** * Initialize the data if the service has not already been initialized * @returns {*} */ function init() { return $q(function(resolve, reject) { if (isInitialized) { resolve(); } else { SessionService .whenProjectOrSessionEnded .then(destroy); $http.get(APP_SETTINGS.HOST + '/' + APP_SETTINGS.API_ROOT + '/folders/root') .success(function(data) { // hydrate the server data into a PIXFolder object root = new PIXFolder(new ItemsCollectionModel()); root.populateSelf(data); // set our page size to the maximum root.getCollectionModel().cacheSettings.pageSize = 500; // expand root folder to get it's children root.expand() .then(function() { setItems(root.contentsCollectionModel.collection); resolve(); }) .catch(function() { NotificationsService.flashWarnings($translate('FileBrowser.Error.Expand', root)); reject(); }); }) .error(function() { NotificationsService.flashWarnings($translate('FileBrowser.Error.Root', root)); reject(); }); } }); } /** * Clear the service cache */ function destroy() { $log.debug('destroying file browser cache: session ended or project changed'); root.collapse(true); root = null; items = []; isInitialized = false; } // setup our public read-only properties Object.defineProperties(this, { items : { get: function() { return items; } }, expand: { value: expand, writable: false }, collapse: { value: collapse, writable: false }, sort: { value: sort, writable: false }, init: { value: init, writable: false } }); } module.exports = angular .module('PIX.FileBrowser.Service', []) .constant('LOADING_OBJECT', { viewData: { fields: { name: 'Loading' } } }) .service('FileBrowserService', FileBrowserService);