UNPKG

linagora-rse

Version:
349 lines (272 loc) 9.73 kB
'use strict'; angular.module('esn.box-overlay', [ 'esn.constants', 'ng.deviceDetector', 'esn.i18n' ]) .constant('ESN_BOX_OVERLAY_EVENTS', { RESIZED: 'esn:box-overlay:resized' }) .service('boxOverlayOpener', function($boxOverlay) { function open(options) { var overlay = $boxOverlay(options); if (angular.isDefined(overlay)) { overlay.show(); } } return { open: open }; }) .service('boxOverlayService', function($rootScope, notificationFactory, MAX_BOX_COUNT) { var boxScopes = []; function count() { return boxScopes.length; } function spaceLeftOnScreen() { return count() < MAX_BOX_COUNT; } function onlyOneSpaceLeftOnScreen() { return count() === (MAX_BOX_COUNT - 1); } function isBoxAlreadyOpened(scope) { return scope.id && boxScopes.some(function(element) { return element.id === scope.id; }); } return { spaceLeftOnScreen: spaceLeftOnScreen, addBox: function(scope) { if (isBoxAlreadyOpened(scope)) { return false; } if (!spaceLeftOnScreen()) { notificationFactory.weakError('', 'Cannot open more than ' + MAX_BOX_COUNT + ' windows. Please close one and try again'); return false; } boxScopes.push(scope); if (!spaceLeftOnScreen()) { $rootScope.$broadcast('box-overlay:no-space-left-on-screen'); } return true; }, removeBox: function(scope) { if (count() > 0) { var index = boxScopes.indexOf(scope); if (index > -1) { boxScopes.splice(index, 1); if (onlyOneSpaceLeftOnScreen()) { $rootScope.$broadcast('box-overlay:space-left-on-screen'); } } } }, maximizedBoxExists: function() { return boxScopes.some(function(scope) { return scope.isMaximized() || scope.isFullScreen(); }); }, minimizeOthers: function(me) { return boxScopes .filter(function(scope) { return scope !== me; }) .forEach(function(scope) { scope.$minimize(); }); } }; }) .factory('StateManager', function() { function StateManager() { this.state = StateManager.STATES.NORMAL; this.callbacks = []; } StateManager.STATES = { NORMAL: 'NORMAL', MINIMIZED: 'MINIMIZED', MAXIMIZED: 'MAXIMIZED', FULL_SCREEN: 'FULL_SCREEN' }; StateManager.prototype.toggle = function(newState) { this.state = this.state === newState ? StateManager.STATES.NORMAL : newState; this.callbacks.forEach(function(callback) {callback();}); }; StateManager.prototype.registerHandler = function(callback) { callback && typeof callback === 'function' && this.callbacks.push(callback); }; return StateManager; }) .provider('$boxOverlay', function() { this.$get = function($window, $rootScope, $compile, $templateCache, $http, $timeout, $q, boxOverlayService, StateManager, deviceDetector, DEVICES, ESN_BOX_OVERLAY_EVENTS) { var boxTemplateUrl = '/views/modules/box-overlay/template.html'; function container() { return angular.element('body .box-overlay-container'); } function ensureContainerElementExists() { if (container().length === 0) { angular.element($window.document.body).append($compile('<box-overlay-container></box-overlay-container>')($rootScope.$new())); } } function setAutoMaximizeForIPAD(box, scope) { if (deviceDetector.device !== DEVICES.I_PAD) { return; } scope.$toggleMaximized(); box .on('focus', 'input, tags-input', function() { $window.scrollTo(0, 0); // Avoid shake effect }) .on('touchstart', 'input, textarea, tags-input', function() { if (!scope.isMaximized()) { scope.$apply(scope.$toggleMaximized); } }); } function removeContainerElementIfPossible() { var element = container(); if (element.children().length === 0) { element.remove(); } } function BoxOverlayFactory(config) { var boxElement, scope = angular.extend($rootScope.$new(), config), $boxOverlay = { $scope: scope }, stateManager = new StateManager(); function initialize() { stateManager.registerHandler(notifyComponentsAboutResizeRequest); } function notifyComponentsAboutResizeRequest() { if (!scope.isMinimized()) { $rootScope.$broadcast(ESN_BOX_OVERLAY_EVENTS.RESIZED); } } $boxOverlay.$isShown = scope.$isShown = false; scope.allowMinimize = _allow.bind(null, StateManager.STATES.MINIMIZED); scope.allowMaximize = _allow.bind(null, StateManager.STATES.MAXIMIZED); scope.allowFullScreen = _allow.bind(null, StateManager.STATES.FULL_SCREEN); function _allow(state) { return !config.allowedStates || config.allowedStates.indexOf(state) > -1; } scope.closeable = function() { return !angular.isDefined(config.closeable) || config.closeable; }; scope.isMinimized = _is.bind(null, StateManager.STATES.MINIMIZED); scope.isMaximized = _is.bind(null, StateManager.STATES.MAXIMIZED); scope.isFullScreen = _is.bind(null, StateManager.STATES.FULL_SCREEN); function _is(state) { return stateManager.state === state; } scope.$minimize = function() { stateManager.state = StateManager.STATES.MINIMIZED; }; scope.$toggleMinimized = _toggle.bind(null, StateManager.STATES.MINIMIZED); scope.$toggleMaximized = _toggle.bind(null, StateManager.STATES.MAXIMIZED); scope.$toggleFullScreen = _toggle.bind(null, StateManager.STATES.FULL_SCREEN); function _toggle(state) { stateManager.toggle(state); if (scope.isMaximized() || scope.isFullScreen()) { boxOverlayService.minimizeOthers(scope); } } scope.$show = nextTick('show'); scope.$hide = nextTick('hide'); $boxOverlay.onTryClose = $q.when; scope.$onTryClose = function(callback) { $boxOverlay.onTryClose = angular.isFunction(callback) ? callback : $boxOverlay.onTryClose; }; scope.$close = function() { $boxOverlay.hide(); return $boxOverlay.onTryClose().then(scope.$forceClose); }; scope.$forceClose = nextTick('destroy'); function nextTick(action) { return function() { $timeout(function() { $boxOverlay[action](); }, 0); }; } scope.$updateTitle = function(title) { $boxOverlay.updateTitle(title); }; $boxOverlay.show = function() { if ($boxOverlay.$isShown || !boxOverlayService.addBox(scope)) { return; } $boxOverlay.$isShown = scope.$isShown = true; ensureContainerElementExists(); fetchTemplate(boxTemplateUrl).then(function(template) { boxElement = $boxOverlay.$element = $compile(template)(scope); boxElement.addClass('box-overlay-open'); container().append(boxElement); setAutoMaximizeForIPAD(boxElement, scope); if (config.initialState) { _toggle(config.initialState); } $timeout(function() { var toFocus = boxElement.find('[autofocus]')[0]; if (toFocus) { toFocus.focus(); } }); }); }; $boxOverlay.hide = function() { if (!$boxOverlay.$isShown) { return; } $boxOverlay.$isShown = scope.$isShown = false; boxOverlayService.removeBox(scope); if (boxElement) { boxElement.remove(); boxElement = null; } removeContainerElementIfPossible(); }; $boxOverlay.destroy = function() { $boxOverlay.hide(); scope.$destroy(); }; $boxOverlay.updateTitle = function(title) { scope.title = title || config.title; }; initialize(); return $boxOverlay; } function fetchTemplate(template) { return $http.get(template, {cache: $templateCache}).then(function(res) { return res.data; }); } return BoxOverlayFactory; }; }) .directive('boxOverlay', function(boxOverlayOpener) { return { restrict: 'A', scope: { boxId: '@', boxTitle: '@', boxTemplateUrl: '@', boxInitialState: '@', boxCloseable: '=', boxAllowedStates: '=' }, link: function(scope, element) { element.on('click', function() { boxOverlayOpener.open({ id: scope.boxId, title: scope.boxTitle, templateUrl: scope.boxTemplateUrl, initialState: scope.boxInitialState, closeable: scope.boxCloseable, allowedStates: scope.boxAllowedStates }); }); } }; }) .directive('boxOverlayContainer', function(boxOverlayService) { return { restrict: 'AE', replace: true, template: '<div class="box-overlay-container" ng-class="{ \'maximized\': isMaximized() }"></div>', link: function($scope) { $scope.isMaximized = boxOverlayService.maximizedBoxExists; } }; });