From 5e5b301d0d2f8df453328ccbcf8f48432e3ff6b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jannis=20Mo=C3=9Fhammer?= Date: Fri, 21 Jun 2013 15:33:06 +0200 Subject: [PATCH] Add support for lazy module loading When the X-Icinga-Module-Enable header is send, the modulemanager automatically tries to load javascript files for that module. This is realized by adding the 'registerHeaderListener' method to the async manager, which allows to listen to specific headers and firing callbacks if a response with the specified header is retrieved. Also the tests have changed a bit, requireNow should be used when using the requiremock, so a require always loads files new. refs #4092 refs #3753 --- application/controllers/ModulesController.php | 6 +- public/js/icinga/icinga.js | 8 ++- public/js/icinga/util/async.js | 34 ++++++++-- test/js/test/icinga/moduleTest.js | 62 +++++++++++++++++-- 4 files changed, 99 insertions(+), 11 deletions(-) diff --git a/application/controllers/ModulesController.php b/application/controllers/ModulesController.php index f8f40a3b3..afd3b9178 100755 --- a/application/controllers/ModulesController.php +++ b/application/controllers/ModulesController.php @@ -35,7 +35,11 @@ class ModulesController extends ActionController public function enableAction() { $this->manager->enableModule($this->_getParam('name')); - $this->redirectNow('modules/overview?_render=body'); + $this->manager->loadModule($this->_getParam('name')); + $this->getResponse()->setHeader('X-Icinga-Enable-Module', $this->_getParam('name')); + $this->replaceLayout = true; + $this->indexAction(); + } public function disableAction() diff --git a/public/js/icinga/icinga.js b/public/js/icinga/icinga.js index ff59321f6..d538ab552 100755 --- a/public/js/icinga/icinga.js +++ b/public/js/icinga/icinga.js @@ -19,16 +19,19 @@ define([ var failedModules = []; var initialize = function () { + registerLazyModuleLoading(); enableInternalModules(); - + containerMgr.registerAsyncMgr(async); containerMgr.initializeContainers(document); log.debug("Initialization finished"); enableModules(); }; - + var registerLazyModuleLoading = function() { + async.registerHeaderListener("X-Icinga-Enable-Module", loadModuleScript, this); + }; var enableInternalModules = function() { $.each(internalModules,function(idx,module) { @@ -37,6 +40,7 @@ define([ }; var loadModuleScript = function(name) { + console.log("Loading ", name); moduleMgr.enableModule("modules/"+name+"/"+name, function(error) { failedModules.push({ name: name, diff --git a/public/js/icinga/util/async.js b/public/js/icinga/util/async.js index 15a6be7df..1b564b176 100644 --- a/public/js/icinga/util/async.js +++ b/public/js/icinga/util/async.js @@ -3,7 +3,8 @@ "use strict"; var asyncMgrInstance = null; - define(['icinga/container','logging','icinga/behaviour','jquery'],function(containerMgr,log,behaviour,$) { + define(['icinga/container','logging','jquery'],function(containerMgr,log,$) { + var headerListeners = {}; var pending = { @@ -18,12 +19,30 @@ return target; }; - var handleResponse = function(html) { + var applyHeaderListeners = function(headers) { + for (var header in headerListeners) { + if (headers.getResponseHeader(header) === null) { + // see if the browser/server converts headers to lowercase + if (headers.getResponseHeader(header.toLowerCase()) === null) { + continue; + } + header = header.toLowerCase(); + } + var value = headers.getResponseHeader(header); + var listeners = headerListeners[header]; + for (var i=0;i")); $('a.test').click(); @@ -223,4 +226,55 @@ describe('The icinga module bootstrap', function() { should.equal(icinga.getFailedModules()[0].name, "test2"); tearDownTestDOM(); }); + + it("Should load modules lazily when discovering a X-Icinga-Enable-Module header", function() { + rjsmock.purgeDependencies(); + + requireNew("icinga/util/async.js"); + var async = rjsmock.getDefine(); + + rjsmock.registerDependencies({ + "icinga/module": module, + "icinga/util/async": async, + "modules/test/test" : { + eventHandler: { + "a.test" : { + click : function() { + testClick = true; + } + } + } + }, + "icinga/container" : { + registerAsyncMgr: function() {}, + initializeContainers: function() {} + }, + "modules/list" : [ + ] + }); + + tearDownTestDOM(); + + requireNew("icinga/icinga.js"); + var icinga = rjsmock.getDefine(); + + var testClick = false; + // The module shouldn't be loaded + $('body').append($("")); + $('a.test').click(); + should.equal(testClick, false, "Unregistered module was loaded"); + + asyncMock.setNextAsyncResult(async,"result", false, { + "X-Icinga-Enable-Module" : "test" + }); + async.createRequest(); + // The module shouldn't be loaded + $('body').append($("")); + $('a.test').click(); + should.equal(testClick, true, "Module wasn't automatically loaded on header!"); + + + tearDownTestDOM(); + + }); });