superdesk/superdesk-client-core

View on GitHub
scripts/core/list/list.ts

Summary

Maintainability
B
4 hrs
Test Coverage
import _ from 'lodash';

function ListItemDirectiveFactory() {
    return {
        link: function(scope, element, attrs, controller, $transclude) {
            var itemScope;

            scope.$watch('item', () => {
                destroyItemScope();
                itemScope = scope.$parent.$parent.$new();
                itemScope.item = scope.item;
                itemScope.items = scope.items;
                itemScope.extras = scope.extras;
                itemScope.$index = scope.$index;
                $transclude(itemScope, (clone) => {
                    element.empty();
                    element.append(clone);
                });
            });

            scope.$on('$destroy', destroyItemScope);

            function destroyItemScope() {
                if (itemScope) {
                    itemScope.$destroy();
                }
            }
        },
    };
}

/**
 * @ngdoc module
 * @module superdesk.core.list
 * @name superdesk.core.list
 * @packageName superdesk.core
 * @description The list module provides alternative listing functionalities.
 */
var mod = angular.module('superdesk.core.list', ['superdesk.core.keyboard', 'superdesk.core.services.asset']);

mod.directive('sdListView', ['$location', 'keyboardManager', 'asset', function($location, keyboardManager, asset) {
    return {
        scope: {
            select: '&',
            extras: '=',
            items: '=',
        },
        replace: true,
        transclude: true,
        templateUrl: asset.templateUrl('core/list/views/list-view.html'),
        link: function(scope, elem, attrs) {
            var UP = -1,
                DOWN = 1;

            function fetchSelectedItem(itemId) {
                if (!itemId) {
                    return;
                }

                var match = _.find(scope.items, {_id: itemId});

                if (match) {
                    scope.clickItem(match);
                }
            }

            function move(diff) {
                return function() {
                    if (scope.items) {
                        var index = _.indexOf(scope.items, scope.selected);

                        if (index === -1) { // selected not in current items, select first
                            return scope.clickItem(_.head(scope.items));
                        }

                        var nextIndex = _.max([0, _.min([scope.items.length - 1, index + diff])]);

                        if (nextIndex < 0) {
                            return scope.clickItem(_.last(scope.items));
                        }

                        return scope.clickItem(scope.items[nextIndex]);
                    }
                };
            }

            function onKey(dir, callback) {
                keyboardManager.bind(dir, callback);
            }

            onKey('up', move(UP));
            onKey('left', move(UP));
            onKey('down', move(DOWN));
            onKey('right', move(DOWN));

            scope.clickItem = function(item, $event) {
                scope.selected = item;
                scope.select({item: item});
                if ($event) {
                    $event.stopPropagation();
                }
            };

            scope.$watch('items', () => {
                fetchSelectedItem($location.search()._id);
                elem.find('.list-view').focus();
            });
        },
    };
}]);

mod.directive('sdSearchbar', ['$location', 'asset', function($location, asset) {
    return {
        scope: true,
        templateUrl: asset.templateUrl('core/list/views/searchbar.html'),
        link: function(scope, elem) {
            var input = elem.find('#search-input');

            scope.q = $location.search().q || null;
            scope.flags = {extended: !!scope.q};

            scope.search = function() {
                $location.search('q', scope.q || null);
                $location.search('page', null);
            };

            scope.close = function() {
                scope.q = null;
                scope.search();
                input.focus();
            };
        },
    };
}]);

mod.directive('sdListItem', ListItemDirectiveFactory);

/**
 * sdPagination inserts pagination controls for a given data set.
 *
 * Usage:
 * <div sd-pagination data-items="users" data-limit="maxResults"></div>
 *
 * Params:
 * @items {object} Item container as received from server, with _items and _meta.
 * @limit {number} Number of items per page.
 */
mod.directive('sdPagination', ['$location', 'asset', function($location, asset) {
    return {
        template: require('./views/sdPagination.html'),
        scope: {
            items: '=',
        },
        link: function(scope, element, attrs) {
            const SIZE = 25;

            scope.pgsizes = [SIZE, SIZE * 2, SIZE * 4];

            scope.$watch('items._meta', (meta) => {
                scope.total = 0;
                if (meta) {
                    scope.total = meta.total;
                    scope.page = Number($location.search().page) || 1;
                    scope.limit = Number(localStorage.getItem('pagesize'))
                        || Number($location.search().max_results) || SIZE;
                    scope.lastPage = scope.limit ? Math.ceil(scope.total / scope.limit) : scope.page;
                    scope.from = (scope.page - 1) * scope.limit + 1;
                    scope.to = Math.min(scope.total, scope.from + scope.limit - 1);
                    if (scope.pageChanged === true) {
                        scrollTop();
                        scope.pageChanged = null;
                    }
                }
            });

            /**
             * Set page
             *
             * @param {integer} page
             */
            scope.setPage = function(page) {
                $location.search('page', page > 1 ? page : null);
                scope.pageChanged = true;
            };

            function scrollTop() {
                window.scrollTo(0, 0);
            }
            /*
            * Set custom page size limit
            *@param {integer} page
            */
            scope.setLimit = function(pagesize) {
                localStorage.setItem('pagesize', pagesize);
                scope.setPage(0);
                $location.search('max_results', !_.isNil(pagesize) ? pagesize : SIZE);
            };
        },
    };
}]);

// Alternative sdPagination, doesn't use $location.
// Should replace sdPagination.
mod.directive('sdPaginationAlt', ['asset', function(asset) {
    return {
        templateUrl: asset.templateUrl('core/list/views/sdPaginationAlt.html'),
        scope: {
            page: '=',
            maxPage: '=',
        },
    };
}]);

export default mod;