From e6f1261f2f3342e3d447df810e01a83fdb664fd3 Mon Sep 17 00:00:00 2001 From: Zarlex Date: Mon, 15 Oct 2018 17:47:16 +0200 Subject: [PATCH 1/5] Add loading service where loading processes can register --- src/mw-utils/mw_utils.js | 1 + src/mw-utils/services/mw_loading_service.js | 142 ++++++++++++++++++ .../services/mw_loading_service_test.js | 92 ++++++++++++ 3 files changed, 235 insertions(+) create mode 100644 src/mw-utils/services/mw_loading_service.js create mode 100644 src/mw-utils/services/mw_loading_service_test.js diff --git a/src/mw-utils/mw_utils.js b/src/mw-utils/mw_utils.js index ee5e6415..e200d545 100644 --- a/src/mw-utils/mw_utils.js +++ b/src/mw-utils/mw_utils.js @@ -26,6 +26,7 @@ angular.module('mwUI.Utils', ['mwUI.i18n','mwUI.Modal']); // @include ./services/mw_bootstrap_breakpoint.js // @include ./services/mw_browser_title_handler.js // @include ./services/mw_callback_handler.js +// @include ./services/mw_loading_service.js // @include ./services/mw_scheduler.js // @include ./services/mw_url_storage.js // @include ./services/mw_runtime_storage.js diff --git a/src/mw-utils/services/mw_loading_service.js b/src/mw-utils/services/mw_loading_service.js new file mode 100644 index 00000000..d3ccb81e --- /dev/null +++ b/src/mw-utils/services/mw_loading_service.js @@ -0,0 +1,142 @@ +'use strict'; + +angular.module('mwUI.Utils') + +/** + * @ngdoc service + * @name mwUI.Utils.service:Loading + * + * @description + * This service manages loading processes. It can be used e.g. by a httpInterceptor to register a loading process + */ + .service('Loading', function ($timeout) { + + var itemsToLoad = 0, + itemsAlreadyLoaded = 0, + loading = false, + keysToLoad = {}, + waitUntilDoneTimout, + doneCallbacks = [], + startCallbacks = []; + + var reset = function () { + itemsToLoad = 0; + itemsAlreadyLoaded = 0; + }; + + var executeCallbacks = function (cbs, args, scope) { + scope = scope || this; + cbs.forEach(function (cb) { + cb.apply(scope, args); + }); + }; + + var setToDone = function () { + if (waitUntilDoneTimout) { + $timeout.cancel(waitUntilDoneTimout); + } + waitUntilDoneTimout = $timeout(function () { + loading = false; + executeCallbacks(doneCallbacks); + reset(); + }, 100); + }; + + var registerCallback = function (array, callback) { + if (typeof callback === 'function') { + array.push(callback); + } else { + throw new Error('Callback has to be a function'); + } + }; + + /** + * @ngdoc function + * @name start + * @methodOf mwUI.Utils.service:Loading + * @description + * Starts a loading process. When a key is passed a specified loading process is registered otherwise + * a global loading process is registered + * @param {String} key a unique key to start the loading process + */ + this.start = function (key) { + if (key) { + keysToLoad[key] = true; + } else { + itemsToLoad++; + if (!loading) { + executeCallbacks(startCallbacks); + loading = true; + $timeout.cancel(waitUntilDoneTimout); + } else { + $timeout.cancel(waitUntilDoneTimout); + } + } + }; + + /** + * @ngdoc function + * @name done + * @methodOf mwUI.Utils.service:Loading + * @description + * Stops a loading process identified by a unique key. + * When no key is specified a global loading process counter is increased. As soon as the global loading + * process counter is the same as the length of registered global loading processes a debounced callback is called + * @param {String} key the unique key which belongs to the animation (optional) + */ + this.done = function (key) { + if (key) { + delete keysToLoad[key]; + } else { + if (itemsToLoad !== 0) { + itemsAlreadyLoaded++; + if (itemsToLoad === itemsAlreadyLoaded) { + setToDone(); + } + } + } + }; + + /** + * @ngdoc function + * @name isLoading + * @methodOf mwUI.Utils.service:Loading + * @description + * When a key is specified it returns whether the loading process for that key is active + * otherwise it returns whether at least one process is active or none at all + * @param {String} key the unique key which belongs to the loading process (optional) + * @return {Boolean} Returns true if a loading is currently active for the given key + */ + this.isLoading = function (key) { + if (key) { + return keysToLoad[key] || false; + } else { + return loading; + } + }; + + /** + * @ngdoc function + * @name registerDoneCallback + * @methodOf mwUI.Utils.service:Loading + * @description + * Registers a callback function which gets called when all loading processes are done + * @param {Function} callback the callback function + */ + this.registerDoneCallback = function (callback) { + registerCallback(doneCallbacks, callback); + }; + + /** + * @ngdoc function + * @name registerStartCallback + * @methodOf mwUI.Utils.service:Loading + * @description + * Registers a callback function which gets called when the loading starts + * @param {Function} callback the callback function + */ + this.registerStartCallback = function (callback) { + registerCallback(startCallbacks, callback); + }; + + }); \ No newline at end of file diff --git a/src/mw-utils/services/mw_loading_service_test.js b/src/mw-utils/services/mw_loading_service_test.js new file mode 100644 index 00000000..3682e7ce --- /dev/null +++ b/src/mw-utils/services/mw_loading_service_test.js @@ -0,0 +1,92 @@ +'use strict'; + +describe('Loading', function () { + var service, rootScope; + var $timeout; + beforeEach(module('mwUI.Utils')); + + afterEach(function () { + service = null; + rootScope = null; + $timeout = null; + }); + + beforeEach(inject(function (_$rootScope_, _Loading_, _$timeout_) { + rootScope = _$rootScope_; + service = _Loading_; + $timeout = _$timeout_; + })); + + it('can be initialized', function () { + expect(service).toBeDefined(); + }); + + it('stores a loading key', function () { + service.start('test-key'); + expect(service.isLoading('test-key')).toBeTruthy(); + service.done('test-key'); + expect(service.isLoading('test-key')).toBeFalsy(); + }); + + it('isLoading can handle undefined as key', function () { + expect(service.isLoading(undefined)).toBeFalsy(); + }); + + it('isLoading can handle undefined as key and returns true when global loading process is in progress', function () { + service.start(); + expect(service.isLoading()).toBeTruthy(); + }); + + it('isLoading can handle undefined as key and returns false when no global loading process is in progress anymore', function () { + service.start(); + service.done(); + $timeout.flush(); + + expect(service.isLoading()).toBeFalsy(); + }); + + it('isLoading can handle undefined as key and returns true when at least one global loading process is in progress', function () { + service.start(); + service.start(); + + service.done(); + + expect(service.isLoading()).toBeTruthy(); + }); + + it('isLoading can handle undefined as key and returns false when all global loading process are done', function () { + service.start(); + service.start(); + + service.done(); + service.done(); + $timeout.flush(); + + expect(service.isLoading()).toBeFalsy(); + }); + + it('isLoading can handle null as key', function () { + expect(service.isLoading(null)).toBeFalsy(); + }); + + it('isLoading can unknown key', function () { + expect(service.isLoading('something')).toBeFalsy(); + }); + + it('sets a loading session with callbacks when no key is provided', function () { + var startCallback = jasmine.createSpy('startSpy'); + var doneCallback = jasmine.createSpy('doneSpy'); + service.registerStartCallback(startCallback); + service.registerDoneCallback(doneCallback); + service.start(); + rootScope.$digest(); + expect(service.isLoading()).toBeTruthy(); + service.done(); + rootScope.$digest(); + $timeout.flush(); + expect(service.isLoading()).toBeFalsy(); + + expect(startCallback).toHaveBeenCalled(); + expect(doneCallback).toHaveBeenCalled(); + }); +}); \ No newline at end of file From 7ad82f20fe16fdd814b4abc05e1dbc3fbd7986b7 Mon Sep 17 00:00:00 2001 From: Zarlex Date: Mon, 15 Oct 2018 17:47:40 +0200 Subject: [PATCH 2/5] Register loading service on request / unregister when request is done --- src/mw-utils/mw_utils.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/mw-utils/mw_utils.js b/src/mw-utils/mw_utils.js index e200d545..a36b9cb5 100644 --- a/src/mw-utils/mw_utils.js +++ b/src/mw-utils/mw_utils.js @@ -36,6 +36,25 @@ angular.module('mwUI.Utils', ['mwUI.i18n','mwUI.Modal']); // @include ./shims/route_to_regex.js // @include ./shims/deprecation_warning.js -angular.module('mwUI.Utils').config(function(i18nProvider){ +angular.module('mwUI.Utils').config(function($provide, $httpProvider, i18nProvider){ i18nProvider.addResource('mw-utils/i18n', 'uikit'); + + $provide.factory('requestInterceptorForLoadingService', function ($q, Loading) { + return { + request: function(request){ + Loading.start(); + return request; + }, + response: function (response) { + Loading.done(); + return response; + }, + responseError: function (response) { + Loading.done(); + return $q.reject(response); + } + }; + }); + + $httpProvider.interceptors.push('requestInterceptorForLoadingService'); }); \ No newline at end of file From 43ac8d02e87508c931ad4716d6faa76560d31ba0 Mon Sep 17 00:00:00 2001 From: Zarlex Date: Mon, 15 Oct 2018 17:48:30 +0200 Subject: [PATCH 3/5] Show loading spinner in header when there is a global loading process --- src/mw-modal/directives/mw_modal.js | 14 +++++++++----- src/mw-modal/directives/templates/mw_modal.html | 4 ++++ src/mw-modal/styles/_mw_modal.scss | 9 +++++++++ 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/mw-modal/directives/mw_modal.js b/src/mw-modal/directives/mw_modal.js index 4453f9b1..ba418c26 100644 --- a/src/mw-modal/directives/mw_modal.js +++ b/src/mw-modal/directives/mw_modal.js @@ -1,6 +1,6 @@ angular.module('mwUI.Modal') - .directive('mwModal', function (mwModalTmpl) { + .directive('mwModal', function (mwModalTmpl, Loading) { return { restrict: 'A', scope: { @@ -8,21 +8,25 @@ angular.module('mwUI.Modal') }, transclude: true, templateUrl: 'uikit/mw-modal/directives/templates/mw_modal.html', - controller: function($scope){ - this.addClass = function(styleClass){ + controller: function ($scope) { + this.addClass = function (styleClass) { $scope.addClass(styleClass); }; }, link: function (scope, el) { scope.$emit('COMPILE:FINISHED'); scope.mwModalTmpl = mwModalTmpl; - scope.addClass = function(styleClass){ + scope.addClass = function (styleClass) { el.addClass(styleClass); }; - if(scope.title){ + if (scope.title) { scope.addClass('has-header'); } + + scope.showLoadingSpinner = function () { + return Loading.isLoading(); + }; } }; }); \ No newline at end of file diff --git a/src/mw-modal/directives/templates/mw_modal.html b/src/mw-modal/directives/templates/mw_modal.html index 3cc74e7b..b62670d5 100644 --- a/src/mw-modal/directives/templates/mw_modal.html +++ b/src/mw-modal/directives/templates/mw_modal.html @@ -6,6 +6,10 @@ ng-src="{{mwModalTmpl.getLogoPath()}}" class="pull-left logo"/> +
+
+
diff --git a/src/mw-modal/styles/_mw_modal.scss b/src/mw-modal/styles/_mw_modal.scss index c85a376d..eabbb275 100644 --- a/src/mw-modal/styles/_mw_modal.scss +++ b/src/mw-modal/styles/_mw_modal.scss @@ -125,6 +125,9 @@ $windowPadding: 60; box-shadow: 0 -1px 4px rgba(122,122,122,.5); position: relative; z-index: 1000; + display: flex; + overflow: hidden; + white-space: nowrap; .logo{ margin-top: 4px; @@ -132,6 +135,12 @@ $windowPadding: 60; height: 16px; } + h4{ + flex-grow: 1; + overflow: hidden; + text-overflow: ellipsis; + } + } .body-holder{ From 246ee5599d503d82431c4e8ac95e0a8db3e31b20 Mon Sep 17 00:00:00 2001 From: Zarlex Date: Tue, 16 Oct 2018 17:31:29 +0200 Subject: [PATCH 4/5] Check after each task whether there is no pending $timeout task --- src/mw-utils/services/mw_loading_service_test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mw-utils/services/mw_loading_service_test.js b/src/mw-utils/services/mw_loading_service_test.js index 3682e7ce..d8da58f7 100644 --- a/src/mw-utils/services/mw_loading_service_test.js +++ b/src/mw-utils/services/mw_loading_service_test.js @@ -6,6 +6,7 @@ describe('Loading', function () { beforeEach(module('mwUI.Utils')); afterEach(function () { + $timeout.verifyNoPendingTasks(); service = null; rootScope = null; $timeout = null; From 5aa65862d2c35bc90c452a400a2a9a1ba62f2729 Mon Sep 17 00:00:00 2001 From: Zarlex Date: Tue, 16 Oct 2018 17:31:43 +0200 Subject: [PATCH 5/5] replace cbs with callbacks --- src/mw-utils/services/mw_loading_service.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mw-utils/services/mw_loading_service.js b/src/mw-utils/services/mw_loading_service.js index d3ccb81e..52da84ec 100644 --- a/src/mw-utils/services/mw_loading_service.js +++ b/src/mw-utils/services/mw_loading_service.js @@ -24,10 +24,10 @@ angular.module('mwUI.Utils') itemsAlreadyLoaded = 0; }; - var executeCallbacks = function (cbs, args, scope) { + var executeCallbacks = function (callbacks, args, scope) { scope = scope || this; - cbs.forEach(function (cb) { - cb.apply(scope, args); + callbacks.forEach(function (callback) { + callback.apply(scope, args); }); };