diff options
Diffstat (limited to 'addons/web/static/src/js/core')
| -rw-r--r-- | addons/web/static/src/js/core/abstract_service.js | 9 | ||||
| -rw-r--r-- | addons/web/static/src/js/core/bus.js | 5 | ||||
| -rw-r--r-- | addons/web/static/src/js/core/registry.js | 14 | ||||
| -rw-r--r-- | addons/web/static/src/js/core/service_mixins.js | 103 | ||||
| -rw-r--r-- | addons/web/static/src/js/core/session.js | 3 | ||||
| -rw-r--r-- | addons/web/static/src/js/core/utils.js | 31 |
6 files changed, 87 insertions, 78 deletions
diff --git a/addons/web/static/src/js/core/abstract_service.js b/addons/web/static/src/js/core/abstract_service.js index cbd6c1322ca..14efef09b39 100644 --- a/addons/web/static/src/js/core/abstract_service.js +++ b/addons/web/static/src/js/core/abstract_service.js @@ -6,7 +6,6 @@ var Mixins = require('web.mixins'); var ServicesMixin = require('web.ServicesMixin'); var AbstractService = Class.extend(Mixins.EventDispatcherMixin, ServicesMixin, { - Services: [], dependencies: [], name: null, init: function (parent) { @@ -15,13 +14,5 @@ var AbstractService = Class.extend(Mixins.EventDispatcherMixin, ServicesMixin, { }, }); -var realExtend = AbstractService.extend; - -AbstractService.extend = function () { - var Service = realExtend.apply(this, arguments); - AbstractService.prototype.Services.push(Service); - return Service; -}; - return AbstractService; }); diff --git a/addons/web/static/src/js/core/bus.js b/addons/web/static/src/js/core/bus.js index 92278e0f1d6..5257453edab 100644 --- a/addons/web/static/src/js/core/bus.js +++ b/addons/web/static/src/js/core/bus.js @@ -10,8 +10,9 @@ var mixins = require('web.mixins'); * @class Bus */ return Class.extend(mixins.EventDispatcherMixin, { - init: function () { - mixins.EventDispatcherMixin.init.call(this, arguments); + init: function (parent) { + mixins.EventDispatcherMixin.init.call(this); + this.setParent(parent); }, }); diff --git a/addons/web/static/src/js/core/registry.js b/addons/web/static/src/js/core/registry.js index d70c09e4ae0..f925b0ea30a 100644 --- a/addons/web/static/src/js/core/registry.js +++ b/addons/web/static/src/js/core/registry.js @@ -25,6 +25,7 @@ var Registry = Class.extend({ */ init: function (mapping) { this.map = Object.create(mapping || null); + this.listeners = []; // listening callbacks on newly added items. }, //-------------------------------------------------------------------------- @@ -34,12 +35,17 @@ var Registry = Class.extend({ /** * Add a key (and a value) to the registry. * + * Notify the listeners on newly added item in the registry. + * * @param {string} key * @param {any} value * @returns {Registry} can be used to chain add calls. */ add: function (key, value) { this.map[key] = value; + _.each(this.listeners, function (callback) { + callback(key, value); + }); return this; }, /** @@ -89,6 +95,14 @@ var Registry = Class.extend({ } return null; }, + /** + * Register a callback to execute when items are added to the registry. + * + * @param {function} callback function with parameters (key, value). + */ + onAdd: function (callback) { + this.listeners.push(callback); + }, }); return Registry; diff --git a/addons/web/static/src/js/core/service_mixins.js b/addons/web/static/src/js/core/service_mixins.js index d5abf727704..4ab0a361988 100644 --- a/addons/web/static/src/js/core/service_mixins.js +++ b/addons/web/static/src/js/core/service_mixins.js @@ -1,58 +1,86 @@ odoo.define('web.ServiceProviderMixin', function (require) { "use strict"; -var AbstractService = require('web.AbstractService'); -var utils = require('web.utils'); +var core = require('web.core'); var ServiceProviderMixin = { - services: {}, - init: function () { + services: {}, // dict containing deployed service instances + UndeployedServices: {}, // dict containing classes of undeployed services + /** + * @override + */ + init: function (parent) { + var self = this; // to properly instantiate services with this as parent, this mixin // assumes that it is used along the EventDispatcherMixin, and that // EventDispatchedMixin's init is called first - var self = this; - // as EventDispatcherMixin's init is already called, this handler has to - // be bound manually + // as EventDispatcherMixin's init is already called, this handler has + // to be bound manually this.on('call_service', this, this._call_service.bind(this)); - var sortedServices = this._sortServices(AbstractService.prototype.Services); - _.each(sortedServices, function (Service) { - var service = new Service(self); - self.services[service.name] = service; + // add already registered services from the service registry + _.each(core.serviceRegistry.map, function (Service, serviceName) { + self.UndeployedServices[serviceName] = Service; + }); + this._deployServices(); + + // listen on newly added services + core.serviceRegistry.onAdd(function (serviceName, Service) { + self.UndeployedServices[serviceName] = Service; + self._deployServices(); }); }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @private + */ + _deployServices: function () { + var self = this; + var done = false; + while (!done) { + var Service = _.find(this.UndeployedServices, function (Service) { + // no missing dependency + return !_.some(Service.prototype.dependencies, function (depName) { + return !self.services[depName]; + }); + }); + if (Service) { + this.services[Service.prototype.name] = new Service(this); + delete this.UndeployedServices[Service.prototype.name]; + } else { + done = true; + } + } + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * Call the 'service', using data from the 'event' that + * has triggered the service call. + * + * For the ajax service, the arguments are extended with + * the target so that it can call back the caller. + * + * @private + * @param {OdooEvent} event + */ _call_service: function (event) { - var service = this.services[event.data.service]; var args = event.data.args || []; - // ajax service uses an extra 'target' argument for rpc if (event.data.service === 'ajax' && event.data.method === 'rpc') { + // ajax service uses an extra 'target' argument for rpc args = args.concat(event.target); } + var service = this.services[event.data.service]; var result = service[event.data.method].apply(service, args); event.data.callback(result); }, - _sortServices: function (services) { - var nodes = {}; - // Create nodes (services) - _.each(services, function (Service) { - nodes[Service.prototype.name] = Service.prototype.dependencies; - }); - var sorted; - try { - sorted = utils.topologicalSort(nodes); - } catch (err) { - console.warn('topologicalSort Error:', err.message); - sorted = nodes; - } - // Sort services based on sorted - // Note: we convert sorted to an object key=>index for efficiency - var sortedObj = _.invert(_.object(_.pairs(sorted))); - sorted = _.sortBy(services, function (Service) { - return sortedObj[Service.prototype.name]; - }); - - return sorted; - }, }; return ServiceProviderMixin; @@ -69,6 +97,11 @@ var rpc = require('web.rpc'); * @name ServicesMixin */ var ServicesMixin = { + /** + * @param {string} service + * @param {string} method + * @return {any} result of the service called + */ call: function (service, method) { var args = Array.prototype.slice.call(arguments, 2); var result; diff --git a/addons/web/static/src/js/core/session.js b/addons/web/static/src/js/core/session.js index e17b1b0c7fc..4760867e99f 100644 --- a/addons/web/static/src/js/core/session.js +++ b/addons/web/static/src/js/core/session.js @@ -29,7 +29,8 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, { "override_session" is set to true. */ init: function (parent, origin, options) { - mixins.EventDispatcherMixin.init.call(this, parent); + mixins.EventDispatcherMixin.init.call(this); + this.setParent(parent); options = options || {}; this.module_list = (options.modules && options.modules.slice()) || (window.odoo._modules && window.odoo._modules.slice()) || []; this.server = null; diff --git a/addons/web/static/src/js/core/utils.js b/addons/web/static/src/js/core/utils.js index 0b4af722203..1bdd9e70a69 100644 --- a/addons/web/static/src/js/core/utils.js +++ b/addons/web/static/src/js/core/utils.js @@ -301,37 +301,6 @@ var utils = { return fn(mod, Math.floor(x)); }, /** - * Topological sort of nodes - * - * @param {Object} nodes where key is name of node, and value is list of - * names of dependent nodes. - * @param {string[]} nodes[name] list of named dependencies of node having - * 'name' as its name. - * @return {string[]} topological sort of nodes by their names. - * @throws {Error} if there is at least one circular - * dependency between nodes - */ - topologicalSort: function (nodes) { - var sorted = []; - var unresolved = nodes; - while (!_.isEmpty(unresolved)) { - // Get all nodes that have no dependency - var resolvable = _.pick(unresolved, function (dependencies, name) { - return _.isEmpty(_.difference(dependencies, sorted)); - }); - if (_.isEmpty(resolvable)) { - throw new Error("Circular dependency detected"); - } - // Append them to sorted - sorted = _.union(sorted, _.keys(resolvable)); - // Remove these nodes from unresolved - _.each(resolvable, function (dependencies, name) { - unresolved = _.omit(unresolved, name); - }); - } - return sorted; - }, - /** * performs a half up rounding with a fixed amount of decimals, correcting for float loss of precision * See the corresponding float_round() in server/tools/float_utils.py for more info * @param {Number} value the value to be rounded |
