From 0468bddc8337194292d71443410486b25d076d1d Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Mon, 10 Aug 2015 14:46:58 +0200 Subject: [PATCH] js: Ensure that rendered events of modules are called on page-load fixes #9869 --- public/js/icinga.js | 57 ++++++++++++++++++++++++++-------- public/js/icinga/events.js | 63 +++++++++++++++++++++++++++----------- 2 files changed, 89 insertions(+), 31 deletions(-) diff --git a/public/js/icinga.js b/public/js/icinga.js index e1f1f8fdd..1f1127714 100644 --- a/public/js/icinga.js +++ b/public/js/icinga.js @@ -112,38 +112,69 @@ /** * Load a given module by name + * + * @param {string} name + * + * @return {boolean} */ loadModule: function (name) { - if (this.hasModule(name)) { + if (this.isLoadedModule(name)) { this.logger.error('Cannot load module ' + name + ' twice'); - return; + return false; } - this.modules[name] = new Icinga.Module(this, name); + if (! this.hasModule(name)) { + this.logger.error('Cannot find module ' + name); + return false; + } + + this.modules[name] = new Icinga.Module( + this, + name, + Icinga.availableModules[name] + ); + return true; }, /** - * Whether a module matching the given name exists + * Whether a module matching the given name exists or is loaded + * + * @param {string} name + * + * @return {boolean} */ hasModule: function (name) { - return 'undefined' !== typeof this.modules[name] || + return this.isLoadedModule(name) || 'undefined' !== typeof Icinga.availableModules[name]; }, + /** + * Return whether the given module is loaded + * + * @param {string} name The name of the module + * + * @returns {Boolean} + */ + isLoadedModule: function (name) { + return 'undefined' !== typeof this.modules[name]; + }, + /** * Get a module by name + * + * @param {string} name + * + * @return {object} */ module: function (name) { - if ('undefined' === typeof this.modules[name]) { - if ('undefined' !== typeof Icinga.availableModules[name]) { - this.modules[name] = new Icinga.Module( - this, - name, - Icinga.availableModules[name] - ); - } + if (this.hasModule(name) && !this.isLoadedModule(name)) { + this.modules[name] = new Icinga.Module( + this, + name, + Icinga.availableModules[name] + ); } return this.modules[name]; diff --git a/public/js/icinga/events.js b/public/js/icinga/events.js index 9eed7f566..71408d712 100644 --- a/public/js/icinga/events.js +++ b/public/js/icinga/events.js @@ -13,6 +13,7 @@ this.icinga = icinga; this.searchValue = ''; + this.initializeModules = true; }; Icinga.Events.prototype = { @@ -35,6 +36,46 @@ var self = event.data.self; var icinga = self.icinga; + if (self.initializeModules) { + var loaded = false; + var moduleName = $target.data('icingaModule'); + if (moduleName) { + if (icinga.hasModule(moduleName) && !icinga.isLoadedModule(moduleName)) { + loaded |= icinga.loadModule(moduleName); + } + } + + $('.icinga-module', $target).each(function(idx, mod) { + moduleName = $(mod).data('icingaModule'); + if (icinga.hasModule(moduleName) && !icinga.isLoadedModule(moduleName)) { + loaded |= icinga.loadModule(moduleName); + } + }); + + if (loaded) { + // Modules may register their own handler for the 'renderend' event + // so we need to ensure that it is called the first time they are + // initialized + event.stopImmediatePropagation(); + self.initializeModules = false; + + var $container = $target.closest('.container'); + if (! $container.length) { + // The page obviously got loaded for the first time, + // so we'll trigger the event for all containers + $container = $('.container'); + } + + $container.trigger('rendered'); + + // But since we're listening on this event by ourself, we'll have + // to abort our own processing as we'll process it twice otherwise + return false; + } + } else { + self.initializeModules = true; + } + $('.dashboard > div', $target).each(function(idx, el) { var $element = $(el); var $url = $element.data('icingaUrl'); @@ -43,21 +84,6 @@ } }); - var moduleName = $target.data('icingaModule'); - if (moduleName) { - if (icinga.hasModule(moduleName)) { - icinga.module(moduleName); - } - } - - $('.icinga-module', $target).each(function(idx, mod) { - var $mod = $(mod); - moduleName = $mod.data('icingaModule'); - if (icinga.hasModule(moduleName)) { - icinga.module(moduleName); - } - }); - var $searchField = $('#menu input.search', $target); // Remember initial search field value if any if ($searchField.length && $searchField.val().length) { @@ -75,13 +101,14 @@ * Global default event handlers */ applyGlobalDefaults: function () { + // Apply element-specific behavior whenever the layout is rendered + // Note: It is important that this is the first handler for this event! + $(document).on('rendered', { self: this }, this.applyHandlers); + $.each(self.icinga.behaviors, function (name, behavior) { behavior.bind($(document)); }); - // Apply element-specific behavior whenever the layout is rendered - $(document).on('rendered', { self: this }, this.applyHandlers); - // We catch resize events $(window).on('resize', { self: this.icinga.ui }, this.icinga.ui.onWindowResize);