diff --git a/addons/website/static/src/js/backend/dashboard.js b/addons/website/static/src/js/backend/dashboard.js index 0ec306c10f7..9f539cbe03e 100644 --- a/addons/website/static/src/js/backend/dashboard.js +++ b/addons/website/static/src/js/backend/dashboard.js @@ -42,7 +42,7 @@ var Dashboard = AbstractAction.extend({ willStart: function() { var self = this; - return $.when(ajax.loadLibs(this), this._super()).then(function() { + return Promise.all([ajax.loadLibs(this), this._super()]).then(function() { return self.fetch_data(); }).then(function(){ var website = _.findWhere(self.websites, {selected: true}); @@ -63,20 +63,22 @@ var Dashboard = AbstractAction.extend({ */ fetch_data: function() { var self = this; - return this._rpc({ + var prom = this._rpc({ route: '/website/fetch_dashboard_data', params: { website_id: this.website_id || false, date_from: this.date_from.year()+'-'+(this.date_from.month()+1)+'-'+this.date_from.date(), date_to: this.date_to.year()+'-'+(this.date_to.month()+1)+'-'+this.date_to.date(), }, - }).done(function(result) { + }); + prom.then(function (result) { self.data = result; self.dashboards_data = result.dashboards; self.currency_id = result.currency_id; self.groups = result.groups; self.websites = result.websites; }); + return prom; }, on_link_analytics_settings: function(ev) { @@ -242,7 +244,7 @@ var Dashboard = AbstractAction.extend({ } var self = this; - $.when(this.fetch_data()).then(function() { + Promise.resolve(this.fetch_data()).then(function () { self.$('.o_website_dashboard').empty(); self.render_dashboards(); self.render_graphs(); @@ -253,7 +255,7 @@ var Dashboard = AbstractAction.extend({ on_website_button: function(website_id) { var self = this; this.website_id = website_id; - $.when(this.fetch_data()).then(function() { + Promise.resolve(this.fetch_data()).then(function () { self.$('.o_website_dashboard').empty(); self.render_dashboards(); self.render_graphs(); diff --git a/addons/website/static/src/js/content/lazy_template_call.js b/addons/website/static/src/js/content/lazy_template_call.js index 80f045cbb0f..f38aab40693 100644 --- a/addons/website/static/src/js/content/lazy_template_call.js +++ b/addons/website/static/src/js/content/lazy_template_call.js @@ -37,7 +37,7 @@ publicWidget.registry.LazyTemplateRenderer = publicWidget.Widget.extend({ }); }); - return $.when(def, renderDef); + return Promise.all([def, renderDef]); }, }); }); diff --git a/addons/website/static/src/js/content/menu.js b/addons/website/static/src/js/content/menu.js index e24ef22a530..913740098b6 100644 --- a/addons/website/static/src/js/content/menu.js +++ b/addons/website/static/src/js/content/menu.js @@ -126,7 +126,7 @@ publicWidget.registry.autohideMenu = publicWidget.Widget.extend({ $window.trigger('resize'); }); } - return $.when.apply($, defs).then(function () { + return Promise.all(defs).then(function () { if (!self.noAutohide) { dom.initAutoMoreMenu(self.$el, {unfoldable: '.divider, .divider ~ li'}); } diff --git a/addons/website/static/src/js/content/website_root.js b/addons/website/static/src/js/content/website_root.js index e1a7be21487..9f16c94b38b 100644 --- a/addons/website/static/src/js/content/website_root.js +++ b/addons/website/static/src/js/content/website_root.js @@ -127,12 +127,12 @@ var WebsiteRoot = publicRootData.PublicRoot.extend({ object: $data.data('object'), }, }) - .done(function (result) { + .then(function (result) { $data.toggleClass("css_unpublished css_published"); $data.find('input').prop("checked", result); $data.parents("[data-publish]").attr("data-publish", +result ? 'on' : 'off'); }) - .fail(function (err, data) { + .guardedCatch(function (err, data) { return new Dialog(self, { title: data.data ? data.data.arguments[0] : "", $content: $('
', { diff --git a/addons/website/static/src/js/editor/editor_menu.js b/addons/website/static/src/js/editor/editor_menu.js index ee504413e2f..46c3fc0b6b1 100644 --- a/addons/website/static/src/js/editor/editor_menu.js +++ b/addons/website/static/src/js/editor/editor_menu.js @@ -75,15 +75,17 @@ var EditorMenu = Widget.extend({ */ cancel: function (reload) { var self = this; - var def = $.Deferred(); - if (!this.wysiwyg.isDirty()) { - def.resolve(); - } else { - var confirm = Dialog.confirm(this, _t("If you discard the current edition, all unsaved changes will be lost. You can cancel to return to the edition mode."), { - confirm_callback: def.resolve.bind(def), - }); - confirm.on('closed', def, def.reject); - } + var def = new Promise(function (resolve, reject) { + if (!self.wysiwyg.isDirty()) { + resolve(); + } else { + var confirm = Dialog.confirm(self, _t("If you discard the current edition, all unsaved changes will be lost. You can cancel to return to the edition mode."), { + confirm_callback: resolve, + }); + confirm.on('closed', self, reject); + } + }); + return def.then(function () { self.trigger_up('edition_will_stopped'); var $wrapwrap = $('#wrapwrap'); @@ -110,10 +112,10 @@ var EditorMenu = Widget.extend({ save: function (reload) { var self = this; this.trigger_up('edition_will_stopped'); - return this.wysiwyg.save().then(function (dirty) { + return this.wysiwyg.save().then(function (result) { var $wrapwrap = $('#wrapwrap'); self.editable($wrapwrap).removeClass('o_editable'); - if (dirty && reload !== false) { + if (result.isDirty && reload !== false) { // remove top padding because the connected bar is not visible $('body').removeClass('o_connected_user'); return self._reload(); @@ -180,7 +182,7 @@ var EditorMenu = Widget.extend({ this.$el.hide(); window.location.hash = 'scrollTop=' + window.document.body.scrollTop; window.location.reload(true); - return $.Deferred(); + return new Promise(function () {}); }, //-------------------------------------------------------------------------- diff --git a/addons/website/static/src/js/editor/snippets.options.js b/addons/website/static/src/js/editor/snippets.options.js index b90f1f91075..be97a42f96c 100644 --- a/addons/website/static/src/js/editor/snippets.options.js +++ b/addons/website/static/src/js/editor/snippets.options.js @@ -57,12 +57,13 @@ options.registry.menu_data = options.Class.extend({ actionName: 'edit_menu', params: [ function () { - var def = $.Deferred(); - self.trigger_up('request_save', { - onSuccess: def.resolve.bind(def), - onFailure: def.reject.bind(def), + var prom = new Promise(function (resolve, reject) { + self.trigger_up('request_save', { + onSuccess: resolve, + onFailure: reject, + }); }); - return def; + return prom; }, ], }); @@ -82,10 +83,10 @@ options.registry.company_data = options.Class.extend({ */ start: function () { var proto = options.registry.company_data.prototype; - var def; + var prom; var self = this; if (proto.__link === undefined) { - def = this._rpc({route: '/web/session/get_session_info'}).then(function (session) { + prom = this._rpc({route: '/web/session/get_session_info'}).then(function (session) { return self._rpc({ model: 'res.users', method: 'read', @@ -95,7 +96,7 @@ options.registry.company_data = options.Class.extend({ proto.__link = '/web#action=base.action_res_company_form&view_type=form&id=' + (res && res[0] && res[0].company_id[0] || 1); }); } - return $.when(this._super.apply(this, arguments), def); + return Promise.all([this._super.apply(this, arguments), prom]); }, /** * When the users selects company data, opens a dialog to ask him if he @@ -737,7 +738,7 @@ options.registry.facebookPage = options.Class.extend({ })); } - return $.when.apply($, defs); + return Promise.all(defs); }, /** * @override diff --git a/addons/website/static/src/js/editor/wysiwyg_multizone.js b/addons/website/static/src/js/editor/wysiwyg_multizone.js index 660afe80bdf..4d29e1f3567 100644 --- a/addons/website/static/src/js/editor/wysiwyg_multizone.js +++ b/addons/website/static/src/js/editor/wysiwyg_multizone.js @@ -238,20 +238,20 @@ var WysiwygMultizone = Wysiwyg.extend({ this.savingMutex.exec(this._saveCroppedImages.bind(this)); } var _super = this._super.bind(this); - return this.savingMutex.def.then(function () { + return this.savingMutex.lock.then(function () { return _super().then(function (_isDirty, html) { this._summernote.layoutInfo.editable.html(html); var $editable = this._getEditableArea(); var $areaDirty = $editable.filter('.o_dirty'); if (!$areaDirty.length) { - return false; + return { isDirty: false }; } $areaDirty.each(function (index, editable) { this.savingMutex.exec(this._saveEditable.bind(this, editable)); }.bind(this)); - return this.savingMutex.def.then(function () { - return true; + return this.savingMutex.lock.then(function () { + return { isDirty: true }; }); }.bind(this)); }.bind(this)); @@ -402,9 +402,9 @@ var WysiwygMultizone = Wysiwyg.extend({ var recordInfo = this._getRecordInfo({target: editable}); var outerHTML = this._getCleanedHtml(editable).prop('outerHTML'); var def = this._saveElement(outerHTML, recordInfo, editable); - def.done(function () { + def.then(function () { self.trigger_up('saved', recordInfo); - }).fail(function () { + }).guardedCatch(function () { self.trigger_up('canceled', recordInfo); }); return def; @@ -456,7 +456,7 @@ var WysiwygMultizone = Wysiwyg.extend({ }); } }).get(); - return $.when.apply($, defs); + return Promise.all(defs); }, /** * Saves one (dirty) element of the page. diff --git a/addons/website/static/src/js/editor/wysiwyg_multizone_translate.js b/addons/website/static/src/js/editor/wysiwyg_multizone_translate.js index 5f68ff09e0f..85eecb1a85a 100644 --- a/addons/website/static/src/js/editor/wysiwyg_multizone_translate.js +++ b/addons/website/static/src/js/editor/wysiwyg_multizone_translate.js @@ -171,7 +171,7 @@ var WysiwygTranslate = WysiwygMultizone.extend({ kwargs: { context: recordInfo.context, }, - }).fail(function (error) { + }).guardedCatch(function (error) { console.error(error.data.message); webDialog.alert(null, error.data.message); }); diff --git a/addons/website/static/src/js/menu/content.js b/addons/website/static/src/js/menu/content.js index e18de94e084..d9f652cda3a 100644 --- a/addons/website/static/src/js/menu/content.js +++ b/addons/website/static/src/js/menu/content.js @@ -92,7 +92,7 @@ var PagePropertiesDialog = weWidgets.Dialog.extend({ self.fields = fields; })); - return $.when.apply($, defs); + return Promise.all(defs); }, /** * @override @@ -175,7 +175,7 @@ var PagePropertiesDialog = weWidgets.Dialog.extend({ } this.$('#date_publish_container').datetimepicker(datepickersOptions); - return $.when.apply($, defs); + return Promise.all(defs); }, /** * @override @@ -255,7 +255,7 @@ var PagePropertiesDialog = weWidgets.Dialog.extend({ * * @private * @param {integer} moID - * @returns {Deferred} + * @returns {Promise} */ _getPageDependencies: function (moID) { return this._rpc({ @@ -269,7 +269,7 @@ var PagePropertiesDialog = weWidgets.Dialog.extend({ * * @private * @param {integer} moID - * @returns {Deferred} + * @returns {Promise} */ _getPageKeyDependencies: function (moID) { return this._rpc({ @@ -282,7 +282,7 @@ var PagePropertiesDialog = weWidgets.Dialog.extend({ * Retrieves supported mimtype * * @private - * @returns {Deferred} + * @returns {Promise} */ _getSupportedMimetype: function () { return this._rpc({ @@ -488,7 +488,7 @@ var EditMenuDialog = weWidgets.Dialog.extend({ self.flat = self._flatenize(menu); self.to_delete = []; })); - return $.when.apply($, defs); + return Promise.all(defs); }, /** * @override @@ -735,63 +735,73 @@ var ContentMenu = websiteNavbarData.WebsiteNavbarActionWidget.extend({ * * @private * @param {function} [beforeReloadCallback] - * @returns {Deferred} + * @returns {Promise} * Unresolved if the menu is edited and saved as the page will be * reloaded. * Resolved otherwise. */ _editMenu: function (beforeReloadCallback) { var self = this; - var def = $.Deferred(); - - // If there is multiple menu on the page, ask the user which one he - // wants to edit - var selectDef = $.Deferred(); - if ($('[data-content_menu_id]').length) { - var select = new SelectEditMenuDialog(this); - select.on('save', selectDef, selectDef.resolve); - select.on('cancel', def, def.resolve); - select.open(); - } else { - selectDef.resolve(null); - } - selectDef.then(function (rootID) { - // Open the dialog to show the menu structure and allow its edition - var editDef = $.Deferred(); - var dialog = new EditMenuDialog(self, {}, rootID).open(); - dialog.on('save', editDef, editDef.resolve); - dialog.on('cancel', def, def.resolve); - return editDef; - }).then(function () { - // Before reloading the page after menu modification, does the - // given action to do. - return beforeReloadCallback && beforeReloadCallback(); - }).then(function () { - // Reload the page so that the menu modification are shown - window.location.reload(true); + return new Promise(function (resolve) { + function resolveWhenEditMenuDialogIsCancelled(rootID) { + return self._openEditMenuDialog(rootID, beforeReloadCallback).then(resolve); + } + if ($('[data-content_menu_id]').length) { + var select = new SelectEditMenuDialog(self); + select.on('save', self, resolveWhenEditMenuDialogIsCancelled); + select.on('cancel', self, resolve); + select.open(); + } else { + resolveWhenEditMenuDialogIsCancelled(null); + } }); - - return def; }, + /** + * + * @param {*} rootID + * @param {function|undefied} beforeReloadCallback function that returns a promise + * @returns {Promise} + */ + _openEditMenuDialog: function (rootID, beforeReloadCallback) { + var self = this; + return new Promise(function (resolve) { + var dialog = new EditMenuDialog(self, {}, rootID); + dialog.on('save', self, function () { + // Before reloading the page after menu modification, does the + // given action to do. + if (beforeReloadCallback) { + // Reload the page so that the menu modification are shown + beforeReloadCallback().then(function () { + window.location.reload(true); + }); + } else { + window.location.reload(true); + } + }); + dialog.on('cancel', self, resolve); + dialog.open(); + }); + }, + /** * Retrieves the value of a page option. * * @private * @param {string} name - * @returns {Deferred<*>} + * @returns {Promise<*>} */ _getPageOption: function (name) { var option = this.pageOptions[name]; if (!option) { - return $.Deferred().reject(); + return Promise.reject(); } - return $.when(option.value); + return Promise.resolve(option.value); }, /** * On save, simulated page options have to be server-saved. * * @private - * @returns {Deferred} + * @returns {Promise} */ _onSave: function () { var self = this; @@ -803,13 +813,13 @@ var ContentMenu = websiteNavbarData.WebsiteNavbarActionWidget.extend({ }, true, true); } }); - return $.when.apply($, defs); + return Promise.all(defs); }, /** * Opens the page properties dialog. * * @private - * @returns {Deferred} + * @returns {Promise} */ _pageProperties: function () { var mo; @@ -830,7 +840,7 @@ var ContentMenu = websiteNavbarData.WebsiteNavbarActionWidget.extend({ * @param {*} [params.value] (change value by default true -> false -> true) * @param {boolean} [forceSave=false] * @param {boolean} [noReload=false] - * @returns {Deferred} + * @returns {Promise} */ _togglePageOption: function (params, forceSave, noReload) { // First check it is a website page @@ -841,13 +851,13 @@ var ContentMenu = websiteNavbarData.WebsiteNavbarActionWidget.extend({ }, }); if (mo.model !== 'website.page') { - return $.Deferred().reject(); + return Promise.reject(); } // Check if this is a valid option var option = this.pageOptions[params.name]; if (!option) { - return $.Deferred().reject(); + return Promise.reject(); } // Toggle the value @@ -856,23 +866,23 @@ var ContentMenu = websiteNavbarData.WebsiteNavbarActionWidget.extend({ // If simulate is true, it means we want the option to be toggled but // not saved on the server yet if (!forceSave) { - return $.when(); + return Promise.resolve(); } // If not, write on the server page and reload the current location var vals = {}; vals[params.name] = option.value; - var def = this._rpc({ + var prom = this._rpc({ model: 'website.page', method: 'write', args: [[mo.id], vals], }); if (noReload) { - return def; + return prom; } - return def.then(function () { + return prom.then(function () { window.location.reload(); - return $.Deferred(); + return new Promise(function () {}); }); }, }); @@ -894,7 +904,7 @@ var PageManagement = Widget.extend({ * * @private * @param {integer} moID - * @returns {Deferred} + * @returns {Promise} */ _getPageDependencies: function (moID) { return this._rpc({ @@ -941,35 +951,35 @@ var PageManagement = Widget.extend({ // TODO: This function should be integrated in a widget in the future function _deletePage(pageId, fromPageManagement) { var self = this; - var def = $.Deferred(); - - // Search the page dependencies - this._getPageDependencies(pageId) - .then(function (dependencies) { - // Inform the user about those dependencies and ask him confirmation - var confirmDef = $.Deferred(); - Dialog.safeConfirm(self, "", { - title: _t("Delete Page"), - $content: $(qweb.render('website.delete_page', {dependencies: dependencies})), - confirm_callback: confirmDef.resolve.bind(confirmDef), - cancel_callback: def.resolve.bind(self), - }); - return confirmDef; - }).then(function () { - // Delete the page if the user confirmed - return self._rpc({ - model: 'website.page', - method: 'unlink', - args: [pageId], - }); - }).then(function () { - if (fromPageManagement) { - window.location.reload(true); - } - else { - window.location.href = '/'; - } - }, def.reject.bind(def)); + var prom = new Promise(function (resolve, reject) { + // Search the page dependencies + self._getPageDependencies(pageId) + .then(function (dependencies) { + // Inform the user about those dependencies and ask him confirmation + return new Promise(function (confirmResolve, confirmReject) { + Dialog.safeConfirm(self, "", { + title: _t("Delete Page"), + $content: $(qweb.render('website.delete_page', {dependencies: dependencies})), + confirm_callback: confirmResolve, + cancel_callback: resolve, + }); + }); + }).then(function () { + // Delete the page if the user confirmed + return self._rpc({ + model: 'website.page', + method: 'unlink', + args: [pageId], + }); + }).then(function () { + if (fromPageManagement) { + window.location.reload(true); + } + else { + window.location.href = '/'; + } + }, reject); + }); } websiteNavbarData.websiteNavbarRegistry.add(ContentMenu, '#content-menu'); diff --git a/addons/website/static/src/js/menu/customize.js b/addons/website/static/src/js/menu/customize.js index aced336de2c..59c4e865242 100644 --- a/addons/website/static/src/js/menu/customize.js +++ b/addons/website/static/src/js/menu/customize.js @@ -45,7 +45,7 @@ var CustomizeMenu = Widget.extend({ * * @private * @param {integer} viewID - * @returns {Deferred} + * @returns {Promise} * Unresolved if the customization succeeded as the page will be * reloaded. * Rejected otherwise. @@ -57,7 +57,7 @@ var CustomizeMenu = Widget.extend({ args: [[viewID]], }).then(function () { window.location.reload(); - return $.Deferred(); + return new Promise(function () {}); }); }, /** @@ -65,11 +65,11 @@ var CustomizeMenu = Widget.extend({ * the current page and shows them as switchable elements in the menu. * * @private - * @return {Deferred} + * @return {Promise} */ _loadCustomizeOptions: function () { if (this.__customizeOptionsLoaded) { - return $.when(); + return Promise.resolve(); } this.__customizeOptionsLoaded = true; @@ -169,18 +169,20 @@ var AceEditorMenu = websiteNavbarData.WebsiteNavbarActionWidget.extend({ * which are used by the current page. * * @private - * @returns {Deferred} + * @returns {Promise} */ _launchAce: function () { - var def = $.Deferred(); - this.trigger_up('action_demand', { - actionName: 'close_all_widgets', - onSuccess: def.resolve.bind(def), + var self = this; + var prom = new Promise(function (resolve, reject) { + self.trigger_up('action_demand', { + actionName: 'close_all_widgets', + onSuccess: resolve, + }); }); - return def.then((function () { - if (this.globalEditor) { - this.globalEditor.do_show(); - return $.when(); + prom.then(function () { + if (self.globalEditor) { + self.globalEditor.do_show(); + return Promise.resolve(); } else { var currentHash = window.location.hash; var indexOfView = currentHash.indexOf("?res="); @@ -193,16 +195,18 @@ var AceEditorMenu = websiteNavbarData.WebsiteNavbarActionWidget.extend({ } } - this.globalEditor = new WebsiteAceEditor(this, $(document.documentElement).data('view-xmlid'), { + self.globalEditor = new WebsiteAceEditor(self, $(document.documentElement).data('view-xmlid'), { initialResID: initialResID, defaultBundlesRestriction: [ "web.assets_frontend", "website.assets_frontend", ], }); - return this.globalEditor.appendTo(document.body); + return self.globalEditor.appendTo(document.body); } - }).bind(this)); + }); + + return prom; }, }); diff --git a/addons/website/static/src/js/menu/edit.js b/addons/website/static/src/js/menu/edit.js index a9712be72bb..a08ca136131 100644 --- a/addons/website/static/src/js/menu/edit.js +++ b/addons/website/static/src/js/menu/edit.js @@ -53,7 +53,7 @@ var EditPageMenu = websiteNavbarData.WebsiteNavbarActionWidget.extend({ // If we auto start the editor, do not show a welcome message if (this._editorAutoStart) { - return $.when(def, this._startEditMode()); + return Promise.all([def, this._startEditMode()]); } // Check that the page is empty @@ -85,7 +85,7 @@ var EditPageMenu = websiteNavbarData.WebsiteNavbarActionWidget.extend({ * welcome message if necessary. * * @private - * @returns {Deferred} + * @returns {Promise} */ _startEditMode: function () { var self = this; @@ -111,13 +111,13 @@ var EditPageMenu = websiteNavbarData.WebsiteNavbarActionWidget.extend({ .find('.oe_structure.oe_empty, [data-oe-type="html"]') .not('[data-editor-message]') .attr('data-editor-message', _t('DRAG BUILDING BLOCKS HERE')); - var def = $.Deferred(); - self.trigger_up('widgets_start_request', { - editableMode: true, - onSuccess: def.resolve.bind(def), - onFailure: def.reject.bind(def), + new Promise(function (resolve, reject) { + self.trigger_up('widgets_start_request', { + editableMode: true, + onSuccess: resolve, + onFailure: reject, + }); }); - return def; }); }, /** diff --git a/addons/website/static/src/js/menu/navbar.js b/addons/website/static/src/js/menu/navbar.js index b132b0e2d51..1809f75a3d7 100644 --- a/addons/website/static/src/js/menu/navbar.js +++ b/addons/website/static/src/js/menu/navbar.js @@ -26,7 +26,11 @@ var WebsiteNavbar = publicWidget.RootWidget.extend({ */ init: function () { this._super.apply(this, arguments); - this._widgetDefs = [$.Deferred()]; + var self = this; + var initPromise = new Promise(function (resolve) { + self.resolveInit = resolve; + }); + this._widgetDefs = [initPromise]; }, /** * @override @@ -34,7 +38,7 @@ var WebsiteNavbar = publicWidget.RootWidget.extend({ start: function () { var self = this; return this._super.apply(this, arguments).then(function () { - self._widgetDefs[0].resolve(); + self.resolveInit(); }); }, @@ -67,7 +71,7 @@ var WebsiteNavbar = publicWidget.RootWidget.extend({ * @private * @param {string} actionName * @param {Array} params - * @returns {Deferred} + * @returns {Promise} */ _handleAction: function (actionName, params, _i) { var self = this; @@ -88,20 +92,20 @@ var WebsiteNavbar = publicWidget.RootWidget.extend({ // instantiated yet (rare) -> retry some times to eventually abort if (_i > 50) { console.warn(_.str.sprintf("Action '%s' was not able to be handled.", actionName)); - return $.Deferred().reject(); + return Promise.reject(); } return concurrency.delay(100).then(function () { return self._handleAction(actionName, params, (_i || 0) + 1); }); } - return $.when.apply($, defs); + return Promise.all(defs); }); }, /** * @private */ _whenReadyForActions: function () { - return $.when.apply($, this._widgetDefs); + return Promise.all(this._widgetDefs); }, //-------------------------------------------------------------------------- @@ -118,9 +122,10 @@ var WebsiteNavbar = publicWidget.RootWidget.extend({ _onActionMenuClick: function (ev) { var $button = $(ev.currentTarget); $button.prop('disabled', true); - this._handleAction($button.data('action')).always(function () { + var always = function () { $button.prop('disabled', false); - }); + }; + this._handleAction($button.data('action')).then(always).guardedCatch(always); }, /** * Called when an action is asked to be executed from a child widget -> @@ -130,10 +135,10 @@ var WebsiteNavbar = publicWidget.RootWidget.extend({ _onActionDemand: function (ev) { var def = this._handleAction(ev.data.actionName, ev.data.params); if (ev.data.onSuccess) { - def.done(ev.data.onSuccess); + def.then(ev.data.onSuccess); } if (ev.data.onFailure) { - def.fail(ev.data.onFailure); + def.guardedCatch(ev.data.onFailure); } }, /** @@ -210,12 +215,12 @@ var WebsiteNavbarActionWidget = Widget.extend({ * * @param {string} actionName * @param {Array} params - * @returns {Deferred|null} action's deferred or null if no action was found + * @returns {Promise|null} action's promise or null if no action was found */ handleAction: function (actionName, params) { var action = this[this.actions[actionName]]; if (action) { - return $.when(action.apply(this, params || [])); + return Promise.resolve(action.apply(this, params || [])); } return null; }, diff --git a/addons/website/static/src/js/menu/new_content.js b/addons/website/static/src/js/menu/new_content.js index d414bc8a800..46a2ce7d7e2 100644 --- a/addons/website/static/src/js/menu/new_content.js +++ b/addons/website/static/src/js/menu/new_content.js @@ -70,7 +70,7 @@ var NewContentMenu = websiteNavbarData.WebsiteNavbarActionWidget.extend({ * redirects the user to this new page. * * @private - * @returns {Deferred} Unresolved if there is a redirection + * @returns {Promise} Unresolved if there is a redirection */ _createNewPage: function () { return wUtils.prompt({ @@ -87,14 +87,16 @@ var NewContentMenu = websiteNavbarData.WebsiteNavbarActionWidget.extend({ $add.find('input').prop('checked', true); $group.after($add); } - }).then(function (val, field, $dialog) { + }).then(function (result) { + var val = result.val; + var $dialog = result.dialog; if (!val) { return; } var url = '/website/add/' + encodeURIComponent(val); if ($dialog.find('input[type="checkbox"]').is(':checked')) url +='?add_menu=1'; document.location = url; - return $.Deferred(); + return new Promise(function () {}); }); }, /** @@ -138,7 +140,7 @@ var NewContentMenu = websiteNavbarData.WebsiteNavbarActionWidget.extend({ * * @private * @param {number} moduleId: the module to install - * @return {Deferred} + * @return {Promise} */ _install: function (moduleId) { this.pendingInstall = true; @@ -147,7 +149,7 @@ var NewContentMenu = websiteNavbarData.WebsiteNavbarActionWidget.extend({ model: 'ir.module.module', method: 'button_immediate_install', args: [[moduleId]], - }).fail(function () { + }).guardedCatch(function () { $('body').css('pointer-events', ''); }); }, @@ -155,20 +157,21 @@ var NewContentMenu = websiteNavbarData.WebsiteNavbarActionWidget.extend({ * Show the menu * * @private - * @returns Deferred + * @returns {Promise} */ _showMenu: function () { - var def = $.Deferred(); - this.trigger_up('action_demand', { - actionName: 'close_all_widgets', - onSuccess: def.resolve.bind(def), - }); - return def.then((function () { - this.firstTab = true; - this.$newContentMenuChoices.removeClass('o_hidden'); + var self = this; + return new Promise(function (resolve, reject) { + self.trigger_up('action_demand', { + actionName: 'close_all_widgets', + onSuccess: resolve, + }); + }).then(function () { + self.firstTab = true; + self.$newContentMenuChoices.removeClass('o_hidden'); $('body').addClass('o_new_content_open'); - this.$('> a').focus(); - }).bind(this)); + self.$('> a').focus(); + }); }, //-------------------------------------------------------------------------- diff --git a/addons/website/static/src/js/menu/seo.js b/addons/website/static/src/js/menu/seo.js index 425024539ec..792934a8375 100644 --- a/addons/website/static/src/js/menu/seo.js +++ b/addons/website/static/src/js/menu/seo.js @@ -105,6 +105,7 @@ var Keyword = Widget.extend({ this._super(parent); }, start: function () { + var self = this; this.$('.js_seo_keyword_suggestion').empty(); this.suggestionList = new SuggestionList(this, { root: this.keyword, @@ -114,12 +115,12 @@ var Keyword = Widget.extend({ this.suggestionList.on('selected', this, function (word, language) { this.trigger('selected', word, language); }); - this.suggestionList.appendTo(this.$('.js_seo_keyword_suggestion')); - - this.htmlPage.on('title-changed', this, this._updateTitle); - this.htmlPage.on('description-changed', this, this._updateDescription); - this._updateTitle(); - this._updateDescription(); + return this.suggestionList.appendTo(this.$('.js_seo_keyword_suggestion')).then(function() { + self.htmlPage.on('title-changed', self, self._updateTitle); + self.htmlPage.on('description-changed', self, self._updateDescription); + self._updateTitle(); + self._updateDescription(); + }); }, destroy: function () { this.trigger('removed'); @@ -461,10 +462,10 @@ var MetaKeywords = Widget.extend({ this.keywordList.on('content-updated', this, function (removed) { self._updateTable(removed); }); - this.keywordList.insertAfter(this.$('.table thead')); - - this._getLanguages(); - this._updateTable(); + return this.keywordList.insertAfter(this.$('.table thead')).then(function() { + self._getLanguages(); + self._updateTable(); + }); }, _addKeyword: function () { var $language = this.$('select[name=seo_page_language]'); @@ -740,39 +741,37 @@ var SeoConfigurator = Dialog.extend({ }, loadMetaData: function () { var obj = this.getMainObject(); - var def = $.Deferred(); - if (!obj) { - // return $.Deferred().reject(new Error("No main_object was found.")); - def.resolve(null); - } else { - var fields = ['website_meta_title', 'website_meta_description', 'website_meta_keywords' - ,'website_meta_og_img']; - if (obj.model === 'website.page'){ - fields.push('website_indexed'); - fields.push('website_id'); - } - rpc.query({ - model: obj.model, - method: 'read', - args: [[obj.id], fields], - }).then(function (data) { - if (data.length) { - var meta = data[0]; - meta.model = obj.model; - def.resolve(meta); - } else { - def.resolve(null); + return new Promise(function (resolve, reject) { + if (!obj) { + // return Promise.reject(new Error("No main_object was found.")); + resolve(null); + } else { + var fields = ['website_meta_title', 'website_meta_description', 'website_meta_keywords' + ,'website_meta_og_img']; + if (obj.model === 'website.page'){ + fields.push('website_indexed'); + fields.push('website_id'); } - }).fail(function () { - def.reject(); - }); - } - return def; + rpc.query({ + model: obj.model, + method: 'read', + args: [[obj.id], fields], + }).then(function (data) { + if (data.length) { + var meta = data[0]; + meta.model = obj.model; + resolve(meta); + } else { + resolve(null); + } + }).guardedCatch(reject); + } + }); }, saveMetaData: function (data) { var obj = this.getMainObject(); if (!obj) { - return $.Deferred().reject(); + return Promise.reject(); } else { return this._rpc({ model: obj.model, diff --git a/addons/website/static/src/js/menu/translate.js b/addons/website/static/src/js/menu/translate.js index 559f9ef3a25..043a900fff6 100644 --- a/addons/website/static/src/js/menu/translate.js +++ b/addons/website/static/src/js/menu/translate.js @@ -43,7 +43,7 @@ var TranslatePageMenu = websiteNavbarData.WebsiteNavbarActionWidget.extend({ * edit mode. * * @private - * @returns {Deferred} + * @returns {Promise} */ _goToMasterPage: function () { var lang = '/' + utils.get_cookie('frontend_lang'); @@ -60,19 +60,19 @@ var TranslatePageMenu = websiteNavbarData.WebsiteNavbarActionWidget.extend({ link.search += (link.search ? '&' : '?') + 'r=' + encodeURIComponent(current.pathname + current.search + current.hash); window.location = link.href; - return $.Deferred(); + return new Promise(function () {}); }, /** * Redirects the user to the same page in translation mode (or start the * translator is translation mode is already enabled). * * @private - * @returns {Deferred} + * @returns {Promise} */ _startTranslateMode: function () { if (!this._mustEditTranslations) { window.location.search += '&edit_translations'; - return $.Deferred(); + return new Promise(function () {}); } var translator = new TranslatorMenu(this); diff --git a/addons/website/static/src/js/tours/rte.js b/addons/website/static/src/js/tours/rte.js index 2fd7aab345c..906f16e2924 100644 --- a/addons/website/static/src/js/tours/rte.js +++ b/addons/website/static/src/js/tours/rte.js @@ -6,9 +6,10 @@ var session = require('web.session'); var tour = require('web_tour.tour'); var Wysiwyg = require('web_editor.wysiwyg.root'); -var domReady = $.Deferred(); -$(domReady.resolve.bind(domReady)); -var ready = $.when(domReady, session.is_bound, ajax.loadXML()); +var domReady = new Promise(function (resolve) { + $(resolve); +}); +var ready = Promise.all([domReady, session.is_bound, ajax.loadXML()]); tour.register('rte_translator', { test: true, diff --git a/addons/website/static/src/js/tours/website_tour_reset_password.js b/addons/website/static/src/js/tours/website_tour_reset_password.js index 307b741ceef..3239dc28f80 100644 --- a/addons/website/static/src/js/tours/website_tour_reset_password.js +++ b/addons/website/static/src/js/tours/website_tour_reset_password.js @@ -57,7 +57,7 @@ tour.register('website_reset_password', { }); }); - return $.when(def1, def2, def3).then(function () { + return Promise.all([def1, def2, def3]).then(function () { window.location.href = usersUrl; }); }, diff --git a/addons/website/static/src/js/utils.js b/addons/website/static/src/js/utils.js index 01f0e7797a4..e93a52897c0 100644 --- a/addons/website/static/src/js/utils.js +++ b/addons/website/static/src/js/utils.js @@ -17,7 +17,7 @@ function loadAnchors(url) { if (url !== window.location.pathname && url[0] !== '#') { def = $.get(window.location.origin + url); } else { - def = $.when(document.body.outerHTML); + def = Promise.resolve(document.body.outerHTML); } return def.then(function (response) { return _.map($(response).find('[id][data-anchor=true]'), function (el) { @@ -69,13 +69,14 @@ function onceAllImagesLoaded($element) { if (img.complete) { return; // Already loaded } - var def = $.Deferred(); - $(img).one('load', function () { - def.resolve(); + var def = new Promise(function (resolve, reject) { + $(img).one('load', function () { + resolve(); + }); }); return def; }); - return $.when.apply($, defs); + return Promise.all(defs); } /** @@ -109,7 +110,7 @@ function prompt(options, _qweb) { * @param {String} [options.textarea] tell the modal to use a textarea field, the given value will be the field title * @param {String} [options.select] tell the modal to use a select box, the given value will be the field title * @param {Object} [options.default=''] default value of the field - * @param {Function} [options.init] optional function that takes the `field` (enhanced with a fillWith() method) and the `dialog` as parameters [can return a deferred] + * @param {Function} [options.init] optional function that takes the `field` (enhanced with a fillWith() method) and the `dialog` as parameters [can return a promise] */ if (typeof options === 'string') { options = { @@ -133,51 +134,51 @@ function prompt(options, _qweb) { options.field_type = type; options.field_name = options.field_name || options[type]; - var def = $.Deferred(); - - $.when(xmlDef).then(function () { - var dialog = $(qweb.render(_qweb, options)).appendTo('body'); - options.$dialog = dialog; - var field = dialog.find(options.field_type).first(); - field.val(options['default']); // dict notation for IE<9 - field.fillWith = function (data) { - if (field.is('select')) { - var select = field[0]; - data.forEach(function (item) { - select.options[select.options.length] = new window.Option(item[1], item[0]); - }); - } else { - field.val(data); - } - }; - var init = options.init(field, dialog); - $.when(init).then(function (fill) { - if (fill) { - field.fillWith(fill); - } - dialog.modal('show'); - field.focus(); - dialog.on('click', '.btn-primary', function () { + var def = new Promise(function (resolve, reject) { + Promise.resolve(xmlDef).then(function () { + var dialog = $(qweb.render(_qweb, options)).appendTo('body'); + options.$dialog = dialog; + var field = dialog.find(options.field_type).first(); + field.val(options['default']); // dict notation for IE<9 + field.fillWith = function (data) { + if (field.is('select')) { + var select = field[0]; + data.forEach(function (item) { + select.options[select.options.length] = new window.Option(item[1], item[0]); + }); + } else { + field.val(data); + } + }; + var init = options.init(field, dialog); + Promise.resolve(init).then(function (fill) { + if (fill) { + field.fillWith(fill); + } + dialog.modal('show'); + field.focus(); + dialog.on('click', '.btn-primary', function () { var backdrop = $('.modal-backdrop'); - def.resolve(field.val(), field, dialog); - dialog.modal('hide').remove(); + resolve({ val: field.val(), field: field, dialog: dialog }); + dialog.modal('hide').remove(); + backdrop.remove(); + }); + }); + dialog.on('hidden.bs.modal', function () { + var backdrop = $('.modal-backdrop'); + reject(); + dialog.remove(); backdrop.remove(); }); + if (field.is('input[type="text"], select')) { + field.keypress(function (e) { + if (e.which === 13) { + e.preventDefault(); + dialog.find('.btn-primary').trigger('click'); + } + }); + } }); - dialog.on('hidden.bs.modal', function () { - var backdrop = $('.modal-backdrop'); - def.reject(); - dialog.remove(); - backdrop.remove(); - }); - if (field.is('input[type="text"], select')) { - field.keypress(function (e) { - if (e.which === 13) { - e.preventDefault(); - dialog.find('.btn-primary').trigger('click'); - } - }); - } }); return def; diff --git a/addons/website/static/src/js/widgets/ace.js b/addons/website/static/src/js/widgets/ace.js index d9440be7b64..f14f38cd911 100644 --- a/addons/website/static/src/js/widgets/ace.js +++ b/addons/website/static/src/js/widgets/ace.js @@ -63,9 +63,9 @@ var WebsiteAceEditor = AceEditor.extend({ } }).bind(this))); } - return $.when.apply($, defs).then((function () { + return Promise.all(defs).then((function () { window.location.reload(); - return $.Deferred(); + return new Promise(function() { }); })); }).bind(this)); }, @@ -75,7 +75,7 @@ var WebsiteAceEditor = AceEditor.extend({ _resetResource: function () { return this._super.apply(this, arguments).then((function () { window.location.reload(); - return $.Deferred(); + return new Promise(function () {}); }).bind(this)); }, /** diff --git a/addons/website/static/src/js/widgets/theme.js b/addons/website/static/src/js/widgets/theme.js index f35769a3748..0b41f844b7e 100644 --- a/addons/website/static/src/js/widgets/theme.js +++ b/addons/website/static/src/js/widgets/theme.js @@ -143,7 +143,7 @@ var ThemeCustomizeDialog = Dialog.extend({ return core.qweb.add_template(data); }); } - return $.when(this._super.apply(this, arguments), templateDef); + return Promise.all([this._super.apply(this, arguments), templateDef]); }, /** * @override @@ -204,7 +204,7 @@ var ThemeCustomizeDialog = Dialog.extend({ } }); - return $.when(this._super.apply(this, arguments), loadDef); + return Promise.all([this._super.apply(this, arguments), loadDef]); }, //-------------------------------------------------------------------------- @@ -216,36 +216,37 @@ var ThemeCustomizeDialog = Dialog.extend({ */ _chooseBodyCustomImage: function () { var self = this; - var def = $.Deferred(); - var $image = $(''); - var editor = new weWidgets.MediaDialog(this, { - onlyImages: true, - firstFilters: ['background'], - }, $image[0]); + var def = new Promise(function (resolve, reject) { + var $image = $(''); + var editor = new weWidgets.MediaDialog(this, { + onlyImages: true, + firstFilters: ['background'], + }, $image[0]); - editor.on('save', this, function (media) { // TODO use scss customization instead (like for user colors) - var src = $(media).attr('src'); - self._rpc({ - model: 'ir.model.data', - method: 'get_object_reference', - args: ['website', this.CUSTOM_BODY_IMAGE_XML_ID], - }).then(function (data) { - return self._rpc({ - model: 'ir.ui.view', - method: 'save', - args: [ - data[1], - '#wrapwrap { background-image: url("' + src + '"); }', - '//style', - ], - }); - }).always(def.resolve.bind(def)); - }); - editor.on('cancel', this, function () { - def.resolve(); - }); + editor.on('save', this, function (media) { // TODO use scss customization instead (like for user colors) + var src = $(media).attr('src'); + self._rpc({ + model: 'ir.model.data', + method: 'get_object_reference', + args: ['website', this.CUSTOM_BODY_IMAGE_XML_ID], + }).then(function (data) { + return self._rpc({ + model: 'ir.ui.view', + method: 'save', + args: [ + data[1], + '#wrapwrap { background-image: url("' + src + '"); }', + '//style', + ], + }); + }).then(resolve).guardedCatch(resolve); + }); + editor.on('cancel', this, function () { + resolve(); + }); - editor.open(); + editor.open(); + }); return def; }, @@ -433,39 +434,37 @@ var ThemeCustomizeDialog = Dialog.extend({ var colorName = $color.data('color'); var colorType = $color.data('colorType'); - var def = $.Deferred(); + return new Promise(function (resolve, reject) { + var colorpicker = new ColorpickerDialog(this, { + defaultColor: $color.css('background-color'), + }); + var chosenColor = undefined; + colorpicker.on('colorpicker:saved', this, function (ev) { + ev.stopPropagation(); + chosenColor = ev.data.cssColor; + }); + colorpicker.on('closed', this, function (ev) { + if (chosenColor === undefined) { + resolve(); + return; + } - var colorpicker = new ColorpickerDialog(this, { - defaultColor: $color.css('background-color'), + var baseURL = '/website/static/src/scss/options/colors/'; + var url = _.str.sprintf('%suser_%scolor_palette.scss', baseURL, (colorType ? (colorType + '_') : '')); + + var colors = {}; + colors[colorName] = chosenColor; + if (colorName === 'alpha') { + colors['beta'] = 'null'; + colors['gamma'] = 'null'; + colors['delta'] = 'null'; + colors['epsilon'] = 'null'; + } + + self._makeSCSSCusto(url, colors).always(resolve); + }); + colorpicker.open(); }); - var chosenColor = undefined; - colorpicker.on('colorpicker:saved', this, function (ev) { - ev.stopPropagation(); - chosenColor = ev.data.cssColor; - }); - colorpicker.on('closed', this, function (ev) { - if (chosenColor === undefined) { - def.resolve(); - return; - } - - var baseURL = '/website/static/src/scss/options/colors/'; - var url = _.str.sprintf('%suser_%scolor_palette.scss', baseURL, (colorType ? (colorType + '_') : '')); - - var colors = {}; - colors[colorName] = chosenColor; - if (colorName === 'alpha') { - colors['beta'] = 'null'; - colors['gamma'] = 'null'; - colors['delta'] = 'null'; - colors['epsilon'] = 'null'; - } - - self._makeSCSSCusto(url, colors).always(def.resolve.bind(def)); - }); - colorpicker.open(); - - return def; }, /** * @private @@ -494,7 +493,7 @@ var ThemeCustomizeDialog = Dialog.extend({ return self._quickEdit($(inputData)); })); - return $.when.apply($, defs); + return Promise.all(defs); }, /** * @private @@ -504,23 +503,25 @@ var ThemeCustomizeDialog = Dialog.extend({ var value = parseFloat(text) || ''; var unit = text.match(/([^\s\d]+)$/)[1]; - var def = $.Deferred(); - var qEdit = new QuickEdit(this, value, unit); - qEdit.on('QuickEdit:save', this, function (ev) { - ev.stopPropagation(); + var def = new Promise(function (resolve, reject) { + var qEdit = new QuickEdit(this, value, unit); + qEdit.on('QuickEdit:save', this, function (ev) { + ev.stopPropagation(); - var value = ev.data.value; - // Convert back to rem if needed - if ($inputData.data('unit') === 'rem' && unit === 'px' && value !== 'null') { - value = parseFloat(value) / this.PX_BY_REM + 'rem'; - } + var value = ev.data.value; + // Convert back to rem if needed + if ($inputData.data('unit') === 'rem' && unit === 'px' && value !== 'null') { + value = parseFloat(value) / this.PX_BY_REM + 'rem'; + } - var values = {}; - values[$inputData.data('value')] = value; - this._makeSCSSCusto('/website/static/src/scss/options/user_values.scss', values) - .always(def.resolve.bind(def)); + var values = {}; + values[$inputData.data('value')] = value; + this._makeSCSSCusto('/website/static/src/scss/options/user_values.scss', values) + .always(resolve); + }); + qEdit.appendTo($inputData.closest('.o_theme_customize_option')); }); - qEdit.appendTo($inputData.closest('.o_theme_customize_option')); + return def; }, /** @@ -581,7 +582,7 @@ var ThemeCustomizeDialog = Dialog.extend({ disable: (disable || []).join(','), tab: this.$('.nav-link.active').parent().index(), }); - return $.Deferred(); + return Promise.resolve(); } return this._rpc({ @@ -599,22 +600,26 @@ var ThemeCustomizeDialog = Dialog.extend({ $allLinks = $allLinks.add($links); var $newLinks = $(bundleContent).filter(linkSelector); - var linksLoaded = $.Deferred(); - var nbLoaded = 0; - $newLinks.on('load', function (e) { - if (++nbLoaded >= $newLinks.length) { - linksLoaded.resolve(); - } - }); - $newLinks.on('error', function (e) { - linksLoaded.reject(); - window.location.hash = 'theme=true'; - window.location.reload(); + var linksLoaded = new Promise(function (resolve, reject) { + var nbLoaded = 0; + $newLinks.on('load', function () { + if (++nbLoaded >= $newLinks.length) { + resolve(); + } + }); + $newLinks.on('error', function () { + reject(); + window.location.hash = 'theme=true'; + window.location.reload(); + }); }); $links.last().after($newLinks); return linksLoaded; }); - return $.when.apply($, defs).always(function () { + return Promise.all(defs).then(function () { + $loading.remove(); + $allLinks.remove(); + }).guardedCatch(function () { $loading.remove(); $allLinks.remove(); }); @@ -750,7 +755,7 @@ var ThemeCustomizeMenu = websiteNavbarData.WebsiteNavbarActionWidget.extend({ * * @private * @param {string} tab - * @returns {Deferred} + * @returns {Promise} */ _openThemeCustomizeDialog: function (tab) { return new ThemeCustomizeDialog(this, {tab: tab}).open(); diff --git a/addons/website/static/tests/website_tests.js b/addons/website/static/tests/website_tests.js index e2dbe53b1b1..cd7d14a68a3 100644 --- a/addons/website/static/tests/website_tests.js +++ b/addons/website/static/tests/website_tests.js @@ -24,10 +24,10 @@ QUnit.module('website', { }; }, }, function () { - QUnit.test("widget website button: display false value", function (assert) { + QUnit.test("widget website button: display false value", async function (assert) { assert.expect(2); - var form = createView({ + var form = await createView({ View: FormView, model: 'blog_post', data: this.data, @@ -49,10 +49,10 @@ QUnit.module('website', { assert.containsOnce(form, selector, "there should be one text in red"); form.destroy(); }); - QUnit.test("widget website button: display true value", function (assert) { + QUnit.test("widget website button: display true value", async function (assert) { assert.expect(2); - var form = createView({ + var form = await createView({ View: FormView, model: 'blog_post', data: this.data,