From 9da538b72753b1d650bed8387157d15921e2696a Mon Sep 17 00:00:00 2001 From: Tommy Yu Date: Tue, 16 May 2017 18:09:38 +1200 Subject: [PATCH] Formalize populate to also trigger init_element - Given that workflows for triggering client-side rendering will happen after the page has loaded, i.e. after do_onload is typically called. - In order to also properly hook that in place, call init_element after the populate is completed. - The testing, especially for the missing module, had to be a bit obtuse for the synchronous version to avoid trigger the async handling which will cascade outside the scope of the synchronous intent of that test. --- src/nunja/engine.js | 9 ++++ src/nunja/tests/test_engine.js | 91 +++++++++++++++++++++++++++++++++- 2 files changed, 99 insertions(+), 1 deletion(-) diff --git a/src/nunja/engine.js b/src/nunja/engine.js index 4aa122b..7fa3142 100644 --- a/src/nunja/engine.js +++ b/src/nunja/engine.js @@ -111,6 +111,12 @@ Engine.prototype.init_element = function(element) { if (main && main.init instanceof Function) { main.init(element); } + }, function() { + // TODO whether have this be a definable behavior, i.e. whether + // to leave undefine instead so import can be attempted again, + // or that it be hard-defined to be nothing like so: + // define(entry_point, [], {}); + // requirejs.undef(entry_point); }); }; @@ -164,11 +170,14 @@ Engine.prototype.populate = function (element, data, cb) { if (!(cb instanceof Function)) { element.innerHTML = this.render(mold_id, data); + this.init_element(element); } else { + var self = this; this.render(mold_id, data, function(err, result) { // TODO handle err if there is an error somewhere... element.innerHTML = result; + self.init_element(element); cb(); }); } diff --git a/src/nunja/tests/test_engine.js b/src/nunja/tests/test_engine.js index 6cc3faa..20389df 100644 --- a/src/nunja/tests/test_engine.js +++ b/src/nunja/tests/test_engine.js @@ -47,6 +47,7 @@ describe('nunja/engine simple test case', function() { delete window.nunjucksPrecompiled['check/template.nja']; requirejs.undef('text!check/template.nja'); requirejs.undef('text!dummy/mold/template.nja'); + requirejs.undef('dummy/mold/index'); this.clock.restore(); document.body.innerHTML = ""; }); @@ -82,6 +83,56 @@ describe('nunja/engine simple test case', function() { expect(this.engine.render('dummy/mold')).to.equal('dummy'); }); + it('test simple populate, undefined index', function(done) { + document.body.innerHTML = '
'; + var element = $('div')[0]; + + define('text!dummy/mold/template.nja', [], function () { + return 'dummy'; + }); + require(['text!dummy/mold/template.nja'], function() {}); + this.clock.tick(500); + + // forcing an error import handling here to prevent requirejs + // from raising an exception after this execution was done by + // running the test within the error handler to ensure the + // error handler actually gets executed. + var self = this; + require(['dummy/mold/index'], function() {}, function() { + self.engine.populate(element, {}); + self.clock.tick(500); + expect(document.body.innerHTML).to.equal( + '
dummy
'); + done(); + }); + this.clock.tick(500); + + }); + + it('test simple populate, defined index', function() { + document.body.innerHTML = '
'; + var element = $('div')[0]; + var called = false; + + // define modules + define('text!dummy/mold/template.nja', [], function () { + return 'dummy'; + }); + require(['text!dummy/mold/template.nja'], function() {}); + define('dummy/mold/index', [], function () { + return {'init': function() { + called = true; + }}; + }); + require(['dummy/mold/index'], function() {}); + this.clock.tick(500); + this.engine.populate(element, {}); + this.clock.tick(500); + expect(document.body.innerHTML).to.equal( + '
dummy
'); + expect(called).to.be.true; + }); + }); @@ -148,6 +199,7 @@ describe_('nunja/engine async test case', function() { requirejs.undef('text!mock.molds/populates/template.nja'); requirejs.undef('text!mock.molds/includes/template.nja'); requirejs.undef('text!mock.molds/includes/embedded.nja'); + requirejs.undef('mock.molds/populate/index'); this.server.restore(); document.body.innerHTML = ""; }); @@ -171,9 +223,10 @@ describe_('nunja/engine async test case', function() { }); }); - it('test async include populate', function(done) { + it('test async include populate, no trigger', function(done) { // Same as above, but it includes another template that required // to be loaded. + // Note the lack of the index module. // First set the innerHTML to a dummy rendering document.body.innerHTML = ( @@ -188,6 +241,42 @@ describe_('nunja/engine async test case', function() { }); }); + it('test async populate trigger', function(done) { + // Given that the rendering for client side interactions almost + // always require async to be responsive, the populate method + // can and should function without the explicit load_mold like + // above. + + var init_element; + var self = this; + + // First set the innerHTML to a dummy rendering + document.body.innerHTML = ( + '
' + ); + // Also define the module + define('mock.molds/populate/index', [], function() { + return {'init': function(el) { + init_element = el; + }}; + }); + + // ensure the index module is first loaded to avoid async errors + require(['mock.molds/populate/index'], function() { + var element = $('div')[0]; + self.engine.populate(element, {'msg': 'Hello World!'}, function() { + var text = element.innerHTML; + expect(text).to.equal( + 'nunja/engine populated: Hello World!'); + // DOM objects behave weird on assignment, so we cannot + // compare their identities directly. + expect(init_element.innerHTML).to.equal( + 'nunja/engine populated: Hello World!'); + done(); + }); + }); + }); + it('test async execute', function(done) { this.engine.execute('mock.molds/includes', {}, function(err, text) { expect(err).to.be.null;