summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js/core
diff options
context:
space:
mode:
authorVincent Schippefilt <vsc@odoo.com>2019-03-06 14:02:32 +0100
committerAaron Bohy <aab@odoo.com>2019-03-06 20:07:17 +0100
commitab56e637b7f97ddcdbcc9baea99ae097e342409c (patch)
tree4cb47da9f7ef89b19d18429220a7507470ec12a9 /addons/web/static/src/js/core
parenteeed894fd50e477135e1ac9a82f6e98ce063ab90 (diff)
[REF] web: adapt code after jQuery update
Part of task 1896658 Co-authored-by: Aaron Bohy <aab@odoo.com> Co-authored-by: Christophe Matthieu <chm@odoo.com> Co-authored-by: Mathieu Duckerts-Antoine <dam@odoo.com> Co-authored-by: David Monjoie <dmo@odoo.com> Co-authored-by: Martin Geubelle <mge@odoo.com> Co-authored-by: svs-odoo <svs@odoo.com> Co-authored-by: Vincent Schippefilt <vsc@odoo.com>
Diffstat (limited to 'addons/web/static/src/js/core')
-rw-r--r--addons/web/static/src/js/core/ajax.js325
-rw-r--r--addons/web/static/src/js/core/concurrency.js239
-rw-r--r--addons/web/static/src/js/core/dialog.js10
-rw-r--r--addons/web/static/src/js/core/dom.js21
-rw-r--r--addons/web/static/src/js/core/misc.js4
-rw-r--r--addons/web/static/src/js/core/mixins.js31
-rw-r--r--addons/web/static/src/js/core/mvc.js11
-rw-r--r--addons/web/static/src/js/core/rpc.js2
-rw-r--r--addons/web/static/src/js/core/service_mixins.js92
-rw-r--r--addons/web/static/src/js/core/session.js68
-rw-r--r--addons/web/static/src/js/core/translation.js4
-rw-r--r--addons/web/static/src/js/core/widget.js34
12 files changed, 427 insertions, 414 deletions
diff --git a/addons/web/static/src/js/core/ajax.js b/addons/web/static/src/js/core/ajax.js
index 509126498bc..8e7216c7b00 100644
--- a/addons/web/static/src/js/core/ajax.js
+++ b/addons/web/static/src/js/core/ajax.js
@@ -3,22 +3,19 @@ odoo.define('web.ajax', function (require) {
var config = require('web.config');
var core = require('web.core');
-var utils = require('web.utils');
var time = require('web.time');
var download = require('web.download');
var contentdisposition = require('web.contentdisposition');
var _t = core._t;
-function genericJsonRpc (fct_name, params, settings, fct) {
+function _genericJsonRpc (fct_name, params, settings, fct) {
var shadow = settings.shadow || false;
delete settings.shadow;
if (!shadow) {
core.bus.trigger('rpc_request');
}
- var deferred = $.Deferred();
-
var data = {
jsonrpc: "2.0",
method: fct_name,
@@ -26,7 +23,7 @@ function genericJsonRpc (fct_name, params, settings, fct) {
id: Math.floor(Math.random() * 1000 * 1000 * 1000)
};
var xhr = fct(data);
- var result = xhr.pipe(function(result) {
+ var result = xhr.then(function(result) {
core.bus.trigger('rpc:result', data, result);
if (result.error !== undefined) {
if (result.error.data.arguments[0] !== "bus.Bus not available in test mode") {
@@ -36,65 +33,86 @@ function genericJsonRpc (fct_name, params, settings, fct) {
console.error("Server application error", JSON.stringify(result.error));
}
}
- return $.Deferred().reject("server", result.error);
+ return Promise.reject({type: "server", error: result.error});
} else {
return result.result;
}
}, function() {
//console.error("JsonRPC communication error", _.toArray(arguments));
- var def = $.Deferred();
- return def.reject.apply(def, ["communication"].concat(_.toArray(arguments)));
+ var reason = {
+ type: 'communication',
+ error: arguments[0],
+ textStatus: arguments[1],
+ errorThrown: arguments[2],
+ };
+ return Promise.reject(reason);
});
- deferred.abort = function () {
- deferred.reject({message: "XmlHttpRequestError abort"}, $.Event('abort'));
- if (xhr.abort) {
- xhr.abort();
- }
- };
- result.then(function (result) {
- if (!shadow) {
- core.bus.trigger('rpc_response');
- }
- deferred.resolve(result);
- }, function (type, error, textStatus, errorThrown) {
- if (type === "server") {
+ var rejection;
+ var promise = new Promise(function (resolve, reject) {
+ rejection = reject;
+
+ result.then(function (result) {
if (!shadow) {
core.bus.trigger('rpc_response');
}
- if (error.code === 100) {
- core.bus.trigger('invalidate_session');
- }
- deferred.reject(error, $.Event());
- } else {
- if (!shadow) {
- core.bus.trigger('rpc_response_failed');
+ resolve(result);
+ }, function (reason) {
+ var type = reason.type;
+ var error = reason.error;
+ var textStatus = reason.textStatus;
+ var errorThrown = reason.errorThrown;
+ if (type === "server") {
+ if (!shadow) {
+ core.bus.trigger('rpc_response');
+ }
+ if (error.code === 100) {
+ core.bus.trigger('invalidate_session');
+ }
+ reject({message: error, event: $.Event()});
+ } else {
+ if (!shadow) {
+ core.bus.trigger('rpc_response_failed');
+ }
+ var nerror = {
+ code: -32098,
+ message: "XmlHttpRequestError " + errorThrown,
+ data: {
+ type: "xhr"+textStatus,
+ debug: error.responseText,
+ objects: [error, errorThrown]
+ },
+ };
+ reject({message: nerror, event: $.Event()});
}
- var nerror = {
- code: -32098,
- message: "XmlHttpRequestError " + errorThrown,
- data: {
- type: "xhr"+textStatus,
- debug: error.responseText,
- objects: [error, errorThrown]
- },
- };
- deferred.reject(nerror, $.Event());
- }
+ });
});
- deferred.fail(function () { // Allow deferred user to disable rpc_error call in fail
- deferred.fail(function (error, event) {
- if (!event.isDefaultPrevented()) {
- core.bus.trigger('rpc_error', error, event);
- }
+
+ // FIXME: jsonp?
+ promise.abort = function () {
+ rejection({
+ message: "XmlHttpRequestError abort",
+ event: $.Event('abort')
});
+ if (xhr.abort) {
+ xhr.abort();
+ }
+ };
+ promise.guardedCatch(function (reason) { // Allow promise user to disable rpc_error call in case of failure
+ setTimeout(function () {
+ // we want to execute this handler after all others (hence
+ // setTimeout) to let the other handlers prevent the event
+ if (!reason.event.isDefaultPrevented()) {
+ core.bus.trigger('rpc_error', reason.message, reason.event);
+ }
+ }, 0);
});
- return deferred;
-}
+ return promise;
+};
function jsonRpc(url, fct_name, params, settings) {
settings = settings || {};
- return genericJsonRpc(fct_name, params, settings, function(data) {
+ return _genericJsonRpc(fct_name, params, settings, function(data) {
return $.ajax(url, _.extend({}, settings, {
url: url,
dataType: 'json',
@@ -110,19 +128,6 @@ function rpc(url, params, settings) {
return jsonRpc(url, 'call', params, settings);
}
-// helper
-function realSetTimeout (fct, millis) {
- var finished = new Date().getTime() + millis;
- var wait = function() {
- var current = new Date().getTime();
- if (current < finished) {
- setTimeout(wait, finished - current);
- } else {
- fct();
- }
- };
- setTimeout(wait, millis);
-}
/**
* Load css asynchronously: fetch it from the url parameter and add a link tag
@@ -131,26 +136,27 @@ function realSetTimeout (fct, millis) {
* immediately.
*
* @param {String} url of the css to be fetched
- * @returns {Deferred} resolved when the css has been loaded.
+ * @returns {Promise} resolved when the css has been loaded.
*/
var loadCSS = (function () {
- var urlDefs = Object.create(null);
+ var urlDefs = {};
return function loadCSS(url) {
if (url in urlDefs) {
// nothing to do here
} else if ($('link[href="' + url + '"]').length) {
- // the link is already in the DOM, the deferred can be resolved
- urlDefs[url] = $.when();
+ // the link is already in the DOM, the promise can be resolved
+ urlDefs[url] = Promise.resolve();
} else {
var $link = $('<link>', {
'href': url,
'rel': 'stylesheet',
'type': 'text/css'
});
- urlDefs[url] = $.Deferred();
- $link.on('load', function () {
- urlDefs[url].resolve();
+ urlDefs[url] = new Promise(function (resolve, reject) {
+ $link.on('load', function () {
+ resolve();
+ });
});
$('head').append($link);
}
@@ -159,44 +165,45 @@ var loadCSS = (function () {
})();
var loadJS = (function () {
- var urls = [];
- var defs = [];
+ var dependenciesPromise = {};
var load = function loadJS(url) {
// Check the DOM to see if a script with the specified url is already there
var alreadyRequired = ($('script[src="' + url + '"]').length > 0);
- // If loadJS was already called with the same URL, it will have a registered deferred indicating if
- // the script has been fully loaded. If not, the deferred has to be initialized. This is initialized
- // as already resolved if the script was already there without the need of loadJS.
- var index = _.indexOf(urls, url);
- if (index < 0) {
- urls.push(url);
- index = defs.push(alreadyRequired ? $.when() : $.Deferred()) - 1;
+ // If loadJS was already called with the same URL, it will have a registered promise indicating if
+ // the script has been fully loaded. If not, the promise has to be initialized.
+ // This is initialized as already resolved if the script was already there without the need of loadJS.
+ if (url in dependenciesPromise) {
+ return dependenciesPromise[url];
}
+ var scriptLoadedPromise = new Promise(function (resolve, reject) {
+ if (alreadyRequired) {
+ resolve();
+ } else {
+ // Get the script associated promise and returns it after initializing the script if needed. The
+ // promise is marked to be resolved on script load and rejected on script error.
+ var script = document.createElement('script');
+ script.type = 'text/javascript';
+ script.src = url;
+ script.onload = script.onreadystatechange = function() {
+ if ((script.readyState && script.readyState !== "loaded" && script.readyState !== "complete") || script.onload_done) {
+ return;
+ }
+ script.onload_done = true;
+ resolve(url);
+ };
+ script.onerror = function () {
+ console.error("Error loading file", script.src);
+ reject(url);
+ };
+ var head = document.head || document.getElementsByTagName('head')[0];
+ head.appendChild(script);
+ }
+ });
- // Get the script associated deferred and returns it after initializing the script if needed. The
- // deferred is marked to be resolved on script load and rejected on script error.
- var def = defs[index];
- if (!alreadyRequired) {
- var script = document.createElement('script');
- script.type = 'text/javascript';
- script.src = url;
- script.onload = script.onreadystatechange = function() {
- if ((script.readyState && script.readyState !== "loaded" && script.readyState !== "complete") || script.onload_done) {
- return;
- }
- script.onload_done = true;
- def.resolve(url);
- };
- script.onerror = function () {
- console.error("Error loading file", script.src);
- def.reject(url);
- };
- var head = document.head || document.getElementsByTagName('head')[0];
- head.appendChild(script);
- }
- return def;
+ dependenciesPromise[url] = scriptLoadedPromise;
+ return scriptLoadedPromise;
};
return load;
@@ -308,22 +315,6 @@ function get_file(options) {
}
function post (controller_url, data) {
-
- var progressHandler = function (deferred) {
- return function (state) {
- if(state.lengthComputable) {
- deferred.notify({
- h_loaded: utils.human_size(state.loaded),
- h_total : utils.human_size(state.total),
- loaded : state.loaded,
- total : state.total,
- pcent : Math.round((state.loaded/state.total)*100)
- });
- }
- };
- };
-
- var Def = $.Deferred();
var postData = new FormData();
$.each(data, function(i,val) {
@@ -333,25 +324,20 @@ function post (controller_url, data) {
postData.append('csrf_token', core.csrf_token);
}
- var xhr = new XMLHttpRequest();
- if(xhr.upload) xhr.upload.addEventListener('progress', progressHandler(Def), false);
-
- var ajaxDef = $.ajax(controller_url, {
- xhr: function() {return xhr;},
- data: postData,
- processData: false,
- contentType: false,
- type: 'POST'
- }).then(function (data) {Def.resolve(data);})
- .fail(function (data) {Def.reject(data);});
-
- return Def;
+ return new Promise(function (resolve, reject) {
+ $.ajax(controller_url, {
+ data: postData,
+ processData: false,
+ contentType: false,
+ type: 'POST'
+ }).then(resolve).fail(reject);
+ });
}
/**
* Loads an XML file according to the given URL and adds its associated qweb
* templates to the given qweb engine. The function can also be used to get
- * the deferred which indicates when all the calls to the function are finished.
+ * the promise which indicates when all the calls to the function are finished.
*
* Note: "all the calls" = the calls that happened before the current no-args
* one + the calls that will happen after but when the previous ones are not
@@ -359,8 +345,8 @@ function post (controller_url, data) {
*
* @param {string} [url] - an URL where to find qweb templates
* @param {QWeb} [qweb] - the engine to which the templates need to be added
- * @returns {Deferred}
- * If no argument is given to the function, the deferred's state
+ * @returns {Promise}
+ * If no argument is given to the function, the promise's state
* indicates if "all the calls" are finished (see main description).
* Otherwise, it indicates when the templates associated to the given
* url have been loaded.
@@ -369,63 +355,64 @@ var loadXML = (function () {
// Some "static" variables associated to the loadXML function
var isLoading = false;
var loadingsData = [];
- var allLoadingsDef = $.when();
var seenURLs = [];
return function (url, qweb) {
- // If no argument, simply returns the deferred which indicates when
+ function _load() {
+ isLoading = true;
+ if (loadingsData.length) {
+ // There is something to load, load it, resolve the associated
+ // promise then start loading the next one
+ var loadingData = loadingsData[0];
+ loadingData.qweb.add_template(loadingData.url, function () {
+ // Remove from array only now so that multiple calls to
+ // loadXML with the same URL returns the right promise
+ loadingsData.shift();
+ loadingData.resolve();
+ _load();
+ });
+ } else {
+ // There is nothing to load anymore, so resolve the
+ // "all the calls" promise
+ isLoading = false;
+ }
+ }
+
+ // If no argument, simply returns the promise which indicates when
// "all the calls" are finished
if (!url || !qweb) {
- return allLoadingsDef;
+ return Promise.resolve();
}
// If the given URL has already been seen, do nothing but returning the
- // associated deferred
+ // associated promise
if (_.contains(seenURLs, url)) {
var oldLoadingData = _.findWhere(loadingsData, {url: url});
- return oldLoadingData ? oldLoadingData.def : $.when();
+ return oldLoadingData ? oldLoadingData.def : Promise.resolve();
}
seenURLs.push(url);
+
// Add the information about the new data to load: the url, the qweb
- // engine and the associated deferred
+ // engine and the associated promise
var newLoadingData = {
url: url,
qweb: qweb,
- def: $.Deferred(),
};
+ newLoadingData.def = new Promise(function (resolve, reject) {
+ newLoadingData.resolve = resolve;
+ newLoadingData.reject = reject;
+ });
loadingsData.push(newLoadingData);
// If not already started, start the loading loop (reinitialize the
- // "all the calls" deferred to an unresolved state)
+ // "all the calls" promise to an unresolved state)
if (!isLoading) {
- allLoadingsDef = $.Deferred();
_load();
}
- // Return the deferred associated to the new given URL
+ // Return the promise associated to the new given URL
return newLoadingData.def;
-
- function _load() {
- isLoading = true;
- if (loadingsData.length) {
- // There is something to load, load it, resolve the associated
- // deferred then start loading the next one
- var loadingData = loadingsData[0];
- loadingData.qweb.add_template(loadingData.url, function () {
- // Remove from array only now so that multiple calls to
- // loadXML with the same URL returns the right deferred
- loadingsData.shift();
- loadingData.def.resolve();
- _load();
- });
- } else {
- // There is nothing to load anymore, so resolve the
- // "all the calls" deferred
- isLoading = false;
- allLoadingsDef.resolve();
- }
- }
};
})();
@@ -444,7 +431,7 @@ var loadAsset = (function () {
var load = function loadAsset(xmlId) {
if (cache[xmlId]) {
- return $.when(cache[xmlId]);
+ return Promise.resolve(cache[xmlId]);
}
var params = {
args: [xmlId, {
@@ -493,22 +480,20 @@ var loadAsset = (function () {
* @param {Array<string>} [libs.assetLibs=[]] A list of xmlId. The loaded template
* contains the script and link to be loaded
*
- * @returns {Deferred}
+ * @returns {Promise}
*/
function loadLibs (libs) {
var defs = [];
- _.each(libs.jsLibs || [], function (urls) {
- defs.push($.when.apply($, defs).then(function () {
+ (libs.jsLibs || []).forEach(function (urls) {
+ defs.push(Promise.all(defs).then(function () {
if (typeof(urls) === 'string') {
return ajax.loadJS(urls);
} else {
- return $.when.apply($, _.map(urls, function (url) {
- return ajax.loadJS(url);
- }));
+ return Promise.all(urls.map(ajax.loadJS));
}
}));
});
- _.each(libs.cssLibs || [], function (url) {
+ (libs.cssLibs || []).forEach(function (url) {
defs.push(ajax.loadCSS(url));
});
_.each(libs.assetLibs || [], function (xmlId) {
@@ -516,7 +501,7 @@ function loadLibs (libs) {
return loadLibs(asset);
}));
});
- return $.when.apply($, defs);
+ return Promise.all(defs);
}
var ajax = {
diff --git a/addons/web/static/src/js/core/concurrency.js b/addons/web/static/src/js/core/concurrency.js
index 6eeebe7ff58..716abafa919 100644
--- a/addons/web/static/src/js/core/concurrency.js
+++ b/addons/web/static/src/js/core/concurrency.js
@@ -8,7 +8,7 @@ odoo.define('web.concurrency', function (require) {
* everything concurrency related in Odoo.
*
* The basic concurrency primitives in Odoo JS are the callback, and the
- * promises. Promises (deferred) are more composable, so we usually use them
+ * promises. Promises (promise) are more composable, so we usually use them
* whenever possible. We use the jQuery implementation.
*
* Those functions are really nothing special, but are simply the result of how
@@ -19,54 +19,15 @@ var Class = require('web.Class');
return {
/**
- * The jquery implementation for $.when has a (most of the time) useful
- * property: it is synchronous, if the deferred is resolved immediately.
- *
- * This means that when we execute $.when(def), then all registered
- * callbacks will be executed before the next line is executed. This is
- * useful quite often, but in some rare cases, we might want to force an
- * async behavior. This is the purpose of this function, which simply adds a
- * setTimeout before resolving the deferred.
- *
- * @returns {Deferred}
- */
- asyncWhen: function () {
- var async = false;
- var def = $.Deferred();
- $.when.apply($, arguments).done(function() {
- var args = arguments;
- var action = function() {
- def.resolve.apply(def, args);
- };
- if (async) {
- action();
- } else {
- setTimeout(action, 0);
- }
- }).fail(function() {
- var args = arguments;
- var action = function() {
- def.reject.apply(def, args);
- };
- if (async) {
- action();
- } else {
- setTimeout(action, 0);
- }
- });
- async = true;
- return def;
- },
- /**
- * Returns a deferred resolved after 'wait' milliseconds
+ * Returns a promise resolved after 'wait' milliseconds
*
* @param {int} [wait=0] the delay in ms
- * @return {Deferred}
+ * @return {Promise}
*/
delay: function (wait) {
- var def = $.Deferred();
- setTimeout(def.resolve, wait);
- return def;
+ return new Promise(function (resolve) {
+ setTimeout(resolve, wait);
+ });
},
/**
* The DropMisordered abstraction is useful for situations where you have
@@ -93,27 +54,27 @@ return {
this.failMisordered = failMisordered || false;
},
/**
- * Adds a deferred (usually an async request) to the sequencer
+ * Adds a promise (usually an async request) to the sequencer
*
- * @param {Deferred} deferred to ensure add
- * @returns {Deferred}
+ * @param {Promise} promise to ensure add
+ * @returns {Promise}
*/
- add: function (deferred) {
- var res = $.Deferred();
-
- var self = this, seq = this.lsn++;
- deferred.done(function () {
- if (seq > self.rsn) {
- self.rsn = seq;
- res.resolve.apply(res, arguments);
- } else if (self.failMisordered) {
- res.reject();
- }
- }).fail(function () {
- res.reject.apply(res, arguments);
+ add: function (promise) {
+ var self = this;
+ var seq = this.lsn++;
+ var res = new Promise(function (resolve, reject) {
+ promise.then(function (result) {
+ if (seq > self.rsn) {
+ self.rsn = seq;
+ resolve(result);
+ } else if (self.failMisordered) {
+ reject();
+ }
+ }).guardedCatch(function (result) {
+ reject(result);
+ });
});
-
- return res.promise();
+ return res;
},
}),
/**
@@ -152,17 +113,26 @@ return {
*/
DropPrevious: Class.extend({
/**
- * Registers a new deferred and rejects the previous one
+ * Registers a new promise and rejects the previous one
*
- * @param {Deferred} deferred the new deferred
+ * @param {Promise} promise the new promise
* @returns {Promise}
*/
- add: function (deferred) {
- if (this.current_def) { this.current_def.reject(); }
- var res = $.Deferred();
- deferred.then(res.resolve, res.reject);
- this.current_def = res;
- return res.promise();
+ add: function (promise) {
+ if (this.currentDef) {
+ this.currentDef.reject();
+ }
+ var rejection;
+ var res = new Promise(function (resolve, reject) {
+ rejection = reject;
+ promise.then(resolve).catch(function (reason) {
+ reject(reason);
+ });
+ });
+
+ this.currentDef = res;
+ this.currentDef.reject = rejection;
+ return res;
}
}),
/**
@@ -171,7 +141,7 @@ return {
* state and cause some corrupted state.
*
* Imagine that we have a function to fetch some data _load(), which returns
- * a deferred which resolves to something useful. Now, we have some code
+ * a promise which resolves to something useful. Now, we have some code
* looking like this::
*
* return this._load().then(function (result) {
@@ -200,37 +170,51 @@ return {
*/
Mutex: Class.extend({
init: function () {
- this.def = $.Deferred().resolve();
- this.unlockedDef = undefined;
+ this.lock = Promise.resolve();
+ this.queueSize = 0;
+ this.unlockedProm = undefined;
+ this._unlock = undefined;
},
/**
* Add a computation to the queue, it will be executed as soon as the
* previous computations are completed.
*
- * @param {function} action a function which may return a deferred
- * @returns {Deferred}
+ * @param {function} action a function which may return a Promise
+ * @returns {Promise}
*/
exec: function (action) {
var self = this;
- var current = this.def;
- var next = this.def = $.Deferred();
- this.unlockedDef = this.unlockedDef || $.Deferred();
- return current.then(function() {
- return $.when(action()).always(function () {
- next.resolve();
- if (self.def.state() === 'resolved' && self.unlockedDef) {
- self.unlockedDef.resolve();
- self.unlockedDef = undefined;
- }
+ var currentLock = this.lock;
+ var result;
+ this.queueSize++;
+ this.unlockedProm = this.unlockedProm || new Promise(function (resolve) {
+ self._unlock = resolve;
+ });
+ this.lock = new Promise(function (unlockCurrent) {
+ currentLock.then(function () {
+ result = action();
+ var always = function (returnedResult) {
+ unlockCurrent();
+ self.queueSize--;
+ if (self.queueSize === 0) {
+ self.unlockedProm = undefined;
+ self._unlock();
+ }
+ return returnedResult;
+ };
+ Promise.resolve(result).then(always).guardedCatch(always);
});
});
+ return this.lock.then(function () {
+ return result;
+ });
},
/**
* @returns {Promise} resolved as soon as the Mutex is unlocked
* (directly if it is currently idle)
*/
getUnlockedDef: function () {
- return $.when(this.unlockedDef);
+ return this.unlockedProm || Promise.resolve();
},
}),
/**
@@ -253,65 +237,86 @@ return {
*
* A MutexedDropPrevious has to be a class, and not a function, because we
* have to keep track of some internal state. The exec function takes as
- * argument an action (and not a deferred as DropPrevious for example)
+ * argument an action (and not a promise as DropPrevious for example)
* because it's the MutexedDropPrevious role to trigger the RPC call that
- * returns a deferred when it's time.
+ * returns a promise when it's time.
*/
MutexedDropPrevious: Class.extend({
init: function () {
- this.currentDef = null;
this.locked = false;
+ this.currentProm = null;
this.pendingAction = null;
- this.pendingDef = null;
+ this.pendingProm = null;
},
/**
- * @param {function} action a function which may return a deferred
- * @returns {Deferred}
+ * @param {function} action a function which may return a promise
+ * @returns {Promise}
*/
exec: function (action) {
var self = this;
+ var resolution;
+ var rejection;
if (this.locked) {
this.pendingAction = action;
- var oldPendingDef = this.pendingDef;
- var pendingDef = this.pendingDef = $.Deferred();
- if (oldPendingDef) {
- oldPendingDef.reject();
- }
- this.currentDef.reject();
- return pendingDef.promise();
+ var oldPendingDef = this.pendingProm;
+
+ this.pendingProm = new Promise(function (resolve, reject) {
+ resolution = resolve;
+ rejection = reject;
+ if (oldPendingDef) {
+ oldPendingDef.reject();
+ }
+ self.currentProm.reject();
+ });
+ this.pendingProm.resolve = resolution;
+ this.pendingProm.reject = rejection;
+ return this.pendingProm;
} else {
this.locked = true;
- this.currentDef = $.Deferred();
- $.when(action())
- .then(this.currentDef.resolve.bind(this.currentDef))
- .fail(this.currentDef.reject.bind(this.currentDef))
- .always(function () {
+ this.currentProm = new Promise(function (resolve, reject) {
+ resolution = resolve;
+ rejection = reject;
+ function unlock() {
self.locked = false;
if (self.pendingAction) {
var action = self.pendingAction;
+ var prom = self.pendingProm;
self.pendingAction = null;
+ self.pendingProm = null;
self.exec(action)
- .then(self.pendingDef.resolve.bind(self.pendingDef))
- .fail(self.pendingDef.reject.bind(self.pendingDef));
+ .then(prom.resolve)
+ .guardedCatch(prom.reject);
}
+ }
+ Promise.resolve(action())
+ .then(function (result) {
+ resolve(result);
+ unlock();
+ })
+ .guardedCatch(function (reason) {
+ reject(reason);
+ unlock();
+ });
});
- return this.currentDef.promise();
+ this.currentProm.resolve = resolution;
+ this.currentProm.reject = rejection;
+ return this.currentProm;
}
- },
+ }
}),
/**
- * Rejects a deferred as soon as a reference deferred is either resolved or
+ * Rejects a promise as soon as a reference promise is either resolved or
* rejected
*
- * @param {Deferred} [target_def] the deferred to potentially reject
- * @param {Deferred} [reference_def] the reference target
- * @returns {Deferred}
+ * @param {Promise} [target_def] the promise to potentially reject
+ * @param {Promise} [reference_def] the reference target
+ * @returns {Promise}
*/
rejectAfter: function (target_def, reference_def) {
- var res = $.Deferred();
- target_def.then(res.resolve, res.reject);
- reference_def.always(res.reject);
- return res.promise();
+ return new Promise(function (resolve, reject) {
+ target_def.then(resolve).guardedCatch(reject);
+ reference_def.then(reject).guardedCatch(reject);
+ });
}
};
diff --git a/addons/web/static/src/js/core/dialog.js b/addons/web/static/src/js/core/dialog.js
index 83eded92c8a..8630b6b9364 100644
--- a/addons/web/static/src/js/core/dialog.js
+++ b/addons/web/static/src/js/core/dialog.js
@@ -52,9 +52,11 @@ var Dialog = Widget.extend({
* (use this for non-editor frontend features)
*/
init: function (parent, options) {
+ var self = this;
this._super(parent);
- this._opened = $.Deferred();
-
+ this._opened = new Promise(function (resolve) {
+ self._openedResolver = resolve;
+ });
options = _.defaults(options || {}, {
title: _t('Odoo'), subtitle: '',
size: 'large',
@@ -140,7 +142,7 @@ var Dialog = Widget.extend({
def = buttonData.click.call(self, e);
}
if (buttonData.close) {
- $.when(def).always(self.close.bind(self));
+ Promise.resolve(def).then(self.close.bind(self)).guardedCatch(self.close.bind(self));
}
});
if (self.technical) {
@@ -185,7 +187,7 @@ var Dialog = Widget.extend({
self.$modal.attr('open', true);
self.$modal.removeAttr("aria-hidden");
self.$modal.modal('show');
- self._opened.resolve();
+ self._openedResolver();
if (options && options.shouldFocusButtons) {
self._onFocusControlButton();
}
diff --git a/addons/web/static/src/js/core/dom.js b/addons/web/static/src/js/core/dom.js
index b8a5b8be3a4..3faa5977c8c 100644
--- a/addons/web/static/src/js/core/dom.js
+++ b/addons/web/static/src/js/core/dom.js
@@ -1,11 +1,10 @@
odoo.define('web.dom_ready', function (require) {
'use strict';
-var def = $.Deferred();
-$(def.resolve.bind(def));
-return def;
+ return new Promise(function (resolve, reject) {
+ $(resolve);
+ });
});
-
//==============================================================================
odoo.define('web.dom', function (require) {
@@ -33,7 +32,7 @@ var _t = core._t;
* that on_attach_callback() will be called on each w with arguments args
*/
function _notify(content, callbacks) {
- _.each(callbacks, function (c) {
+ callbacks.forEach(function (c) {
if (c.widget && c.widget.on_attach_callback) {
c.widget.on_attach_callback(c.callback_args);
}
@@ -170,14 +169,14 @@ var dom = {
* @return {jQuery} the detached elements
*/
detach: function (to_detach, options) {
- _.each(to_detach, function (d) {
+ to_detach.forEach( function (d) {
if (d.widget.on_detach_callback) {
d.widget.on_detach_callback(d.callback_args);
}
});
var $to_detach = options && options.$to_detach;
if (!$to_detach) {
- $to_detach = $(_.map(to_detach, function (d) {
+ $to_detach = $(to_detach.map(function (d) {
return d.widget.el;
}));
}
@@ -229,7 +228,7 @@ var dom = {
* @param {function|boolean} stopPropagation
*/
makeAsyncHandler: function (fct, preventDefault, stopPropagation) {
- // Create a deferred indicating if a previous call to this handler is
+ // Create a promise indicating if a previous call to this handler is
// still pending.
var def = $.when();
@@ -284,11 +283,13 @@ var dom = {
// a 'real' debounce creation useless. Also, during the debouncing
// part, the button is disabled without any visual effect.
$button.addClass('o_debounce_disabled');
- $.when(dom.DEBOUNCE && concurrency.delay(dom.DEBOUNCE)).then(function () {
+ Promise.resolve(dom.DEBOUNCE && concurrency.delay(dom.DEBOUNCE)).then(function () {
$button.addClass('disabled').prop('disabled', true);
$button.removeClass('o_debounce_disabled');
- return $.when(result).always(function () {
+ return Promise.resolve(result).then(function () {
+ $button.removeClass('disabled').prop('disabled', false);
+ }).guardedCatch(function () {
$button.removeClass('disabled').prop('disabled', false);
});
});
diff --git a/addons/web/static/src/js/core/misc.js b/addons/web/static/src/js/core/misc.js
index cd9a73ef22b..39fd8021071 100644
--- a/addons/web/static/src/js/core/misc.js
+++ b/addons/web/static/src/js/core/misc.js
@@ -114,7 +114,7 @@ function redirect (url, wait) {
};
var wait_server = function() {
- ajax.rpc("/web/webclient/version_info", {}).done(load).fail(function() {
+ ajax.rpc("/web/webclient/version_info", {}).then(load).guardedCatch(function () {
setTimeout(wait_server, 250);
});
};
@@ -172,7 +172,7 @@ core.action_registry.add("login", login);
function logout() {
redirect('/web/session/logout');
- return $.Deferred();
+ return new Promise();
}
core.action_registry.add("logout", logout);
diff --git a/addons/web/static/src/js/core/mixins.js b/addons/web/static/src/js/core/mixins.js
index e29c97ea086..228ac2d68dd 100644
--- a/addons/web/static/src/js/core/mixins.js
+++ b/addons/web/static/src/js/core/mixins.js
@@ -62,37 +62,36 @@ var ParentedMixin = {
* Utility method to only execute asynchronous actions if the current
* object has not been destroyed.
*
- * @param {$.Deferred} promise The promise representing the asynchronous
+ * @param {Promise} promise The promise representing the asynchronous
* action.
- * @param {bool} [reject=false] If true, the returned promise will be
+ * @param {bool} [shouldReject=false] If true, the returned promise will be
* rejected with no arguments if the current
* object is destroyed. If false, the
* returned promise will never be resolved
* or rejected.
- * @returns {$.Deferred} A promise that will mirror the given promise if
+ * @returns {Promise} A promise that will mirror the given promise if
* everything goes fine but will either be rejected
* with no arguments or never resolved if the
* current object is destroyed.
*/
- alive: function (promise, reject) {
+ alive: function (promise, shouldReject) {
var self = this;
- return $.Deferred(function (def) {
- promise.then(function () {
+
+ return new Promise(function (resolve, reject) {
+ promise.then(function (result) {
if (!self.isDestroyed()) {
- def.resolve.apply(def, arguments);
+ resolve(result);
+ } else if (shouldReject) {
+ reject();
}
- }, function () {
+ }).guardedCatch(function (reason) {
if (!self.isDestroyed()) {
- def.reject.apply(def, arguments);
- }
- }).always(function () {
- if (reject) {
- // noop if def already resolved or rejected
- def.reject();
+ reject(reason);
+ } else if (shouldReject) {
+ reject();
}
- // otherwise leave promise in limbo
});
- }).promise();
+ });
},
/**
* Inform the object it should destroy itself, releasing any
diff --git a/addons/web/static/src/js/core/mvc.js b/addons/web/static/src/js/core/mvc.js
index cdef88c4211..6e0e4267caa 100644
--- a/addons/web/static/src/js/core/mvc.js
+++ b/addons/web/static/src/js/core/mvc.js
@@ -76,7 +76,7 @@ var Model = Class.extend(mixins.EventDispatcherMixin, ServicesMixin, {
* @returns {Promise} The promise resolves to some kind of handle
*/
load: function () {
- return $.when();
+ return Promise.resolve();
},
});
@@ -119,9 +119,9 @@ var Controller = Widget.extend({
* @returns {Promise}
*/
start: function () {
- return $.when(
- this._super.apply(this, arguments),
- this._startRenderer()
+ return Promise.all(
+ [this._super.apply(this, arguments),
+ this._startRenderer()]
);
},
@@ -177,7 +177,8 @@ var Factory = Class.extend({
getController: function (parent) {
var self = this;
var model = this.getModel(parent);
- return $.when(this._loadData(model), ajax.loadLibs(this)).then(function (state) {
+ return Promise.all([this._loadData(model), ajax.loadLibs(this)]).then(function (result) {
+ var state = result[0];
var renderer = self.getRenderer(parent, state);
var Controller = self.Controller || self.config.Controller;
var controllerParams = _.extend({
diff --git a/addons/web/static/src/js/core/rpc.js b/addons/web/static/src/js/core/rpc.js
index cc56cb74ebb..21ec43e3d95 100644
--- a/addons/web/static/src/js/core/rpc.js
+++ b/addons/web/static/src/js/core/rpc.js
@@ -11,7 +11,7 @@ return {
*
* @param {Object} params @see buildQuery for a description
* @param {Object} options
- * @returns {Deferred<any>}
+ * @returns {Promise<any>}
*/
query: function (params, options) {
var query = this.buildQuery(params);
diff --git a/addons/web/static/src/js/core/service_mixins.js b/addons/web/static/src/js/core/service_mixins.js
index e8088d45cb5..4f296b6bb90 100644
--- a/addons/web/static/src/js/core/service_mixins.js
+++ b/addons/web/static/src/js/core/service_mixins.js
@@ -124,7 +124,7 @@ var ServicesMixin = {
return result;
},
/**
- * Builds and executes RPC query. Returns a deferred's promise resolved with
+ * Builds and executes RPC query. Returns a promise resolved with
* the RPC result.
*
* @param {string} params either a route or a model
@@ -133,11 +133,17 @@ var ServicesMixin = {
*/
_rpc: function (params, options) {
var query = rpc.buildQuery(params);
- var def = this.call('ajax', 'rpc', query.route, query.params, options, this) || $.Deferred();
- var promise = def.promise();
- var abort = (def.abort ? def.abort : def.reject) || function () {};
- promise.abort = abort.bind(def);
- return promise;
+ var prom = this.call('ajax', 'rpc', query.route, query.params, options, this);
+ if (!prom) {
+ prom = new Promise(function () {});
+ prom.abort = function () {};
+ }
+ var abort = prom.abort ? prom.abort : prom.reject;
+ if (!abort) {
+ throw new Error("a rpc promise should always have a reject function");
+ }
+ prom.abort = abort.bind(prom);
+ return prom;
},
loadFieldView: function (modelName, context, view_id, view_type, options) {
return this.loadViews(modelName, context, [[view_id, view_type]], options).then(function (result) {
@@ -145,41 +151,45 @@ var ServicesMixin = {
});
},
loadViews: function (modelName, context, views, options) {
- var def = $.Deferred();
- this.trigger_up('load_views', {
- modelName: modelName,
- context: context,
- views: views,
- options: options,
- on_success: def.resolve.bind(def),
+ var self = this;
+ return new Promise(function (resolve) {
+ self.trigger_up('load_views', {
+ modelName: modelName,
+ context: context,
+ views: views,
+ options: options,
+ on_success: resolve,
+ });
});
- return def;
},
loadFilters: function (modelName, actionId, context) {
- var def = $.Deferred();
- this.trigger_up('load_filters', {
- modelName: modelName,
- actionId: actionId,
- context: context,
- on_success: def.resolve.bind(def),
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ self.trigger_up('load_filters', {
+ modelName: modelName,
+ actionId: actionId,
+ context: context,
+ on_success: resolve,
+ });
});
- return def;
},
createFilter: function (filter) {
- var def = $.Deferred();
- this.trigger_up('create_filter', {
- filter: filter,
- on_success: def.resolve.bind(def),
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ self.trigger_up('create_filter', {
+ filter: filter,
+ on_success: resolve,
+ });
});
- return def;
},
deleteFilter: function (filterId) {
- var def = $.Deferred();
- this.trigger_up('delete_filter', {
- filterId: filterId,
- on_success: def.resolve.bind(def),
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ self.trigger_up('delete_filter', {
+ filterId: filterId,
+ on_success: resolve,
+ });
});
- return def;
},
// Session stuff
getSession: function () {
@@ -195,22 +205,22 @@ var ServicesMixin = {
* Informs the action manager to do an action. This supposes that the action
* manager can be found amongst the ancestors of the current widget.
* If that's not the case this method will simply return an unresolved
- * deferred.
+ * promise.
*
* @param {any} action
* @param {any} options
- * @returns {Deferred}
+ * @returns {Promise}
*/
do_action: function (action, options) {
- var def = $.Deferred();
-
- this.trigger_up('do_action', {
- action: action,
- options: options,
- on_success: function (result) { def.resolve(result); },
- on_fail: function (result) { def.reject(result); },
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ self.trigger_up('do_action', {
+ action: action,
+ options: options,
+ on_success: resolve,
+ on_fail: reject,
+ });
});
- return def;
},
do_notify: function (title, message, sticky, className) {
return this.call('notification', 'notify', {title: title, message: message, sticky: sticky, className: className});
diff --git a/addons/web/static/src/js/core/session.js b/addons/web/static/src/js/core/session.js
index 14886591d7b..2874a2ea559 100644
--- a/addons/web/static/src/js/core/session.js
+++ b/addons/web/static/src/js/core/session.js
@@ -84,27 +84,27 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
*/
session_init: function () {
var self = this;
- var def = this.session_reload();
+ var prom = this.session_reload();
if (this.is_frontend) {
- return def.then(function () {
+ return prom.then(function () {
return self.load_translations();
});
}
- return def.then(function () {
+ return prom.then(function () {
var modules = self.module_list.join(',');
- var deferred = self.load_qweb(modules);
+ var promise = self.load_qweb(modules);
if (self.session_is_valid()) {
- return deferred.then(function () { return self.load_modules(); });
+ return promise.then(function () { return self.load_modules(); });
}
- return $.when(
- deferred,
+ return Promise.all([
+ promise,
self.rpc('/web/webclient/bootstrap_translations', {mods: self.module_list})
.then(function (trans) {
_t.database.set_bundle(trans);
})
- );
+ ]);
});
},
session_is_valid: function () {
@@ -119,7 +119,7 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
*/
session_authenticate: function () {
var self = this;
- return $.when(this._session_authenticate.apply(this, arguments)).then(function () {
+ return Promise.resolve(this._session_authenticate.apply(this, arguments)).then(function () {
return self.load_modules();
});
},
@@ -131,7 +131,7 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
var params = {db: db, login: login, password: password};
return this.rpc("/web/session/authenticate", params).then(function (result) {
if (!result.uid) {
- return $.Deferred().reject();
+ return Promise.reject();
}
_.extend(self, result);
});
@@ -142,7 +142,7 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
},
user_has_group: function (group) {
if (!this.uid) {
- return $.when(false);
+ return Promise.resolve(false);
}
var def = this._groups_def[group];
if (!def) {
@@ -196,22 +196,24 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
var to_load = _.difference(modules, self.module_list).join(',');
this.module_list = all_modules;
- var loaded = $.when(self.load_translations());
+ var loaded = Promise.resolve(self.load_translations());
var locale = "/web/webclient/locale/" + self.user_context.lang || 'en_US';
var file_list = [ locale ];
if(to_load.length) {
- loaded = $.when(
+ loaded = Promise.all([
loaded,
- self.rpc('/web/webclient/csslist', {mods: to_load}).done(self.load_css.bind(self)),
+ self.rpc('/web/webclient/csslist', {mods: to_load})
+ .then(self.load_css.bind(self)),
self.load_qweb(to_load),
- self.rpc('/web/webclient/jslist', {mods: to_load}).done(function (files) {
- file_list = file_list.concat(files);
- })
- );
+ self.rpc('/web/webclient/jslist', {mods: to_load})
+ .then(function (files) {
+ file_list = file_list.concat(files);
+ })
+ ]);
}
return loaded.then(function () {
return self.load_js(file_list);
- }).done(function () {
+ }).then(function () {
self.on_modules_loaded();
self.trigger('module_loaded');
});
@@ -227,24 +229,24 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
},
load_js: function (files) {
var self = this;
- var d = $.Deferred();
- if (files.length !== 0) {
- var file = files.shift();
- var url = self.url(file, null);
- ajax.loadJS(url).done(d.resolve);
- } else {
- d.resolve();
- }
- return d;
+ return new Promise(function (resolve, reject) {
+ if (files.length !== 0) {
+ var file = files.shift();
+ var url = self.url(file, null);
+ ajax.loadJS(url).then(resolve);
+ } else {
+ resolve();
+ }
+ });
},
load_qweb: function (mods) {
- this.qweb_mutex.exec(function () {
+ var lock = this.qweb_mutex.exec(function () {
return $.get('/web/webclient/qweb?mods=' + mods).then(function (doc) {
if (!doc) { return; }
qweb.add_template(doc);
});
});
- return this.qweb_mutex.def;
+ return lock;
},
on_modules_loaded: function () {
var openerp = window.openerp;
@@ -276,12 +278,12 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
* (re)loads the content of a session: db name, username, user id, session
* context and status of the support contract
*
- * @returns {$.Deferred} deferred indicating the session is done reloading
+ * @returns {Promise} promise indicating the session is done reloading
*/
session_reload: function () {
var result = _.extend({}, window.odoo.session_info);
_.extend(this, result);
- return $.when();
+ return Promise.resolve();
},
/**
* Executes an RPC call, registering the provided callbacks.
@@ -293,7 +295,7 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
* @param {String} url RPC endpoint
* @param {Object} params call parameters
* @param {Object} options additional options for rpc call
- * @returns {jQuery.Deferred} jquery-provided ajax deferred
+ * @returns {Promise}
*/
rpc: function (url, params, options) {
var self = this;
diff --git a/addons/web/static/src/js/core/translation.js b/addons/web/static/src/js/core/translation.js
index 76493fdb432..83c556c3c37 100644
--- a/addons/web/static/src/js/core/translation.js
+++ b/addons/web/static/src/js/core/translation.js
@@ -58,14 +58,14 @@ var TranslationDataBase = Class.extend(/** @lends instance.TranslationDataBase#
@param {Object} [lang] lang The language. If not specified it will default to the language
of the current user.
@param {string} [url='/web/webclient/translations']
- @returns {jQuery.Deferred}
+ @returns {Promise}
*/
load_translations: function(session, modules, lang, url) {
var self = this;
return session.rpc(url || '/web/webclient/translations', {
"mods": modules || null,
"lang": lang || null
- }).done(function(trans) {
+ }).then(function (trans) {
self.set_bundle(trans);
});
}
diff --git a/addons/web/static/src/js/core/widget.js b/addons/web/static/src/js/core/widget.js
index d3b9cc1033c..0de8c6aa1cd 100644
--- a/addons/web/static/src/js/core/widget.js
+++ b/addons/web/static/src/js/core/widget.js
@@ -31,7 +31,7 @@ var ServicesMixin = require('web.ServicesMixin');
* },
* willStart: function () {
* // async work that need to be done before the widget is ready
- * // this method should return a deferred
+ * // this method should return a promise
* },
* start: function() {
* // stuff you want to make after the rendering, `this.$el` holds a correct value
@@ -135,45 +135,47 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, {
* Method called between @see init and @see start. Performs asynchronous
* calls required by the rendering and the start method.
*
- * This method should return a Deferred which is resolved when start can be
+ * This method should return a Promose which is resolved when start can be
* executed.
*
- * @returns {Deferred}
+ * @returns {Promise}
*/
willStart: function () {
- var defs = [];
+ var proms = [];
if (this.xmlDependencies) {
- defs.push.apply(defs, _.map(this.xmlDependencies, function (xmlPath) {
+ proms.push.apply(proms, _.map(this.xmlDependencies, function (xmlPath) {
return ajax.loadXML(xmlPath, core.qweb);
}));
}
if (this.jsLibs || this.cssLibs || this.assetLibs) {
- defs.push(ajax.loadLibs(this));
+ proms.push(ajax.loadLibs(this));
}
- return $.when.apply($, defs);
+ return Promise.all(proms);
},
/**
* Method called after rendering. Mostly used to bind actions, perform
* asynchronous calls, etc...
*
* By convention, this method should return an object that can be passed to
- * $.when() to inform the caller when this widget has been initialized.
+ * Promise.resolve() to inform the caller when this widget has been initialized.
*
* Note that, for historic reasons, many widgets still do work in the start
* method that would be more suited to the willStart method.
*
- * @returns {Deferred}
+ * @returns {Promise}
*/
start: function () {
- return $.when();
+ return Promise.resolve();
},
/**
* Destroys the current widget, also destroys all its children before
* destroying itself.
*/
destroy: function () {
- _.invoke(this.getChildren(), 'destroy');
- if(this.$el) {
+ this.getChildren().forEach(function (child) {
+ child.destroy();
+ });
+ if (this.$el) {
this.$el.remove();
}
mixins.PropertiesMixin.destroy.call(this);
@@ -187,6 +189,7 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, {
* Renders the current widget and appends it to the given jQuery object.
*
* @param {jQuery} target
+ * @returns {Promise}
*/
appendTo: function (target) {
var self = this;
@@ -198,6 +201,7 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, {
* Attach the current widget to a dom element
*
* @param {jQuery} target
+ * @returns {Promise}
*/
attachTo: function (target) {
var self = this;
@@ -234,6 +238,7 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, {
* object.
*
* @param {jQuery} target
+ * @returns {Promise}
*/
insertAfter: function (target) {
var self = this;
@@ -246,6 +251,7 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, {
* object.
*
* @param {jQuery} target
+ * @returns {Promise}
*/
insertBefore: function (target) {
var self = this;
@@ -257,6 +263,7 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, {
* Renders the current widget and prepends it to the given jQuery object.
*
* @param {jQuery} target
+ * @returns {Promise}
*/
prependTo: function (target) {
var self = this;
@@ -282,6 +289,7 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, {
* Renders the current widget and replaces the given jQuery object.
*
* @param target A jQuery object or a Widget instance.
+ * @returns {Promise}
*/
replace: function (target) {
return this._widgetRenderAndInsert(_.bind(function (t) {
@@ -415,7 +423,7 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, {
* @private
* @param {function: jQuery -> any} insertion
* @param {jQuery} target
- * @returns {Deferred}
+ * @returns {Promise}
*/
_widgetRenderAndInsert: function (insertion, target) {
var self = this;