diff options
| author | Géry Debongnie <ged@odoo.com> | 2015-03-09 16:34:27 +0100 |
|---|---|---|
| committer | Géry Debongnie <ged@odoo.com> | 2015-03-18 09:01:49 +0100 |
| commit | e8a00bc50da435d3859118ca127d20a2eb9a0cab (patch) | |
| tree | 039f6ec40b37392e76c8830a8e518ac40f7e7fec /addons/web/static/src/js/boot.js | |
| parent | 9036084f065c7aca3b2199903f4da67db3501ba7 (diff) | |
[REF] web: add module system to the web client
This commit introduces a new module system for the javascript code.
Instead of using global (namespaced) variables everywhere (like
openerp.web.whatever, ...), each file declare one (or more) module
with its dependencies. Each module will be loaded after its
dependencies, and will be given a reference to the return values.
This change is a massive departure from the way the client worked
previously. It will sadly break some/most history, but I am sure that
the future git ecosystem will allow you to easily browse the history
past this revision (one can dream).
This commit feature:
* main namespace is now odoo instead of openerp
* a way to define modules and dependencies (inspired by requirejs)
* many files have been splitted in simpler subfiles
* basic support for debugging in odoo.__DEBUG__
* no global variable (i.e. nothing in window.openerp)
* many bug fixes, many new bugs
Future vision: this modularization should simplify future code
development, simplify debugging and will allow a serious testing effort
Diffstat (limited to 'addons/web/static/src/js/boot.js')
| -rw-r--r-- | addons/web/static/src/js/boot.js | 159 |
1 files changed, 119 insertions, 40 deletions
diff --git a/addons/web/static/src/js/boot.js b/addons/web/static/src/js/boot.js index 5fad3d0a140..67834ebf6b2 100644 --- a/addons/web/static/src/js/boot.js +++ b/addons/web/static/src/js/boot.js @@ -6,50 +6,129 @@ * @name openerp * @namespace openerp */ + (function() { - // copy everything in the openerp namespace to openerp.web - openerp.web = _.clone(openerp); - - var inited = false; - - _.extend(openerp, { - // Per session namespace - // openerp.<module> will map to - // openerp.instances.sessionname.<module> using a closure - instances: {instance0: openerp}, - // links to the global openerp - _openerp: openerp, - // this unique id will be replaced by hostname_databasename by - // openerp.web.Session on the first connection - _session_id: "instance0", - _modules: openerp._modules || ['web'], - web_mobile: {}, - /** - * OpenERP instance constructor - * - * @param {Array|String} modules list of modules to initialize - */ - init: function(modules) { - if (modules === undefined) { - modules = openerp._modules; + "use strict"; + + var jobs = []; + var factories = Object.create(null); + var job_names = []; + var job_deps = []; + + var services = Object.create({ + qweb: new QWeb2.Engine(), + $: $, + _: _, + }); + + var debug = ($.deparam($.param.querystring()).debug !== undefined); + + var odoo = window.odoo = { + testing: typeof QUnit === "object", + debug: debug, + + __DEBUG__: { + get_dependencies: function (name, transitive) { + var deps = name instanceof Array ? name: [name], + changed; + do { + changed = false; + _.each(job_deps, function (dep) { + if (_.contains(deps, dep.to) && (!_.contains(deps, dep.from))) { + deps.push(dep.from); + changed = true; + } + }); + } while (changed && transitive) + return deps; + }, + get_dependents: function (name) { + return _.pluck(_.where(job_deps, {from: name}), 'to'); + }, + factories: factories, + services: services, + }, + define: function () { + var args = Array.prototype.slice.call(arguments), + name = typeof args[0] === 'string' ? args.shift() : _.uniqueId('__job'), + deps = args[0] instanceof Array ? args.shift() : [], + factory = args[0]; + + if (odoo.debug) { + if (!(deps instanceof Array)) { + throw new Error ('Dependencies should be defined by an array', deps); + } + if (typeof factory !== 'function') { + throw new Error ('Factory should be defined by a function', factory); + } + if (typeof name !== 'string') { + throw new Error("Invalid name definition (should be a string", name); + } + if (name in factories) { + throw new Error("Service " + name + " already defined"); + } } - modules = _.without(modules, "web"); - if (inited) - throw new Error("OpenERP was already inited"); - inited = true; - for(var i=0; i < modules.length; i++) { - var fct = openerp[modules[i]]; - if (typeof(fct) === "function") { - openerp[modules[i]] = {}; - for (var k in fct) { - openerp[modules[i]][k] = fct[k]; + + factory.deps = deps; + factories[name] = factory; + + jobs.push({ + name: name, + factory: factory, + deps: deps, + }); + + job_names.push(name); + _.each(deps, function (dep) { + job_deps.push({from:dep, to:name}); + }); + + this.process_jobs(jobs, services); + }, + init: function () { + odoo.__DEBUG__.remaining_jobs = jobs; + odoo.__DEBUG__.web_client = services['web.web_client']; + + if (jobs.length) { + console.warn('Warning: not all jobs could be started.', jobs); + } + // _.each(factories, function (value, key) { + // delete factories[key]; + // }); + }, + process_jobs: function (jobs, services) { + var job, require; + while (jobs.length && (job = _.find(jobs, is_ready))) { + require = make_require(job); + + services[job.name] = job.factory.call(null, require); + if (require.__require_calls !== job.deps.length) { + console.warn('Job ' + job.name + ' did not require all its dependencies'); + } + jobs.splice(jobs.indexOf(job), 1); + } + return services; + + function is_ready (job) { + return _.every(job.factory.deps, function (name) { return name in services; }); + } + + function make_require (job) { + var deps = _.pick(services, job.deps); + + function require (name) { + if (!(name in deps)) { + console.error('Undefined dependency: ', name); + } else { + require.__require_calls++; } - fct(openerp, openerp[modules[i]]); + return deps[name]; } + + require.__require_calls = 0; + return require; } - openerp._modules = ['web'].concat(modules); - return openerp; } - }); -})(); + }; +})(); |
