Skip to content

Commit 94985a4

Browse files
committed
MOBILE-925 remoteaddons: Handle addon dependencies
1 parent 224b624 commit 94985a4

File tree

1 file changed

+90
-7
lines changed

1 file changed

+90
-7
lines changed

www/core/lib/addonmanager.js

Lines changed: 90 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ angular.module('mm.core')
3535
remoteAddonCssFilename = 'styles.css',
3636
pathWildcardRegex = /\$ADDONPATH\$/g,
3737
headEl = angular.element(document.querySelector('head')),
38-
loadedAddons = [];
38+
loadedAddons = [],
39+
loadedModules = [];
3940

4041
/**
4142
* Download a remote addon if it's not downloaded already.
@@ -104,12 +105,12 @@ angular.module('mm.core')
104105
* @ngdoc method
105106
* @name $mmAddonManager#downloadRemoteAddons
106107
* @param {String} [siteId] Site ID. If not defined, current site.
107-
* @return {Promise} Promise resolved when done. Returns the list of downloaded addons.
108+
* @return {Promise} Promise resolved when done. Returns the list of downloaded addons (object).
108109
*/
109110
self.downloadRemoteAddons = function(siteId) {
110111
siteId = siteId || $mmSite.getId();
111112

112-
var downloaded = [],
113+
var downloaded = {},
113114
preSets = {};
114115

115116
return $mmSitesManager.getSite(siteId).then(function(site) {
@@ -120,7 +121,7 @@ angular.module('mm.core')
120121

121122
angular.forEach(data.plugins, function(addon) {
122123
promises.push(self.downloadRemoteAddon(addon, siteId).then(function() {
123-
downloaded.push(addon);
124+
downloaded[addon.addon]= addon;
124125
}));
125126
});
126127

@@ -261,17 +262,99 @@ angular.module('mm.core')
261262
* @module mm.core
262263
* @ngdoc method
263264
* @name $mmAddonManager#loadRemoteAddons
264-
* @param {Object[]} addons Addons to load.
265-
* @return {Promise} Promise resolved when all have been loaded.
265+
* @param {Object} addons Addons to load.
266+
* @return {Promise} Promise resolved when all have been loaded.
266267
*/
267268
self.loadRemoteAddons = function(addons) {
268269
var promises = [];
270+
271+
// Update the list of loaded modules in the app.
272+
loadedModules = $ocLazyLoad.getModules();
273+
274+
// Load each addon if all dependencies are found. Addons will be loaded in dependency order.
269275
angular.forEach(addons, function(addon) {
270-
promises.push(self.loadRemoteAddon(addon));
276+
self.setRemoteAddonLoadPromise(addons, addon);
277+
if (addon.loadPromise) {
278+
promises.push(addon.loadPromise);
279+
}
271280
});
281+
272282
return $mmUtil.allPromises(promises);
273283
};
274284

285+
/**
286+
* Set the promise to load a remote addon. The promise will be stored in 'addon.loadPromise'.
287+
* This promise will depend on the dependencies promises, so an addon won't be loaded until all dependencies are.
288+
* If a dependency isn't found then 'addon.loadPromise' will be set to false.
289+
*
290+
* @module mm.core
291+
* @ngdoc method
292+
* @name $mmAddonManager#setRemoteAddonLoadPromise
293+
* @param {Object[]} addons List of all addons to load.
294+
* @param {Object} addon Addon.
295+
* @param {String[]} [dependants] List of addons that depend on this addon. Will be built on recursive calls.
296+
* This is to prevent circular dependencies.
297+
* @return {Void}
298+
*/
299+
self.setRemoteAddonLoadPromise = function(addons, addon, dependants) {
300+
if (typeof addon.loadPromise != 'undefined') {
301+
// Already set.
302+
return;
303+
}
304+
305+
dependants = dependants || [];
306+
307+
var promises = [],
308+
stop = false;
309+
310+
angular.forEach(addon.dependencies, function(dependency) {
311+
if (stop) {
312+
// A dependency wasn't found, no need to calculate it any further.
313+
return;
314+
}
315+
316+
if (dependency == addon.addon) {
317+
// A plugin can't depend on itself, ignore it.
318+
return;
319+
}
320+
321+
if (dependants.indexOf(dependency) != -1) {
322+
// Circular dependency! Stop.
323+
stop = true;
324+
return;
325+
}
326+
327+
if (!addons[dependency]) {
328+
// Dependency not found in remote addons. Search in app addons.
329+
if (dependency.indexOf('mm.addons.') == -1) {
330+
dependency = 'mm.addons.' + dependency;
331+
}
332+
333+
if (loadedModules.indexOf(dependency) == -1) {
334+
// Not found in app either.
335+
stop = true;
336+
}
337+
} else {
338+
// Set the load promise of the dependency if it hasn't been set already.
339+
self.setRemoteAddonLoadPromise(addons, addons[dependency], dependants.concat(addon.addon));
340+
if (!addons[dependency].loadPromise) {
341+
// Dependency cannot be loaded, don't load this addon either.
342+
stop = true;
343+
} else {
344+
promises.push(addons[dependency].loadPromise);
345+
}
346+
}
347+
});
348+
349+
if (!stop) {
350+
addon.loadPromise = $q.all(promises).then(function() {
351+
return self.loadRemoteAddon(addon);
352+
});
353+
} else {
354+
addon.loadPromise = false;
355+
}
356+
};
357+
275358
/**
276359
* Set status of a remote addon.
277360
*

0 commit comments

Comments
 (0)