Skip to content
This repository has been archived by the owner on Nov 3, 2021. It is now read-only.

Commit

Permalink
Merge pull request #30125 from luke-chang/1166214_basemodule_support_…
Browse files Browse the repository at this point in the history
…subdirectory

Bug 1166214 - Make BaseModule.SUB_MODULES support subdirectory, r=alive
  • Loading branch information
Luke Chang committed May 21, 2015
2 parents 48b2c20 + ec9c681 commit 208ec11
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 32 deletions.
85 changes: 56 additions & 29 deletions apps/system/js/base_module.js
Expand Up @@ -31,8 +31,10 @@

/**
* The sub modules belong to this module.
* BaseModule will load and then start these sub modules
* automatically.
* BaseModule will load and then start these sub modules automatically.
* The expressions can include path (e.g. 'path/to/ModuleName'). BaseModule
* will load them from specified subdirectory. However, the module names
* (without path) should be unique even they're under different folders.
* @type {Array}
*/
BaseModule.SUB_MODULES = [];
Expand Down Expand Up @@ -71,7 +73,7 @@
/**
* This tells System the sandbox what methods you are going to
* register and let the other to request.
*
*
* @example
* var MyModule = function() {};
* MyModule.SERVICES = ['unlock'];
Expand All @@ -93,7 +95,7 @@
* The function or property exported here will be
* synchronously queried by other module in system app.
* If we are not started yet, they will get undefined.
*
*
* @example
* var MyModule = function() {};
* MyModule.STATES = ['isActive'];
Expand Down Expand Up @@ -126,13 +128,15 @@
BaseModule.lazyLoad(this.constructor.SUB_MODULES).then(function() {
this.debug('lazy loaded submodules: ' +
this.constructor.SUB_MODULES.concat());
this.constructor.SUB_MODULES.forEach(function(module) {
var moduleName = BaseModule.lowerCapital(module);
var parent = this.constructor.SUB_MODULE_PARENT || this;
if (!parent[moduleName]) {
this._initialSubModule(moduleName, module);
}
}, this);
this.constructor.SUB_MODULES
.map(BaseModule.parsePath)
.forEach(function(module) {
var moduleName = BaseModule.lowerCapital(module.name);
var parent = this.constructor.SUB_MODULE_PARENT || this;
if (!parent[moduleName]) {
this._initialSubModule(moduleName, module.name);
}
}, this);
}.bind(this));
},

Expand All @@ -156,14 +160,16 @@
if (!this.constructor.SUB_MODULES) {
return;
}
this.constructor.SUB_MODULES.forEach(function(module) {
var moduleName = BaseModule.lowerCapital(module);
var parent = this.constructor.SUB_MODULE_PARENT || this;
if (parent[moduleName]) {
this.debug('Stopping submodule: ' + moduleName);
parent[moduleName].stop && parent[moduleName].stop();
}
}, this);
this.constructor.SUB_MODULES
.map(BaseModule.parsePath)
.forEach(function(module) {
var moduleName = BaseModule.lowerCapital(module.name);
var parent = this.constructor.SUB_MODULE_PARENT || this;
if (parent[moduleName]) {
this.debug('Stopping submodule: ' + moduleName);
parent[moduleName].stop && parent[moduleName].stop();
}
}, this);
}
};

Expand Down Expand Up @@ -326,7 +332,7 @@
* name: 'MyModule'
* });
* var myModule = BaseModule.instantiate('MyModule');
*
*
* @param {Function} constructor The constructor function.
* @param {Object} prototype
* The prototype which will be injected into the class.
Expand Down Expand Up @@ -414,21 +420,42 @@
return str.charAt(0).toLowerCase() + str.slice(1);
};

/**
* A helper function to split module expressions into "path" and "name".
* @example
* Service.parsePath('path/to/ModuleName');
* // {path: 'path/to/', name: 'ModuleName'}
* @param {String} str String to be splitted
* @return {Object} The result object with members: "path" and "name".
*/
BaseModule.parsePath = function(str) {
var [, path, name] = /^(.*\/|)(.+)$/.exec(str);
return {
path: path,
name: name
};
};

/**
* A helper function to transform object name to file name
* @example
* var modules = ['AppWindowManager', 'HomescreenLauncher'];
* Service.object2fileName(modules);
* // ['js/app_window_manager.js', 'js/homescreen_launcher.js']
* Service.object2fileName('AppWindowManager');
* // 'js/app_window_manager.js'
* Service.object2fileName('path/to/ModuleName');
* // 'js/path/to/module_name.js'
*
* @param {Array} strings Array of module names
* @return {Array} Array of file names
* @param {String} string Module name
* @return {String} File name
*/
BaseModule.object2fileName = function(strings) {
BaseModule.object2fileName = function(string) {
var i = 0;
var ch = '';
while (i <= strings.length) {
var character = strings.charAt(i);

var module = BaseModule.parsePath(string);
var moduleName = module.name;

while (i <= moduleName.length) {
var character = moduleName.charAt(i);
if (character !== character.toLowerCase()) {
if (ch === '') {
ch += character.toLowerCase();
Expand All @@ -440,7 +467,7 @@
}
i++;
}
return '/js/' + ch + '.js';
return '/js/' + module.path + ch + '.js';
};

BaseModule.prototype = {
Expand Down
29 changes: 26 additions & 3 deletions apps/system/test/unit/base_module_test.js
Expand Up @@ -21,9 +21,17 @@ suite('system/BaseModule', function() {
BaseModule.lowerCapital('AppWindowManager'));
});

test('parse module path', function() {
var module = BaseModule.parsePath('path/to/ModuleName');
assert.equal(module.path, 'path/to/');
assert.equal(module.name, 'ModuleName');
});

test('object name to file name', function() {
assert.deepEqual('/js/app_window_manager.js',
BaseModule.object2fileName('AppWindowManager'));
assert.deepEqual('/js/path/to/module_name.js',
BaseModule.object2fileName('path/to/ModuleName'));
});

test('lazy load from an array of submodule strings', function(done) {
Expand Down Expand Up @@ -194,7 +202,7 @@ suite('system/BaseModule', function() {
'_pre_handleEvent').returns(false);
var spyFtuskip = fakeAppWindowManager._handle_ftuskip = this.sinon.spy();
var ftuskipEvent = new CustomEvent('ftuskip');

window.dispatchEvent(ftuskipEvent);
assert.isFalse(spy.called);
assert.isFalse(spyFtuskip.called);
Expand Down Expand Up @@ -230,14 +238,17 @@ suite('system/BaseModule', function() {
});

suite('Submodule management', function() {
var fakeAppWindowManager, fakePromise;
var fakeAppWindowManager, fakeSubModule, fakePromise;
setup(function() {
fakePromise = new MockPromise();
this.sinon.stub(BaseModule, 'lazyLoad', function() {
return fakePromise;
});
window.FakeAppWindowManager = function() {};
window.FakeAppWindowManager.SUB_MODULES = ['FakeTaskManager'];
window.FakeAppWindowManager.SUB_MODULES = [
'FakeTaskManager',
'path/to/FakeSubModule'
];
BaseModule.create(window.FakeAppWindowManager, {
name: 'FakeAppWindowManager'
});
Expand All @@ -247,6 +258,12 @@ suite('system/BaseModule', function() {
});
fakeAppWindowManager = new window.FakeAppWindowManager();
fakeAppWindowManager.start();
window.FakeSubModule = function() {};
BaseModule.create(window.FakeSubModule, {
name: 'FakeSubModule'
});
fakeSubModule = new window.FakeSubModule();
fakeSubModule.start();
});

teardown(function() {
Expand All @@ -257,9 +274,12 @@ suite('system/BaseModule', function() {

test('submodule should be loaded', function() {
var spy = fakeAppWindowManager._fakeTaskManager_loaded = this.sinon.spy();
var spy2 = fakeAppWindowManager._fakeSubModule_loaded = this.sinon.spy();
fakePromise.mFulfillToValue();
assert.isDefined(fakeAppWindowManager.fakeTaskManager);
assert.isTrue(spy.called);
assert.isDefined(fakeAppWindowManager.fakeSubModule);
assert.isTrue(spy2.called);
});

test('submodule loaded handler should be called if it exists', function() {
Expand All @@ -279,9 +299,12 @@ suite('system/BaseModule', function() {
fakePromise.mFulfillToValue();
var spyStop =
this.sinon.stub(fakeAppWindowManager.fakeTaskManager, 'stop');
var spyStop2 =
this.sinon.stub(fakeAppWindowManager.fakeSubModule, 'stop');

fakeAppWindowManager.stop();
assert.isTrue(spyStop.called);
assert.isTrue(spyStop2.called);
});

test('submodule should not be started if the parent is already stopped',
Expand Down

0 comments on commit 208ec11

Please sign in to comment.