summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorqsm-odoo <qsm@odoo.com>2019-02-06 14:29:07 +0000
committerqsm-odoo <qsm@odoo.com>2019-02-26 17:09:22 +0000
commit27fca749af30d7dce448f6632132422df8d8a7c1 (patch)
treec644db5efbb12cde722d059d250a83ec0de8aed7 /addons
parentc3da83b40a6431f607cf69b8c2a7a922a6e5b52c (diff)
[REF] *: use 'frontend' system in non-website apps
* account, auth_signup, payment, portal, project, sale, sale_management, web_unsplash, website, website_mail, website_rating, website_sale This commit does probably not do what is stated for all non-website apps but it is a first step. It also uses the system in apps which could have already used it but did not. Part of https://github.com/odoo/odoo/pull/29442 task-1932066
Diffstat (limited to 'addons')
-rw-r--r--addons/account/static/src/js/account_portal_sidebar.js34
-rw-r--r--addons/auth_signup/static/src/js/signup.js29
-rw-r--r--addons/payment/static/src/js/payment_form.js826
-rw-r--r--addons/portal/static/src/js/portal.js170
-rw-r--r--addons/portal/static/src/js/portal_chatter.js156
-rw-r--r--addons/portal/static/src/js/portal_sidebar.js19
-rw-r--r--addons/portal/static/src/js/portal_signature.js360
-rw-r--r--addons/project/static/src/js/portal_rating.js47
-rw-r--r--addons/sale/static/src/js/sale_portal_sidebar.js39
-rw-r--r--addons/sale_management/static/src/js/sale_management.js84
-rw-r--r--addons/web_unsplash/static/src/js/unsplash_beacon.js44
-rw-r--r--addons/website/static/src/js/content/website_root.js8
-rw-r--r--addons/website/static/src/js/website.js9
-rw-r--r--addons/website/views/website_templates.xml1
-rw-r--r--addons/website_mail/static/src/js/website_mail.js17
-rw-r--r--addons/website_rating/static/src/js/website_mail.js628
-rw-r--r--addons/website_sale/static/src/js/website_sale_payment.js56
17 files changed, 1342 insertions, 1185 deletions
diff --git a/addons/account/static/src/js/account_portal_sidebar.js b/addons/account/static/src/js/account_portal_sidebar.js
index 83fdf7dccae..92a31e69fe5 100644
--- a/addons/account/static/src/js/account_portal_sidebar.js
+++ b/addons/account/static/src/js/account_portal_sidebar.js
@@ -1,40 +1,25 @@
-odoo.define('account.AccountPortalSidebar.instance', function (require) {
-"use strict";
-
-require('web.dom_ready');
-var AccountPortalSidebar = require('account.AccountPortalSidebar');
-
-if (!$('.o_portal_invoice_sidebar').length) {
- return $.Deferred().reject("DOM doesn't contain '.o_portal_invoice_sidebar'");
-}
-
-var account_portal_sidebar = new AccountPortalSidebar();
-return account_portal_sidebar.attachTo($('.o_portal_invoice_sidebar')).then(function () {
- return account_portal_sidebar;
-});
-});
-
-//==============================================================================
-
odoo.define('account.AccountPortalSidebar', function (require) {
-"use strict";
+'use strict';
+var publicWidget = require('web.public.widget');
var PortalSidebar = require('portal.PortalSidebar');
-var AccountPortalSidebar = PortalSidebar.extend({
+publicWidget.registry.AccountPortalSidebar = PortalSidebar.extend({
+ selector: '.o_portal_invoice_sidebar',
events: {
'click .o_portal_invoice_print': '_onPrintInvoice',
},
+
/**
* @override
*/
start: function () {
- var self = this;
- this._super.apply(this, arguments);
+ var def = this._super.apply(this, arguments);
var $invoiceHtml = this.$el.find('iframe#invoice_html');
- var updateIframeSize = self._updateIframeSize.bind(self, $invoiceHtml);
+ var updateIframeSize = this._updateIframeSize.bind(this, $invoiceHtml);
$invoiceHtml.on('load', updateIframeSize);
$(window).on('resize', updateIframeSize);
+ return def;
},
//--------------------------------------------------------------------------
@@ -64,7 +49,4 @@ var AccountPortalSidebar = PortalSidebar.extend({
this._printIframeContent(href);
},
});
-
-
-return AccountPortalSidebar;
});
diff --git a/addons/auth_signup/static/src/js/signup.js b/addons/auth_signup/static/src/js/signup.js
index 567b2d612f1..366d4cef124 100644
--- a/addons/auth_signup/static/src/js/signup.js
+++ b/addons/auth_signup/static/src/js/signup.js
@@ -1,16 +1,25 @@
odoo.define('auth_signup.signup', function (require) {
- 'use strict';
+'use strict';
-require('web.dom_ready');
+var publicWidget = require('web.public.widget');
-// Disable 'Sign Up' button to prevent user form continuous clicking
-if ($('.oe_signup_form').length > 0) {
- $('.oe_signup_form').on('submit', function (ev) {
- var $form = $(ev.currentTarget);
- var $btn = $form.find('.oe_login_buttons > button[type="submit"]');
+publicWidget.registry.SignUpForm = publicWidget.Widget.extend({
+ selector: '.oe_signup_form',
+ events: {
+ 'submit': '_onSubmit',
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ _onSubmit: function () {
+ var $btn = this.$('.oe_login_buttons > button[type="submit"]');
$btn.attr('disabled', 'disabled');
$btn.prepend('<i class="fa fa-refresh fa-spin"/> ');
- });
-}
-
+ },
+});
});
diff --git a/addons/payment/static/src/js/payment_form.js b/addons/payment/static/src/js/payment_form.js
index 7494f50bf03..6bbe4604dd4 100644
--- a/addons/payment/static/src/js/payment_form.js
+++ b/addons/payment/static/src/js/payment_form.js
@@ -1,234 +1,163 @@
odoo.define('payment.payment_form', function (require) {
- "use strict";
-
- var ajax = require('web.ajax');
- var config = require('web.config');
- var core = require('web.core');
- var dom = require('web.dom');
- var Dialog = require("web.Dialog");
- var Widget = require("web.Widget");
- var rpc = require("web.rpc");
- var _t = core._t;
-
- var PaymentForm = Widget.extend({
-
- events: {
- 'click #o_payment_form_pay': 'payEvent',
- 'click #o_payment_form_add_pm': 'addPmEvent',
- 'click button[name="delete_pm"]': 'deletePmEvent',
- 'click .o_payment_acquirer_select': 'radioClickEvent',
- 'click .o_payment_form_pay_icon_more': 'onClickMorePaymentIcon',
- },
-
- init: function(parent, options) {
- this._super.apply(this, arguments);
- this.options = _.extend(options || {}, {
- });
-
- // TODO simplify this using the 'async' keyword in the events
- // property definition as soon as this widget is converted in
- // frontend widget.
- this.payEvent = dom.makeButtonHandler(this.payEvent);
- },
-
- start: function () {
- this.updateNewPaymentDisplayStatus();
- $('[data-toggle="tooltip"]').tooltip();
- },
-
- payEvent: function (ev) {
- ev.preventDefault();
- var form = this.el;
- var checked_radio = this.$('input[type="radio"]:checked');
- var self = this;
- var button = ev.target;
-
- // first we check that the user has selected a payment method
- if (checked_radio.length === 1) {
- checked_radio = checked_radio[0];
-
- // we retrieve all the input inside the acquirer form and 'serialize' them to an indexed array
- var acquirer_id = this.getAcquirerIdFromRadio(checked_radio);
- var acquirer_form = false;
- if (this.isNewPaymentRadio(checked_radio)) {
- acquirer_form = this.$('#o_payment_add_token_acq_' + acquirer_id);
- } else {
- acquirer_form = this.$('#o_payment_form_acq_' + acquirer_id);
- }
- var inputs_form = $('input', acquirer_form);
- var ds = $('input[name="data_set"]', acquirer_form)[0];
-
- // if the user is adding a new payment
- if (this.isNewPaymentRadio(checked_radio)) {
- if (this.options.partnerId === undefined) {
- console.warn('payment_form: unset partner_id when adding new token; things could go wrong');
- }
- var form_data = this.getFormData(inputs_form);
- var wrong_input = false;
-
- inputs_form.toArray().forEach(function (element) {
- //skip the check of non visible inputs
- if ($(element).attr('type') == 'hidden') {
- return true;
- }
- $(element).closest('div.form-group').removeClass('o_has_error').find('.form-control, .custom-select').removeClass('is-invalid');
- $(element).siblings( ".o_invalid_field" ).remove();
- //force check of forms validity (useful for Firefox that refill forms automatically on f5)
- $(element).trigger("focusout");
- if (element.dataset.isRequired && element.value.length === 0) {
- $(element).closest('div.form-group').addClass('o_has_error').find('.form-control, .custom-select').addClass('is-invalid');
- $(element).closest('div.form-group').append('<div style="color: red" class="o_invalid_field" aria-invalid="true">' + _.str.escapeHTML("The value is invalid.") + '</div>');
- wrong_input = true;
- }
- else if ($(element).closest('div.form-group').hasClass('o_has_error')) {
- wrong_input = true;
- $(element).closest('div.form-group').append('<div style="color: red" class="o_invalid_field" aria-invalid="true">' + _.str.escapeHTML("The value is invalid.") + '</div>');
- }
- });
-
- if (wrong_input) {
- return;
- }
-
- $(button).attr('disabled', true);
- $(button).children('.fa-plus-circle').removeClass('fa-plus-circle')
- $(button).prepend('<span class="o_loader"><i class="fa fa-refresh fa-spin"></i>&nbsp;</span>');
-
- var verify_validity = this.$el.find('input[name="verify_validity"]');
+"use strict";
+
+var core = require('web.core');
+var Dialog = require('web.Dialog');
+var publicWidget = require('web.public.widget');
+
+var _t = core._t;
+
+publicWidget.registry.PaymentForm = publicWidget.Widget.extend({
+ selector: '.o_payment_form',
+ events: {
+ 'click #o_payment_form_pay': 'async payEvent',
+ 'click #o_payment_form_add_pm': 'addPmEvent',
+ 'click button[name="delete_pm"]': 'deletePmEvent',
+ 'click .o_payment_form_pay_icon_more': 'onClickMorePaymentIcon',
+ 'click .o_payment_acquirer_select': 'radioClickEvent',
+ },
+
+ /**
+ * @override
+ */
+ start: function () {
+ this.options = _.extend(this.$el.data(), this.options);
+ this.updateNewPaymentDisplayStatus();
+ $('[data-toggle="tooltip"]').tooltip();
+ return this._super.apply(this, arguments);
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * @param {string} title
+ * @param {string} message
+ */
+ displayError: function (title, message) {
+ var $checkedRadio = this.$('input[type="radio"]:checked'),
+ acquirerID = this.getAcquirerIdFromRadio($checkedRadio[0]);
+ var $acquirerForm;
+ if (this.isNewPaymentRadio($checkedRadio[0])) {
+ $acquirerForm = this.$('#o_payment_add_token_acq_' + acquirerID);
+ }
+ else if (this.isFormPaymentRadio($checkedRadio[0])) {
+ $acquirerForm = this.$('#o_payment_form_acq_' + acquirerID);
+ }
- if (verify_validity.length>0) {
- form_data.verify_validity = verify_validity[0].value === "1";
- }
+ if ($checkedRadio.length === 0) {
+ return new Dialog(null, {
+ title: _t('Error: ') + _.str.escapeHTML(title),
+ size: 'medium',
+ $content: "<p>" + (_.str.escapeHTML(message) || "") + "</p>" ,
+ buttons: [
+ {text: _t('Ok'), close: true}]}).open();
+ } else {
+ // removed if exist error message
+ this.$('#payment_error').remove();
+ var messageResult = '<div class="alert alert-danger mb4" id="payment_error">';
+ if (title != '') {
+ messageResult = messageResult + '<b>' + _.str.escapeHTML(title) + ':</b></br>';
+ }
+ messageResult = messageResult + _.str.escapeHTML(message) + '</div>';
+ $acquirerForm.append(messageResult);
+ }
+ },
+ /**
+ * @private
+ * @param {DOMElement} element
+ */
+ getAcquirerIdFromRadio: function (element) {
+ return $(element).data('acquirer-id');
+ },
+ /**
+ * @private
+ * @param {jQuery} $form
+ */
+ getFormData: function ($form) {
+ var unindexed_array = $form.serializeArray();
+ var indexed_array = {};
+
+ $.map(unindexed_array, function (n, i) {
+ indexed_array[n.name] = n.value;
+ });
+ return indexed_array;
+ },
+ /**
+ * @private
+ * @param {DOMElement} element
+ */
+ isFormPaymentRadio: function (element) {
+ return $(element).data('form-payment') === 'True';
+ },
+ /**
+ * @private
+ * @param {DOMElement} element
+ */
+ isNewPaymentRadio: function (element) {
+ return $(element).data('s2s-payment') === 'True';
+ },
+ /**
+ * @private
+ */
+ updateNewPaymentDisplayStatus: function () {
+ var checked_radio = this.$('input[type="radio"]:checked');
+ // we hide all the acquirers form
+ this.$('[id*="o_payment_add_token_acq_"]').addClass('d-none');
+ this.$('[id*="o_payment_form_acq_"]').addClass('d-none');
+ if (checked_radio.length !== 1) {
+ return;
+ }
+ checked_radio = checked_radio[0];
+ var acquirer_id = this.getAcquirerIdFromRadio(checked_radio);
- // do the call to the route stored in the 'data_set' input of the acquirer form, the data must be called 'create-route'
- return ajax.jsonRpc(ds.dataset.createRoute, 'call', form_data).then(function (data) {
- // if the server has returned true
- if (data.result) {
- // and it need a 3DS authentication
- if (data['3d_secure'] !== false) {
- // then we display the 3DS page to the user
- $("body").html(data['3d_secure']);
- }
- else {
- checked_radio.value = data.id; // set the radio value to the new card id
- form.submit();
- return $.Deferred();
- }
- }
- // if the server has returned false, we display an error
- else {
- if (data.error) {
- self.displayError(
- '',
- data.error);
- } else { // if the server doesn't provide an error message
- self.displayError(
- _t('Server Error'),
- _t('e.g. Your credit card details are wrong. Please verify.'));
- }
- }
- // here we remove the 'processing' icon from the 'add a new payment' button
- $(button).attr('disabled', false);
- $(button).children('.fa').addClass('fa-plus-circle')
- $(button).find('span.o_loader').remove();
- }).fail(function (error, event) {
- // if the rpc fails, pretty obvious
- $(button).attr('disabled', false);
- $(button).children('.fa').addClass('fa-plus-circle')
- $(button).find('span.o_loader').remove();
+ // if we clicked on an add new payment radio, display its form
+ if (this.isNewPaymentRadio(checked_radio)) {
+ this.$('#o_payment_add_token_acq_' + acquirer_id).removeClass('d-none');
+ }
+ else if (this.isFormPaymentRadio(checked_radio)) {
+ this.$('#o_payment_form_acq_' + acquirer_id).removeClass('d-none');
+ }
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * @param {Event} ev
+ */
+ payEvent: function (ev) {
+ ev.preventDefault();
+ var form = this.el;
+ var checked_radio = this.$('input[type="radio"]:checked');
+ var self = this;
+ var button = ev.target;
+
+ // first we check that the user has selected a payment method
+ if (checked_radio.length === 1) {
+ checked_radio = checked_radio[0];
- self.displayError(
- _t('Server Error'),
- _t("We are not able to add your payment method at the moment.") +
- error.data.message
- );
- });
- }
- // if the user is going to pay with a form payment, then
- else if (this.isFormPaymentRadio(checked_radio)) {
- var $tx_url = this.$el.find('input[name="prepare_tx_url"]');
- // if there's a prepare tx url set
- if ($tx_url.length === 1) {
- // if the user wants to save his credit card info
- var form_save_token = acquirer_form.find('input[name="o_payment_form_save_token"]').prop('checked');
- // then we call the route to prepare the transaction
- return ajax.jsonRpc($tx_url[0].value, 'call', {
- 'acquirer_id': parseInt(acquirer_id),
- 'save_token': form_save_token,
- 'access_token': self.options.accessToken,
- 'success_url': self.options.successUrl,
- 'error_url': self.options.errorUrl,
- 'callback_method': self.options.callbackMethod,
- 'order_id': self.options.orderId,
- }).then(function (result) {
- if (result) {
- // if the server sent us the html form, we create a form element
- var newForm = document.createElement('form');
- newForm.setAttribute("method", "post"); // set it to post
- newForm.setAttribute("provider", checked_radio.dataset.provider);
- newForm.hidden = true; // hide it
- newForm.innerHTML = result; // put the html sent by the server inside the form
- var action_url = $(newForm).find('input[name="data_set"]').data('actionUrl');
- newForm.setAttribute("action", action_url); // set the action url
- $(document.getElementsByTagName('body')[0]).append(newForm); // append the form to the body
- $(newForm).find('input[data-remove-me]').remove(); // remove all the input that should be removed
- if(action_url) {
- newForm.submit(); // and finally submit the form
- return $.Deferred();
- }
- }
- else {
- self.displayError(
- _t('Server Error'),
- _t("We are not able to redirect you to the payment form.")
- );
- }
- }).fail(function (error, event) {
- self.displayError(
- _t('Server Error'),
- _t("We are not able to redirect you to the payment form. ") +
- error.data.message
- );
- });
- }
- else {
- // we append the form to the body and send it.
- this.displayError(
- _t("Cannot set-up the payment"),
- _t("We're unable to process your payment.")
- );
- }
- }
- else { // if the user is using an old payment then we just submit the form
- form.submit();
- return $.Deferred();
- }
- }
- else {
- this.displayError(
- _t('No payment method selected'),
- _t('Please select a payment method.')
- );
+ // we retrieve all the input inside the acquirer form and 'serialize' them to an indexed array
+ var acquirer_id = this.getAcquirerIdFromRadio(checked_radio);
+ var acquirer_form = false;
+ if (this.isNewPaymentRadio(checked_radio)) {
+ acquirer_form = this.$('#o_payment_add_token_acq_' + acquirer_id);
+ } else {
+ acquirer_form = this.$('#o_payment_form_acq_' + acquirer_id);
}
- },
- // event handler when clicking on the button to add a new payment method
- addPmEvent: function (ev) {
- ev.stopPropagation();
- ev.preventDefault();
- var checked_radio = this.$('input[type="radio"]:checked');
- var self = this;
- var button = ev.target;
+ var inputs_form = $('input', acquirer_form);
+ var ds = $('input[name="data_set"]', acquirer_form)[0];
- // we check if the user has selected a 'add a new payment' option
- if (checked_radio.length === 1 && this.isNewPaymentRadio(checked_radio[0])) {
- // we retrieve which acquirer is used
- checked_radio = checked_radio[0];
- var acquirer_id = this.getAcquirerIdFromRadio(checked_radio);
- var acquirer_form = this.$('#o_payment_add_token_acq_' + acquirer_id);
- // we retrieve all the input inside the acquirer form and 'serialize' them to an indexed array
- var inputs_form = $('input', acquirer_form);
+ // if the user is adding a new payment
+ if (this.isNewPaymentRadio(checked_radio)) {
+ if (this.options.partnerId === undefined) {
+ console.warn('payment_form: unset partner_id when adding new token; things could go wrong');
+ }
var form_data = this.getFormData(inputs_form);
- var ds = $('input[name="data_set"]', acquirer_form)[0];
var wrong_input = false;
inputs_form.toArray().forEach(function (element) {
@@ -242,30 +171,34 @@ odoo.define('payment.payment_form', function (require) {
$(element).trigger("focusout");
if (element.dataset.isRequired && element.value.length === 0) {
$(element).closest('div.form-group').addClass('o_has_error').find('.form-control, .custom-select').addClass('is-invalid');
- var message = '<div style="color: red" class="o_invalid_field" aria-invalid="true">' + _.str.escapeHTML("The value is invalid.") + '</div>';
- $(element).closest('div.form-group').append(message);
+ $(element).closest('div.form-group').append('<div style="color: red" class="o_invalid_field" aria-invalid="true">' + _.str.escapeHTML("The value is invalid.") + '</div>');
wrong_input = true;
}
else if ($(element).closest('div.form-group').hasClass('o_has_error')) {
wrong_input = true;
- var message = '<div style="color: red" class="o_invalid_field" aria-invalid="true">' + _.str.escapeHTML("The value is invalid.") + '</div>';
- $(element).closest('div.form-group').append(message);
+ $(element).closest('div.form-group').append('<div style="color: red" class="o_invalid_field" aria-invalid="true">' + _.str.escapeHTML("The value is invalid.") + '</div>');
}
});
if (wrong_input) {
return;
}
- // We add a 'processing' icon into the 'add a new payment' button
+
$(button).attr('disabled', true);
- $(button).children('.fa-plus-circle').removeClass('fa-plus-circle')
+ $(button).children('.fa-plus-circle').removeClass('fa-plus-circle');
$(button).prepend('<span class="o_loader"><i class="fa fa-refresh fa-spin"></i>&nbsp;</span>');
- // we force the check when adding a card trough here
- form_data.verify_validity = true;
+ var verify_validity = this.$el.find('input[name="verify_validity"]');
+
+ if (verify_validity.length>0) {
+ form_data.verify_validity = verify_validity[0].value === "1";
+ }
// do the call to the route stored in the 'data_set' input of the acquirer form, the data must be called 'create-route'
- ajax.jsonRpc(ds.dataset.createRoute, 'call', form_data).then( function (data) {
+ return this._rpc({
+ route: ds.dataset.createRoute,
+ params: form_data,
+ }).then(function (data) {
// if the server has returned true
if (data.result) {
// and it need a 3DS authentication
@@ -273,15 +206,10 @@ odoo.define('payment.payment_form', function (require) {
// then we display the 3DS page to the user
$("body").html(data['3d_secure']);
}
- // if it doesn't require 3DS
else {
- // we just go to the return_url or reload the page
- if (form_data.return_url) {
- window.location = form_data.return_url;
- }
- else {
- window.location.reload();
- }
+ checked_radio.value = data.id; // set the radio value to the new card id
+ form.submit();
+ return $.Deferred();
}
}
// if the server has returned false, we display an error
@@ -298,186 +226,296 @@ odoo.define('payment.payment_form', function (require) {
}
// here we remove the 'processing' icon from the 'add a new payment' button
$(button).attr('disabled', false);
- $(button).children('.fa').addClass('fa-plus-circle')
+ $(button).children('.fa').addClass('fa-plus-circle');
$(button).find('span.o_loader').remove();
}).fail(function (error, event) {
// if the rpc fails, pretty obvious
$(button).attr('disabled', false);
- $(button).children('.fa').addClass('fa-plus-circle')
+ $(button).children('.fa').addClass('fa-plus-circle');
$(button).find('span.o_loader').remove();
self.displayError(
- _t('Server error'),
- _t("We are not able to add your payment method at the moment.</p>") +
- error.data.message
+ _t('Server Error'),
+ _t("We are not able to add your payment method at the moment.") +
+ error.data.message
);
});
}
- else {
- this.displayError(
- _t('No payment method selected'),
- _t('Please select the option to add a new payment method.')
- );
- }
- },
- // event handler when clicking on a button to delete a payment method
- deletePmEvent: function (ev) {
- ev.stopPropagation();
- ev.preventDefault();
- var self = this;
- var pm_id = parseInt(ev.target.value);
-
- var tokenDelete = function () {
- rpc.query({
- model: 'payment.token',
- method: 'unlink',
- args: [pm_id],
- })
- .then(function (result) {
- if ( result === true) {
- ev.target.closest('div').remove();
+ // if the user is going to pay with a form payment, then
+ else if (this.isFormPaymentRadio(checked_radio)) {
+ var $tx_url = this.$el.find('input[name="prepare_tx_url"]');
+ // if there's a prepare tx url set
+ if ($tx_url.length === 1) {
+ // if the user wants to save his credit card info
+ var form_save_token = acquirer_form.find('input[name="o_payment_form_save_token"]').prop('checked');
+ // then we call the route to prepare the transaction
+ return this._rpc({
+ route: $tx_url[0].value,
+ params: {
+ 'acquirer_id': parseInt(acquirer_id),
+ 'save_token': form_save_token,
+ 'access_token': self.options.accessToken,
+ 'success_url': self.options.successUrl,
+ 'error_url': self.options.errorUrl,
+ 'callback_method': self.options.callbackMethod,
+ 'order_id': self.options.orderId,
+ },
+ }).then(function (result) {
+ if (result) {
+ // if the server sent us the html form, we create a form element
+ var newForm = document.createElement('form');
+ newForm.setAttribute("method", "post"); // set it to post
+ newForm.setAttribute("provider", checked_radio.dataset.provider);
+ newForm.hidden = true; // hide it
+ newForm.innerHTML = result; // put the html sent by the server inside the form
+ var action_url = $(newForm).find('input[name="data_set"]').data('actionUrl');
+ newForm.setAttribute("action", action_url); // set the action url
+ $(document.getElementsByTagName('body')[0]).append(newForm); // append the form to the body
+ $(newForm).find('input[data-remove-me]').remove(); // remove all the input that should be removed
+ if(action_url) {
+ newForm.submit(); // and finally submit the form
+ return $.Deferred();
+ }
}
- }, function () {
+ else {
+ self.displayError(
+ _t('Server Error'),
+ _t("We are not able to redirect you to the payment form.")
+ );
+ }
+ }).fail(function (error, event) {
self.displayError(
_t('Server Error'),
- _t("We are not able to delete your payment method at the moment.")
+ _t("We are not able to redirect you to the payment form. ") +
+ error.data.message
);
});
- };
+ }
+ else {
+ // we append the form to the body and send it.
+ this.displayError(
+ _t("Cannot set-up the payment"),
+ _t("We're unable to process your payment.")
+ );
+ }
+ }
+ else { // if the user is using an old payment then we just submit the form
+ form.submit();
+ return $.Deferred();
+ }
+ }
+ else {
+ this.displayError(
+ _t('No payment method selected'),
+ _t('Please select a payment method.')
+ );
+ }
+ },
+ /**
+ * Called when clicking on the button to add a new payment method.
+ *
+ * @private
+ * @param {Event} ev
+ */
+ addPmEvent: function (ev) {
+ ev.stopPropagation();
+ ev.preventDefault();
+ var checked_radio = this.$('input[type="radio"]:checked');
+ var self = this;
+ var button = ev.target;
+
+ // we check if the user has selected a 'add a new payment' option
+ if (checked_radio.length === 1 && this.isNewPaymentRadio(checked_radio[0])) {
+ // we retrieve which acquirer is used
+ checked_radio = checked_radio[0];
+ var acquirer_id = this.getAcquirerIdFromRadio(checked_radio);
+ var acquirer_form = this.$('#o_payment_add_token_acq_' + acquirer_id);
+ // we retrieve all the input inside the acquirer form and 'serialize' them to an indexed array
+ var inputs_form = $('input', acquirer_form);
+ var form_data = this.getFormData(inputs_form);
+ var ds = $('input[name="data_set"]', acquirer_form)[0];
+ var wrong_input = false;
+
+ inputs_form.toArray().forEach(function (element) {
+ //skip the check of non visible inputs
+ if ($(element).attr('type') == 'hidden') {
+ return true;
+ }
+ $(element).closest('div.form-group').removeClass('o_has_error').find('.form-control, .custom-select').removeClass('is-invalid');
+ $(element).siblings( ".o_invalid_field" ).remove();
+ //force check of forms validity (useful for Firefox that refill forms automatically on f5)
+ $(element).trigger("focusout");
+ if (element.dataset.isRequired && element.value.length === 0) {
+ $(element).closest('div.form-group').addClass('o_has_error').find('.form-control, .custom-select').addClass('is-invalid');
+ var message = '<div style="color: red" class="o_invalid_field" aria-invalid="true">' + _.str.escapeHTML("The value is invalid.") + '</div>';
+ $(element).closest('div.form-group').append(message);
+ wrong_input = true;
+ }
+ else if ($(element).closest('div.form-group').hasClass('o_has_error')) {
+ wrong_input = true;
+ var message = '<div style="color: red" class="o_invalid_field" aria-invalid="true">' + _.str.escapeHTML("The value is invalid.") + '</div>';
+ $(element).closest('div.form-group').append(message);
+ }
+ });
+
+ if (wrong_input) {
+ return;
+ }
+ // We add a 'processing' icon into the 'add a new payment' button
+ $(button).attr('disabled', true);
+ $(button).children('.fa-plus-circle').removeClass('fa-plus-circle');
+ $(button).prepend('<span class="o_loader"><i class="fa fa-refresh fa-spin"></i>&nbsp;</span>');
+
+ // we force the check when adding a card trough here
+ form_data.verify_validity = true;
+
+ // do the call to the route stored in the 'data_set' input of the acquirer form, the data must be called 'create-route'
+ this._rpc({
+ route: ds.dataset.createRoute,
+ params: form_data,
+ }).then(function (data) {
+ // if the server has returned true
+ if (data.result) {
+ // and it need a 3DS authentication
+ if (data['3d_secure'] !== false) {
+ // then we display the 3DS page to the user
+ $("body").html(data['3d_secure']);
+ }
+ // if it doesn't require 3DS
+ else {
+ // we just go to the return_url or reload the page
+ if (form_data.return_url) {
+ window.location = form_data.return_url;
+ }
+ else {
+ window.location.reload();
+ }
+ }
+ }
+ // if the server has returned false, we display an error
+ else {
+ if (data.error) {
+ self.displayError(
+ '',
+ data.error);
+ } else { // if the server doesn't provide an error message
+ self.displayError(
+ _t('Server Error'),
+ _t('e.g. Your credit card details are wrong. Please verify.'));
+ }
+ }
+ // here we remove the 'processing' icon from the 'add a new payment' button
+ $(button).attr('disabled', false);
+ $(button).children('.fa').addClass('fa-plus-circle');
+ $(button).find('span.o_loader').remove();
+ }).fail(function (error, event) {
+ // if the rpc fails, pretty obvious
+ $(button).attr('disabled', false);
+ $(button).children('.fa').addClass('fa-plus-circle');
+ $(button).find('span.o_loader').remove();
- rpc.query({
+ self.displayError(
+ _t('Server error'),
+ _t("We are not able to add your payment method at the moment.</p>") +
+ error.data.message
+ );
+ });
+ }
+ else {
+ this.displayError(
+ _t('No payment method selected'),
+ _t('Please select the option to add a new payment method.')
+ );
+ }
+ },
+ /**
+ * Called when clicking on a button to delete a payment method.
+ *
+ * @private
+ * @param {Event} ev
+ */
+ deletePmEvent: function (ev) {
+ ev.stopPropagation();
+ ev.preventDefault();
+ var self = this;
+ var pm_id = parseInt(ev.target.value);
+
+ var tokenDelete = function () {
+ self._rpc({
model: 'payment.token',
- method: 'get_linked_records',
+ method: 'unlink',
args: [pm_id],
}).then(function (result) {
- if (result[pm_id].length > 0) {
- // if there's records linked to this payment method
- var content = '';
- result[pm_id].forEach(function (sub) {
- content += '<p><a href="' + sub.url + '" title="' + sub.description + '">' + sub.name + '</a><p/>';
- });
-
- content = $('<div>').html(_t('<p>This card is currently linked to the following records:<p/>') + content);
- // Then we display the list of the records and ask the user if he really want to remove the payment method.
- new Dialog(self, {
- title: _t('Warning!'),
- size: 'medium',
- $content: content,
- buttons: [
- {text: _t('Confirm Deletion'), classes: 'btn-primary', close: true, click: tokenDelete},
- {text: _t('Cancel'), close: true}]
- }).open();
- }
- else {
- // if there's no records linked to this payment method, then we delete it
- tokenDelete();
+ if (result === true) {
+ ev.target.closest('div').remove();
}
- }, function (err, event) {
+ }, function () {
self.displayError(
_t('Server Error'),
- _t("We are not able to delete your payment method at the moment.") + err.data.message
+ _t("We are not able to delete your payment method at the moment.")
);
});
- },
-
- // event handler when clicking on 'and more' to show more payment icon
- onClickMorePaymentIcon: function (ev) {
- ev.preventDefault();
- ev.stopPropagation();
- var $listItems = $(ev.currentTarget).parents('ul').children('li');
- var $moreItem = $(ev.currentTarget).parents('li');
- $listItems.removeClass('d-none');
- $moreItem.addClass('d-none');
- },
-
- // event handler when clicking on a radio button
- radioClickEvent: function (ev) {
- // radio button checked when we click on entire zone(body) of the payment acquirer
- $(ev.currentTarget).find('input[type="radio"]').prop("checked", true);
- this.updateNewPaymentDisplayStatus();
- },
- updateNewPaymentDisplayStatus: function ()
- {
- var checked_radio = this.$('input[type="radio"]:checked');
- // we hide all the acquirers form
- this.$('[id*="o_payment_add_token_acq_"]').addClass('d-none');
- this.$('[id*="o_payment_form_acq_"]').addClass('d-none');
- if (checked_radio.length !== 1) {
- return;
- }
- checked_radio = checked_radio[0];
- var acquirer_id = this.getAcquirerIdFromRadio(checked_radio);
-
- // if we clicked on an add new payment radio, display its form
- if (this.isNewPaymentRadio(checked_radio)) {
- this.$('#o_payment_add_token_acq_' + acquirer_id).removeClass('d-none');
- }
- else if (this.isFormPaymentRadio(checked_radio)) {
- this.$('#o_payment_form_acq_' + acquirer_id).removeClass('d-none');
- }
- },
- isNewPaymentRadio: function (element) {
- return $(element).data('s2s-payment') === 'True';
- },
- isFormPaymentRadio: function (element) {
- return $(element).data('form-payment') === 'True';
- },
- getAcquirerIdFromRadio: function (element) {
- return $(element).data('acquirer-id');
- },
- displayError: function (title, message) {
- var $checkedRadio = this.$('input[type="radio"]:checked'),
- acquirerID = this.getAcquirerIdFromRadio($checkedRadio[0]);
- var $acquirerForm;
- if (this.isNewPaymentRadio($checkedRadio[0])) {
- $acquirerForm = this.$('#o_payment_add_token_acq_' + acquirerID);
- }
- else if (this.isFormPaymentRadio($checkedRadio[0])) {
- $acquirerForm = this.$('#o_payment_form_acq_' + acquirerID);
- }
+ };
+
+ this._rpc({
+ model: 'payment.token',
+ method: 'get_linked_records',
+ args: [pm_id],
+ }).then(function (result) {
+ if (result[pm_id].length > 0) {
+ // if there's records linked to this payment method
+ var content = '';
+ result[pm_id].forEach(function (sub) {
+ content += '<p><a href="' + sub.url + '" title="' + sub.description + '">' + sub.name + '</a><p/>';
+ });
- if ($checkedRadio.length === 0) {
- return new Dialog(null, {
- title: _t('Error: ') + _.str.escapeHTML(title),
+ content = $('<div>').html(_t('<p>This card is currently linked to the following records:<p/>') + content);
+ // Then we display the list of the records and ask the user if he really want to remove the payment method.
+ new Dialog(self, {
+ title: _t('Warning!'),
size: 'medium',
- $content: "<p>" + (_.str.escapeHTML(message) || "") + "</p>" ,
+ $content: content,
buttons: [
- {text: _t('Ok'), close: true}]}).open();
- } else {
- // removed if exist error message
- this.$('#payment_error').remove();
- var messageResult = '<div class="alert alert-danger mb4" id="payment_error">';
- if (title != '') {
- messageResult = messageResult + '<b>' + _.str.escapeHTML(title) + ':</b></br>';
- }
- messageResult = messageResult + _.str.escapeHTML(message) + '</div>';
- $acquirerForm.append(messageResult);
+ {text: _t('Confirm Deletion'), classes: 'btn-primary', close: true, click: tokenDelete},
+ {text: _t('Cancel'), close: true}]
+ }).open();
}
- },
- getFormData: function ($form) {
- var unindexed_array = $form.serializeArray();
- var indexed_array = {};
-
- $.map(unindexed_array, function (n, i) {
- indexed_array[n.name] = n.value;
- });
- return indexed_array;
- },
- });
-
- $(function () {
- // TODO move this to another module, requiring dom_ready and rejecting
- // the returned deferred to get the proper message
- if (!$('.o_payment_form').length) {
- console.log("DOM doesn't contain '.o_payment_form'");
- return;
- }
- $('.o_payment_form').each(function () {
- var $elem = $(this);
- var form = new PaymentForm(null, $elem.data());
- form.attachTo($elem);
+ else {
+ // if there's no records linked to this payment method, then we delete it
+ tokenDelete();
+ }
+ }, function (err, event) {
+ self.displayError(
+ _t('Server Error'),
+ _t("We are not able to delete your payment method at the moment.") + err.data.message
+ );
});
- });
-
- return PaymentForm;
+ },
+ /**
+ * Called when clicking on 'and more' to show more payment icon.
+ *
+ * @private
+ * @param {Event} ev
+ */
+ onClickMorePaymentIcon: function (ev) {
+ ev.preventDefault();
+ ev.stopPropagation();
+ var $listItems = $(ev.currentTarget).parents('ul').children('li');
+ var $moreItem = $(ev.currentTarget).parents('li');
+ $listItems.removeClass('d-none');
+ $moreItem.addClass('d-none');
+ },
+ /**
+ * Called when clicking on a radio button.
+ *
+ * @private
+ * @param {Event} ev
+ */
+ radioClickEvent: function (ev) {
+ // radio button checked when we click on entire zone(body) of the payment acquirer
+ $(ev.currentTarget).find('input[type="radio"]').prop("checked", true);
+ this.updateNewPaymentDisplayStatus();
+ },
+});
+return publicWidget.registry.PaymentForm;
});
diff --git a/addons/portal/static/src/js/portal.js b/addons/portal/static/src/js/portal.js
index f750bab1318..6a96ac5c967 100644
--- a/addons/portal/static/src/js/portal.js
+++ b/addons/portal/static/src/js/portal.js
@@ -1,48 +1,130 @@
odoo.define('portal.portal', function (require) {
'use strict';
- require('web.dom_ready');
-
-
- if (!$('.o_portal').length) {
- return $.Deferred().reject("DOM doesn't contain '.o_portal'");
- }
-
- if ($('.o_portal_details').length) {
- var state_options = $("select[name='state_id']:enabled option:not(:first)");
- $('.o_portal_details').on('change', "select[name='country_id']", function () {
- var select = $("select[name='state_id']");
- state_options.detach();
- var displayed_state = state_options.filter("[data-country_id="+($(this).val() || 0)+"]");
- var nb = displayed_state.appendTo(select).show().size();
- select.parent().toggle(nb>=1);
- });
- $('.o_portal_details').find("select[name='country_id']").change();
- }
-
- if ($('.o_portal_search_panel').length) {
- $('.o_portal_search_panel .search-submit').click(function () {
- var search = $.deparam(window.location.search.substring(1));
- search.search_in = $(".o_portal_search_panel .dropdown-item.active").attr("href").replace("#","");
- search.search = $(".o_portal_search_panel input[name='search']").val();
- window.location.search = $.param(search);
- });
-
- $('.o_portal_search_panel .dropdown-menu').find('.dropdown-item').click(function (e) {
- e.preventDefault();
- $(this).parents('.dropdown-menu').find('.dropdown-item').removeClass('active');
- $(this).closest('.dropdown-item').addClass('active');
- var label = $(this).clone();
- label.find('span.nolabel').remove();
- $(".o_portal_search_panel span#search_label").text(label.text());
- });
- // init search label
- $('.o_portal_search_panel .dropdown-menu').find('.dropdown-item.active').trigger('click');
-
- $(".o_portal_search_panel input[name='search']").on('keyup', function (e) {
- if (e.keyCode === 13) {
- $('.o_portal_search_panel .search-submit').trigger('click');
- }
- });
- }
+var publicWidget = require('web.public.widget');
+
+publicWidget.registry.portalDetails = publicWidget.Widget.extend({
+ selector: '.o_portal_details',
+ read_events: {
+ 'change select[name="country_id"]': '_onCountryChange',
+ },
+
+ /**
+ * @override
+ */
+ start: function () {
+ var def = this._super.apply(this, arguments);
+ if (this.editableMode) {
+ return;
+ }
+
+ this.$state = this.$('select[name="state_id"]');
+ this.$stateOptions = this.$state.filter(':enabled').find('option:not(:first)');
+ this._adaptAddressForm();
+
+ return def;
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ _adaptAddressForm: function () {
+ var $country = this.$('select[name="country_id"]');
+ var countryID = ($country.val() || 0);
+ this.$stateOptions.detach();
+ var $displayedState = this.$stateOptions.filter('[data-country_id=' + countryID + ']');
+ var nb = $displayedState.appendTo(this.$state).show().size();
+ this.$state.parent().toggle(nb >= 1);
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ _onCountryChange: function () {
+ this._adaptAddressForm();
+ },
+});
+
+publicWidget.registry.portalSearchPanel = publicWidget.Widget.extend({
+ selector: '.o_portal_search_panel',
+ read_events: {
+ 'click .search-submit': '_onSearchSubmitClick',
+ 'click .dropdown-item': '_onDropdownItemClick',
+ 'keyup input[name="search"]': '_onSearchInputKeyup',
+ },
+
+ /**
+ * @override
+ */
+ start: function () {
+ var def = this._super.apply(this, arguments);
+ if (this.editableMode) {
+ return;
+ }
+
+ this._adaptSearchLabel(this.$('.dropdown-item.active'));
+
+ return def;
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ _adaptSearchLabel: function (elem) {
+ var $label = $(elem).clone();
+ $label.find('span.nolabel').remove();
+ this.$('input[name="search"]').attr('placeholder', $label.text().trim());
+ },
+ /**
+ * @private
+ */
+ _search: function () {
+ var search = $.deparam(window.location.search.substring(1));
+ search['search_in'] = this.$('.dropdown-item.active').attr('href').replace('#', '');
+ search['search'] = this.$('input[name="search"]').val();
+ window.location.search = $.param(search);
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ _onSearchSubmitClick: function () {
+ this._search();
+ },
+ /**
+ * @private
+ */
+ _onDropdownItemClick: function (ev) {
+ ev.preventDefault();
+ var $item = $(ev.currentTarget);
+ $item.closest('.dropdown-menu').find('.dropdown-item').removeClass('active');
+ $item.addClass('active');
+
+ this._adaptSearchLabel(ev.currentTarget);
+ },
+ /**
+ * @private
+ */
+ _onSearchInputKeyup: function (ev) {
+ if (ev.keyCode === $.ui.keyCode.ENTER) {
+ this._search();
+ }
+ },
+});
});
diff --git a/addons/portal/static/src/js/portal_chatter.js b/addons/portal/static/src/js/portal_chatter.js
index bfd8fe95957..081a8f02ad3 100644
--- a/addons/portal/static/src/js/portal_chatter.js
+++ b/addons/portal/static/src/js/portal_chatter.js
@@ -1,12 +1,8 @@
-odoo.define('portal.chatter', function(require) {
+odoo.define('portal.chatter', function (require) {
'use strict';
-var base = require('web_editor.base');
-var ajax = require('web.ajax');
var core = require('web.core');
-var dom = require('web.dom');
-var Widget = require('web.Widget');
-var rpc = require('web.rpc');
+var publicWidget = require('web.public.widget');
var time = require('web.time');
var qweb = core.qweb;
@@ -18,12 +14,17 @@ var _t = core._t;
* Display the composer (according to access right)
*
*/
-var PortalComposer = Widget.extend({
+var PortalComposer = publicWidget.Widget.extend({
template: 'portal.Composer',
+ xmlDependencies: ['/portal/static/src/xml/portal_chatter.xml'],
events: {
- 'click .o_portal_chatter_composer_btn': '_onSubmitButtonClick',
+ 'click .o_portal_chatter_composer_btn': 'async _onSubmitButtonClick',
},
- init: function(parent, options){
+
+ /**
+ * @constructor
+ */
+ init: function (parent, options) {
this._super.apply(this, arguments);
this.options = _.defaults(options || {}, {
'allow_composer': true,
@@ -33,12 +34,12 @@ var PortalComposer = Widget.extend({
'res_model': false,
'res_id': false,
});
-
- // TODO simplify this using the 'async' keyword in the events
- // property definition as soon as this widget is converted in
- // frontend widget.
- this._onSubmitButtonClick = dom.makeButtonHandler(this._onSubmitButtonClick);
},
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
/**
* @private
*/
@@ -56,20 +57,23 @@ var PortalComposer = Widget.extend({
* - Display chatter: pager, total message, composer (according to access right)
* - Provider API to filter displayed messages
*/
-var PortalChatter = Widget.extend({
+var PortalChatter = publicWidget.Widget.extend({
template: 'portal.Chatter',
+ xmlDependencies: ['/portal/static/src/xml/portal_chatter.xml'],
events: {
"click .o_portal_chatter_pager_btn": '_onClickPager',
},
- xmlDependencies: ['/portal/static/src/xml/portal_chatter.xml'],
- init: function(parent, options){
+ /**
+ * @constructor
+ */
+ init: function (parent, options) {
var self = this;
this.options = {};
this._super.apply(this, arguments);
// underscorize the camelcased option keys
- _.each(options, function(val, key) {
+ _.each(options, function (val, key) {
self.options[_.str.underscored(key)] = val;
});
// set default options
@@ -92,22 +96,16 @@ var PortalChatter = Widget.extend({
this.set('message_count', this.options['message_count']);
this.set('pager', {});
this.set('domain', this.options['domain']);
- this._current_page = this.options['pager_start'];
+ this._currentPage = this.options['pager_start'];
},
- willStart: function(){
- var self = this;
- // load qweb template and init data
+ /**
+ * @override
+ */
+ willStart: function () {
return $.when(
- rpc.query({
- route: '/mail/chatter_init',
- params: this._messageFetchPrepareParams()
- }),
this._super.apply(this, arguments),
- ).then(function(result){
- self.result = result;
- self.options = _.extend(self.options, self.result['options'] || {});
- return result;
- });
+ this._chatterInit()
+ );
},
/**
* @override
@@ -115,9 +113,9 @@ var PortalChatter = Widget.extend({
start: function () {
// bind events
this.on("change:messages", this, this._renderMessages);
- this.on("change:message_count", this, function(){
+ this.on("change:message_count", this, function () {
this._renderMessageCount();
- this.set('pager', this._pager(this._current_page));
+ this.set('pager', this._pager(this._currentPage));
});
this.on("change:pager", this, this._renderPager);
this.on("change:domain", this, this._onChangeDomain);
@@ -149,12 +147,12 @@ var PortalChatter = Widget.extend({
* @param {Array} domain
* @returns {Deferred}
*/
- messageFetch: function(domain){
+ messageFetch: function (domain) {
var self = this;
- return rpc.query({
+ return this._rpc({
route: '/mail/chatter_fetch',
- params: self._messageFetchPrepareParams()
- }).then(function(result){
+ params: self._messageFetchPrepareParams(),
+ }).then(function (result) {
self.set('messages', self.preprocessMessages(result['messages']));
self.set('message_count', result['message_count']);
});
@@ -165,8 +163,8 @@ var PortalChatter = Widget.extend({
* @param {Array<Object>}
* @returns {Array}
*/
- preprocessMessages: function(messages){
- _.each(messages, function(m){
+ preprocessMessages: function (messages) {
+ _.each(messages, function (m) {
m['author_avatar_url'] = _.str.sprintf('/web/image/%s/%s/author_avatar/50x50', 'mail.message', m.id);
m['published_date_str'] = _.str.sprintf(_t('Published on %s'), moment(time.str_to_datetime(m.date)).format('MMMM Do YYYY, h:mm:ss a'));
});
@@ -178,32 +176,47 @@ var PortalChatter = Widget.extend({
//--------------------------------------------------------------------------
/**
+ * @private
+ * @returns {Deferred}
+ */
+ _chatterInit: function () {
+ var self = this;
+ return this._rpc({
+ route: '/mail/chatter_init',
+ params: this._messageFetchPrepareParams()
+ }).then(function (result) {
+ self.result = result;
+ self.options = _.extend(self.options, self.result['options'] || {});
+ return result;
+ });
+ },
+ /**
* Change the current page by refreshing current domain
*
* @private
* @param {Number} page
* @param {Array} domain
*/
- _changeCurrentPage: function(page, domain){
- this._current_page = page;
+ _changeCurrentPage: function (page, domain) {
+ this._currentPage = page;
var d = domain ? domain : _.clone(this.get('domain'));
this.set('domain', d); // trigger fetch message
},
- _messageFetchPrepareParams: function(){
+ _messageFetchPrepareParams: function () {
var self = this;
var data = {
'res_model': this.options['res_model'],
'res_id': this.options['res_id'],
'limit': this.options['pager_step'],
- 'offset': (this._current_page-1) * this.options['pager_step'],
+ 'offset': (this._currentPage - 1) * this.options['pager_step'],
'allow_composer': this.options['allow_composer'],
};
// add token field to allow to post comment without being logged
- if(self.options['token']){
+ if (self.options['token']) {
data['token'] = self.options['token'];
}
// add domain
- if(this.get('domain')){
+ if (this.get('domain')) {
data['domain'] = this.get('domain');
}
return data;
@@ -215,34 +228,34 @@ var PortalChatter = Widget.extend({
* @param {Number} page
* @returns {Object}
*/
- _pager: function(page){
- var page = page || 1;
+ _pager: function (page) {
+ page = page || 1;
var total = this.get('message_count');
var scope = this.options['pager_scope'];
var step = this.options['pager_step'];
// Compute Pager
- var page_count = Math.ceil(parseFloat(total) / step);
+ var pageCount = Math.ceil(parseFloat(total) / step);
- var page = Math.max(1, Math.min(parseInt(page), page_count));
+ page = Math.max(1, Math.min(parseInt(page), pageCount));
scope -= 1;
- var pmin = Math.max(page - parseInt(Math.floor(scope/2)), 1);
- var pmax = Math.min(pmin + scope, page_count);
+ var pmin = Math.max(page - parseInt(Math.floor(scope / 2)), 1);
+ var pmax = Math.min(pmin + scope, pageCount);
- if(pmax - scope > 0){
+ if (pmax - scope > 0) {
pmin = pmax - scope;
- }else{
+ } else {
pmin = 1;
}
var pages = [];
- _.each(_.range(pmin, pmax+1), function(index){
+ _.each(_.range(pmin, pmax + 1), function (index) {
pages.push(index);
});
return {
- "page_count": page_count,
+ "page_count": pageCount,
"offset": (page - 1) * step,
"page": page,
"page_start": pmin,
@@ -252,13 +265,13 @@ var PortalChatter = Widget.extend({
"pages": pages
};
},
- _renderMessages: function(){
+ _renderMessages: function () {
this.$('.o_portal_chatter_messages').html(qweb.render("portal.chatter_messages", {widget: this}));
},
- _renderMessageCount: function(){
+ _renderMessageCount: function () {
this.$('.o_message_counter').replaceWith(qweb.render("portal.chatter_message_count", {widget: this}));
},
- _renderPager: function(){
+ _renderPager: function () {
this.$('.o_portal_chatter_pager').replaceWith(qweb.render("portal.pager", {widget: this}));
},
@@ -266,10 +279,10 @@ var PortalChatter = Widget.extend({
// Handlers
//--------------------------------------------------------------------------
- _onChangeDomain: function(){
+ _onChangeDomain: function () {
var self = this;
- this.messageFetch().then(function(){
- var p = self._current_page;
+ this.messageFetch().then(function () {
+ var p = self._currentPage;
self.set('pager', self._pager(p));
});
},
@@ -277,24 +290,29 @@ var PortalChatter = Widget.extend({
* @private
* @param {MouseEvent} event
*/
- _onClickPager: function(ev){
+ _onClickPager: function (ev) {
ev.preventDefault();
var page = $(ev.currentTarget).data('page');
this._changeCurrentPage(page);
},
});
-base.ready().then(function () {
- $('.o_portal_chatter').each(function (index) {
- var $elem = $(this);
- var mail_thread = new PortalChatter(null, $elem.data());
- mail_thread.appendTo($elem);
- });
+publicWidget.registry.portalChatter = publicWidget.Widget.extend({
+ selector: '.o_portal_chatter',
+
+ /**
+ * @override
+ */
+ start: function () {
+ var defs = [this._super.apply(this, arguments)];
+ var chatter = new PortalChatter(this, this.$el.data());
+ defs.push(chatter.appendTo(this.$el));
+ return $.when.apply($, defs);
+ },
});
return {
PortalComposer: PortalComposer,
PortalChatter: PortalChatter,
};
-
});
diff --git a/addons/portal/static/src/js/portal_sidebar.js b/addons/portal/static/src/js/portal_sidebar.js
index b0f2d3ed457..b565e27868b 100644
--- a/addons/portal/static/src/js/portal_sidebar.js
+++ b/addons/portal/static/src/js/portal_sidebar.js
@@ -1,21 +1,19 @@
odoo.define('portal.PortalSidebar', function (require) {
-"use strict";
+'use strict';
-var config = require('web.config');
var core = require('web.core');
-var Widget = require('web.Widget');
+var publicWidget = require('web.public.widget');
var time = require('web.time');
var _t = core._t;
-var PortalSidebar = Widget.extend({
+var PortalSidebar = publicWidget.Widget.extend({
/**
* @override
*/
start: function () {
- var self = this;
- this._super.apply(this, arguments);
this._setDelayLabel();
+ return this._super.apply(this, arguments);
},
//--------------------------------------------------------------------------
@@ -25,9 +23,10 @@ var PortalSidebar = Widget.extend({
/**
* Set the due/delay information according to the given date
* like : <span class="o_portal_sidebar_timeago" t-att-datetime="invoice.date_due"/>
+ *
* @private
*/
- _setDelayLabel : function () {
+ _setDelayLabel: function () {
var $sidebarTimeago = this.$el.find('.o_portal_sidebar_timeago');
_.each($sidebarTimeago, function (el) {
var dateTime = moment(time.auto_str_to_date($(el).attr('datetime'))),
@@ -35,7 +34,7 @@ var PortalSidebar = Widget.extend({
diff = dateTime.diff(today, 'days', true),
displayStr;
- if (diff === 0){
+ if (diff === 0) {
displayStr = _t('Due today');
} else if (diff > 0) {
displayStr = _.str.sprintf(_t('Due in %d days'), Math.abs(diff));
@@ -54,10 +53,10 @@ var PortalSidebar = Widget.extend({
// open a new window with pdf for print in Firefox (in other system: http://printjs.crabbly.com)
if ($.browser.mozilla) {
window.open(href, '_blank');
- return ;
+ return;
}
if (!this.printContent) {
- this.printContent = $('<iframe id="print_iframe_content" src="'+ href +'" style="display:none"></iframe>');
+ this.printContent = $('<iframe id="print_iframe_content" src="' + href + '" style="display:none"></iframe>');
this.$el.append(this.printContent);
this.printContent.on('load', function () {
$(this).get(0).contentWindow.print();
diff --git a/addons/portal/static/src/js/portal_signature.js b/addons/portal/static/src/js/portal_signature.js
index 60d999cfbf0..0174eeacdfe 100644
--- a/addons/portal/static/src/js/portal_signature.js
+++ b/addons/portal/static/src/js/portal_signature.js
@@ -1,195 +1,193 @@
odoo.define('portal.signature_form', function (require) {
- 'use strict';
+'use strict';
+
+var core = require('web.core');
+var publicWidget = require('web.public.widget');
+var NameAndSignature = require('web.name_and_signature').NameAndSignature;
+var qweb = core.qweb;
+
+var _t = core._t;
+
+/**
+ * This widget is a signature request form. It uses
+ * @see NameAndSignature for the input fields, adds a submit
+ * button, and handles the RPC to save the result.
+ */
+var SignatureForm = publicWidget.Widget.extend({
+ template: 'portal.portal_signature',
+ xmlDependencies: ['/portal/static/src/xml/portal_signature.xml'],
+ events: {
+ 'click .o_portal_sign_submit': 'async _onClickSignSubmit',
+ },
+ custom_events: {
+ 'signature_changed': '_onChangeSignature',
+ },
+
+ /**
+ * Overridden to allow options.
+ *
+ * @constructor
+ * @param {Widget} parent
+ * @param {Object} options
+ * @param {string} options.callUrl - make RPC to this url
+ * @param {string} [options.sendLabel='Accept & Sign'] - label of the
+ * send button
+ * @param {Object} [options.rpcParams={}] - params for the RPC
+ * @param {Object} [options.nameAndSignatureOptions={}] - options for
+ * @see NameAndSignature.init()
+ */
+ init: function (parent, options) {
+ this._super.apply(this, arguments);
- var core = require('web.core');
- var dom = require('web.dom');
- var NameAndSignature = require('web.name_and_signature').NameAndSignature;
- var qweb = core.qweb;
- var Widget = require('web.Widget');
+ this.csrf_token = odoo.csrf_token;
- var _t = core._t;
+ this.callUrl = options.callUrl || '';
+ this.rpcParams = options.rpcParams || {};
+ this.sendLabel = options.sendLabel || _t("Accept & Sign");
+ this.nameAndSignature = new NameAndSignature(this,
+ options.nameAndSignatureOptions || {});
+ },
/**
- * This widget is a signature request form. It uses
- * @see NameAndSignature for the input fields, adds a submit
- * button, and handles the RPC to save the result.
+ * Overridden to get the DOM elements
+ * and to insert the name and signature.
+ *
+ * @override
*/
- var SignatureForm = Widget.extend({
- template: 'portal.portal_signature',
- xmlDependencies: ['/portal/static/src/xml/portal_signature.xml'],
- events: {
- 'click .o_portal_sign_submit': '_onClickSignSubmit',
- },
- custom_events: {
- 'signature_changed': '_onChangeSignature',
- },
-
- /**
- * Overridden to allow options.
- *
- * @constructor
- * @param {Widget} parent
- * @param {Object} options
- * @param {string} options.callUrl - make RPC to this url
- * @param {string} [options.sendLabel='Accept & Sign'] - label of the
- * send button
- * @param {Object} [options.rpcParams={}] - params for the RPC
- * @param {Object} [options.nameAndSignatureOptions={}] - options for
- * @see NameAndSignature.init()
- */
- init: function (parent, options) {
- this._super.apply(this, arguments);
-
- this.csrf_token = odoo.csrf_token;
-
- this.callUrl = options.callUrl || '';
- this.rpcParams = options.rpcParams || {};
- this.sendLabel = options.sendLabel || _t("Accept & Sign");
-
- this.nameAndSignature = new NameAndSignature(this,
- options.nameAndSignatureOptions || {});
-
- // debounce on click to not make multiple RPC if clicking too fast
- this._onClickSignSubmit = dom.makeButtonHandler(this._onClickSignSubmit);
- },
- /**
- * Overridden to get the DOM elements
- * and to insert the name and signature.
- *
- * @override
- */
- start: function () {
- this.$confirm_btn = this.$('.o_portal_sign_submit');
- this.$controls = this.$('.o_portal_sign_controls');
- this.nameAndSignature.replace(this.$('.o_web_sign_name_and_signature'));
- return this._super.apply(this, arguments);
- },
-
- //----------------------------------------------------------------------
- // Public
- //----------------------------------------------------------------------
-
- /**
- * Focuses the name.
- *
- * @see NameAndSignature.focusName();
- */
- focusName: function () {
- this.nameAndSignature.focusName();
- },
- /**
- * Resets the signature.
- *
- * @see NameAndSignature.resetSignature();
- */
- resetSignature: function () {
- return this.nameAndSignature.resetSignature();
- },
-
- //----------------------------------------------------------------------
- // Handlers
- //----------------------------------------------------------------------
-
- /**
- * Handles click on the submit button.
- *
- * This will get the current name and signature and validate them.
- * If they are valid, they are sent to the server, and the reponse is
- * handled. If they are invalid, it will display the errors to the user.
- *
- * @private
- * @param {Event} ev
- * @returns {Deferred}
- */
- _onClickSignSubmit: function (ev) {
- var self = this;
- ev.preventDefault();
-
- if (!this.nameAndSignature.validateSignature()) {
- return;
- }
+ start: function () {
+ this.$confirm_btn = this.$('.o_portal_sign_submit');
+ this.$controls = this.$('.o_portal_sign_controls');
+ this.nameAndSignature.replace(this.$('.o_web_sign_name_and_signature'));
+ return this._super.apply(this, arguments);
+ },
- var name = this.nameAndSignature.getName();
- var signature = this.nameAndSignature.getSignatureImage()[1];
-
- return this._rpc({
- route: this.callUrl,
- params: _.extend(this.rpcParams, {
- 'name': name,
- 'signature': signature,
- }),
- }).then(function (data) {
- if (data.error) {
- self.$('.o_portal_sign_error_msg').remove();
- self.$controls.prepend(qweb.render('portal.portal_signature_error', {widget: data}));
- } else if (data.success) {
- var $success = qweb.render('portal.portal_signature_success', {widget: data});
- self.$el.empty().append($success);
- }
- if (data.force_refresh) {
- if (data.redirect_url) {
- window.location = data.redirect_url;
- } else {
- window.location.reload();
- }
- // no resolve if we reload the page
- return $.Deferred();
+ //----------------------------------------------------------------------
+ // Public
+ //----------------------------------------------------------------------
+
+ /**
+ * Focuses the name.
+ *
+ * @see NameAndSignature.focusName();
+ */
+ focusName: function () {
+ this.nameAndSignature.focusName();
+ },
+ /**
+ * Resets the signature.
+ *
+ * @see NameAndSignature.resetSignature();
+ */
+ resetSignature: function () {
+ return this.nameAndSignature.resetSignature();
+ },
+
+ //----------------------------------------------------------------------
+ // Handlers
+ //----------------------------------------------------------------------
+
+ /**
+ * Handles click on the submit button.
+ *
+ * This will get the current name and signature and validate them.
+ * If they are valid, they are sent to the server, and the reponse is
+ * handled. If they are invalid, it will display the errors to the user.
+ *
+ * @private
+ * @param {Event} ev
+ * @returns {Deferred}
+ */
+ _onClickSignSubmit: function (ev) {
+ var self = this;
+ ev.preventDefault();
+
+ if (!this.nameAndSignature.validateSignature()) {
+ return;
+ }
+
+ var name = this.nameAndSignature.getName();
+ var signature = this.nameAndSignature.getSignatureImage()[1];
+
+ return this._rpc({
+ route: this.callUrl,
+ params: _.extend(this.rpcParams, {
+ 'name': name,
+ 'signature': signature,
+ }),
+ }).then(function (data) {
+ if (data.error) {
+ self.$('.o_portal_sign_error_msg').remove();
+ self.$controls.prepend(qweb.render('portal.portal_signature_error', {widget: data}));
+ } else if (data.success) {
+ var $success = qweb.render('portal.portal_signature_success', {widget: data});
+ self.$el.empty().append($success);
+ }
+ if (data.force_refresh) {
+ if (data.redirect_url) {
+ window.location = data.redirect_url;
+ } else {
+ window.location.reload();
}
- });
- },
- /**
- * Toggles the submit button depending on the signature state.
- *
- * @private
- */
- _onChangeSignature: function () {
- var isEmpty = this.nameAndSignature.isSignatureEmpty();
- this.$confirm_btn.prop('disabled', isEmpty);
- },
- });
-
- return {
- SignatureForm: SignatureForm,
- };
+ // no resolve if we reload the page
+ return $.Deferred();
+ }
+ });
+ },
+ /**
+ * Toggles the submit button depending on the signature state.
+ *
+ * @private
+ */
+ _onChangeSignature: function () {
+ var isEmpty = this.nameAndSignature.isSignatureEmpty();
+ this.$confirm_btn.prop('disabled', isEmpty);
+ },
});
-odoo.define('portal.signature_form_init', function (require) {
-'use strict';
+publicWidget.registry.SignatureForm = publicWidget.Widget.extend({
+ selector: '.o_portal_signature_form',
-var SignatureForm = require('portal.signature_form').SignatureForm;
-var rootWidget = require('root.widget');
-require('web.dom_ready');
-
-$('.o_portal_signature_form').each(function () {
- var hasBeenReset = false;
- var $elem = $(this);
-
- var callUrl = $elem.data('call-url');
- var nameAndSignatureOptions = {
- defaultName: $elem.data('default-name'),
- mode: $elem.data('mode'),
- displaySignatureRatio: $elem.data('signature-ratio'),
- signatureType: $elem.data('signature-type'),
- };
- var sendLabel = $elem.data('send-label');
-
- var form = new SignatureForm(rootWidget, {
- callUrl: callUrl,
- nameAndSignatureOptions: nameAndSignatureOptions,
- sendLabel: sendLabel,
- });
- form.appendTo($elem);
- // Correctly set up the signature area if it is inside a modal
- $('.o_portal_signature_form').parents('.modal').on('shown.bs.modal', function (ev) {
- if (!hasBeenReset) {
- // Reset it only the first time it is open to get correct
- // size. After we want to keep its content on reopen.
- hasBeenReset = true;
- form.resetSignature();
- } else {
- form.focusName();
- }
- });
+ /**
+ * @private
+ */
+ start: function () {
+ var hasBeenReset = false;
+
+ var callUrl = this.$el.data('call-url');
+ var nameAndSignatureOptions = {
+ defaultName: this.$el.data('default-name'),
+ mode: this.$el.data('mode'),
+ displaySignatureRatio: this.$el.data('signature-ratio'),
+ signatureType: this.$el.data('signature-type'),
+ };
+ var sendLabel = this.$el.data('send-label');
+
+ var form = new SignatureForm(this, {
+ callUrl: callUrl,
+ nameAndSignatureOptions: nameAndSignatureOptions,
+ sendLabel: sendLabel,
+ });
+
+ // Correctly set up the signature area if it is inside a modal
+ this.$el.closest('.modal').on('shown.bs.modal', function (ev) {
+ if (!hasBeenReset) {
+ // Reset it only the first time it is open to get correct
+ // size. After we want to keep its content on reopen.
+ hasBeenReset = true;
+ form.resetSignature();
+ } else {
+ form.focusName();
+ }
+ });
+
+ return $.when(
+ this._super.apply(this, arguments),
+ form.appendTo(this.$el)
+ );
+ },
});
+return {
+ SignatureForm: SignatureForm,
+};
});
diff --git a/addons/project/static/src/js/portal_rating.js b/addons/project/static/src/js/portal_rating.js
index 12740b9bbba..e1b51d9edc1 100644
--- a/addons/project/static/src/js/portal_rating.js
+++ b/addons/project/static/src/js/portal_rating.js
@@ -1,27 +1,32 @@
odoo.define('website_rating_project.rating', function (require) {
'use strict';
- var time = require('web.time');
- require('web.dom_ready');
+var time = require('web.time');
+var publicWidget = require('web.public.widget');
- if(!$('.o_portal_project_rating').length) {
- return $.Deferred().reject("DOM doesn't contain '.o_portal_project_rating'");
- }
+publicWidget.registry.ProjectRatingImage = publicWidget.Widget.extend({
+ selector: '.o_portal_project_rating .o_rating_image',
- /**
- * Rating popover with some informations
- */
- $('.o_portal_project_rating .o_rating_image').popover({
- placement: 'bottom',
- trigger: 'hover',
- html: 'true',
- content: function () {
- var id = $(this).data('id');
- var rating_date = $(this).data('rating-date');
- var base_date = time.auto_str_to_date(rating_date);
- var duration = moment(base_date).fromNow();
- $("#rating_"+ id).find(".rating_timeduration").text(duration);
- return $("#rating_"+ id).html();
- }
- });
+ /**
+ * @override
+ */
+ start: function () {
+ this.$el.popover({
+ placement: 'bottom',
+ trigger: 'hover',
+ html: 'true',
+ content: function () {
+ var $elem = $(this);
+ var id = $elem.data('id');
+ var ratingDate = $elem.data('rating-date');
+ var baseDate = time.auto_str_to_date(ratingDate);
+ var duration = moment(baseDate).fromNow();
+ var $rating = $('#rating_' + id);
+ $rating.find('.rating_timeduration').text(duration);
+ return $rating.html();
+ },
+ });
+ return this._super.apply(this, arguments);
+ },
+});
});
diff --git a/addons/sale/static/src/js/sale_portal_sidebar.js b/addons/sale/static/src/js/sale_portal_sidebar.js
index 162a4ec5b2d..f9ba54ad661 100644
--- a/addons/sale/static/src/js/sale_portal_sidebar.js
+++ b/addons/sale/static/src/js/sale_portal_sidebar.js
@@ -1,43 +1,25 @@
-odoo.define('sale.SalePortalSidebar.instance', function (require) {
-"use strict";
-
-require('web.dom_ready');
-var SalePortalSidebar = require('sale.SalePortalSidebar');
-
-if (!$('.o_portal_sale_sidebar').length) {
- return $.Deferred().reject("DOM doesn't contain '.o_portal_sale_sidebar'");
-}
-
-var $spyWatch = $('body[data-target=".navspy"]'),
- sale_portal_sidebar = new SalePortalSidebar($spyWatch);
-
-return sale_portal_sidebar.attachTo($('.o_portal_sale_sidebar')).then(function () {
- return sale_portal_sidebar;
-});
-});
-
-//==============================================================================
-
odoo.define('sale.SalePortalSidebar', function (require) {
-"use strict";
+'use strict';
+var publicWidget = require('web.public.widget');
var PortalSidebar = require('portal.PortalSidebar');
-var SalePortalSidebar = PortalSidebar.extend({
+publicWidget.registry.SalePortalSidebar = PortalSidebar.extend({
+ selector: '.o_portal_sale_sidebar',
+
/**
- * @override
- * @param {Object} $watched_selector
+ * @constructor
*/
- init: function ($watched_selector) {
+ init: function (parent, options) {
this._super.apply(this, arguments);
this.authorizedTextTag = ['em', 'b', 'i', 'u'];
- this.spyWatched = $watched_selector;
+ this.spyWatched = $('body[data-target=".navspy"]');
},
/**
* @override
*/
start: function () {
- this._super.apply(this, arguments);
+ var def = this._super.apply(this, arguments);
var $spyWatcheElement = this.$el.find('[data-id="portal_sidebar"]');
this._setElementId($spyWatcheElement);
// Nav Menu ScrollSpy
@@ -47,6 +29,7 @@ var SalePortalSidebar = PortalSidebar.extend({
this.$('#o_sale_portal_paynow').trigger('click');
$.bbq.removeState('allow_payment');
}
+ return def;
},
//--------------------------------------------------------------------------
@@ -129,6 +112,4 @@ var SalePortalSidebar = PortalSidebar.extend({
return rawText.join(' ');
},
});
-
-return SalePortalSidebar;
});
diff --git a/addons/sale_management/static/src/js/sale_management.js b/addons/sale_management/static/src/js/sale_management.js
index 77806630166..87d2c94c5d8 100644
--- a/addons/sale_management/static/src/js/sale_management.js
+++ b/addons/sale_management/static/src/js/sale_management.js
@@ -1,51 +1,47 @@
odoo.define('sale_management.sale_management', function (require) {
'use strict';
-require('web.dom_ready');
-var ajax = require('web.ajax');
-var Widget = require('web.Widget');
+var publicWidget = require('web.public.widget');
-if (!$('.o_portal_sale_sidebar').length) {
- return $.Deferred().reject("DOM doesn't contain '.o_portal_sale_sidebar'");
-}
+publicWidget.registry.SaleUpdateLineButton = publicWidget.Widget.extend({
+ selector: '.o_portal_sale_sidebar a.js_update_line_json',
+ events: {
+ 'click': '_onClick',
+ },
- // Add to SO button
- var UpdateLineButton = Widget.extend({
- events: {
- 'click' : 'onClick',
- },
- onClick: function (ev) {
- ev.preventDefault();
- var self = this;
- var href = this.$el.attr("href");
- var order_id = href.match(/my\/orders\/([0-9]+)/);
- var line_id = href.match(/update_line\/([0-9]+)/);
- var params = {
- 'line_id': line_id[1],
- 'remove': self.$el.is('[href*="remove"]'),
- 'unlink': self.$el.is('[href*="unlink"]'),
- };
- var token = href.match(/token=(.*)/);
- if (token) {
- params.access_token = token;
- }
- var url = "/my/orders/" + parseInt(order_id[1]) + "/update_line";
- ajax.jsonRpc(url, 'call', params).then(function (data) {
- if (!data) {
- window.location.reload();
- }
- self.$el.parents('.input-group:first').find('.js_quantity').val(data[0]);
- $('[data-id="total_amount"]>span').html(data[1]);
- });
- return false;
- },
- });
-
- var update_button_list = [];
- $('a.js_update_line_json').each(function (index) {
- var button = new UpdateLineButton();
- button.setElement($(this)).start();
- update_button_list.push(button);
- });
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+ /**
+ * @private
+ */
+ _onClick: function (ev) {
+ ev.preventDefault();
+ var self = this;
+ var href = this.$el.attr("href");
+ var orderID = href.match(/my\/orders\/([0-9]+)/);
+ var lineID = href.match(/update_line\/([0-9]+)/);
+ var params = {
+ 'line_id': lineID[1],
+ 'remove': self.$el.is('[href*="remove"]'),
+ 'unlink': self.$el.is('[href*="unlink"]'),
+ };
+ var token = href.match(/token=(.*)/);
+ if (token) {
+ params['access_token'] = token;
+ }
+ var url = "/my/orders/" + parseInt(orderID[1]) + "/update_line";
+ this._rpc({
+ route: url,
+ params: params,
+ }).then(function (data) {
+ if (!data) {
+ window.location.reload();
+ }
+ self.$el.closest('.input-group').find('.js_quantity').val(data[0]);
+ $('[data-id="total_amount"] > span').html(data[1]);
+ });
+ },
+});
});
diff --git a/addons/web_unsplash/static/src/js/unsplash_beacon.js b/addons/web_unsplash/static/src/js/unsplash_beacon.js
index eb19383b93f..c15ff027faf 100644
--- a/addons/web_unsplash/static/src/js/unsplash_beacon.js
+++ b/addons/web_unsplash/static/src/js/unsplash_beacon.js
@@ -1,24 +1,34 @@
odoo.define('web_unsplash.beacon', function (require) {
'use strict';
-require('web.dom_ready');
-var ajax = require('web.ajax');
+var publicWidget = require('web.public.widget');
-var unsplash_images = [];
-_.each($('img[src*="/unsplash/"]'), function (img, index) {
- // get image id from URL (`http://www.domain.com:1234/unsplash/xYdf5feoI/lion.jpg` -> `xYdf5feoI`)
- unsplash_images.push(img.src.split('/unsplash/')[1].split('/')[0]);
-});
-if (unsplash_images.length) {
- ajax.jsonRpc('/web_unsplash/get_app_id', 'call').then(function (appID) {
- if (appID) {
- var unsplash_view_url = 'https://views.unsplash.com/v';
- $.get(unsplash_view_url, {
- photo_id: unsplash_images.join(','),
- app_id: appID,
+publicWidget.registry.UnsplashBeacon = publicWidget.Widget.extend({
+ // /!\ To adapt the day the beacon makes sense for backend customizations
+ selector: '#wrapwrap',
+
+ /**
+ * @override
+ */
+ start: function () {
+ var unsplashImages = _.map(this.$('img[src*="/unsplash/"]'), function (img) {
+ // get image id from URL (`http://www.domain.com:1234/unsplash/xYdf5feoI/lion.jpg` -> `xYdf5feoI`)
+ return img.src.split('/unsplash/')[1].split('/')[0];
+ });
+ if (unsplashImages.length) {
+ this._rpc({
+ route: '/web_unsplash/get_app_id',
+ }).then(function (appID) {
+ if (!appID) {
+ return;
+ }
+ $.get('https://views.unsplash.com/v', {
+ 'photo_id': unsplashImages.join(','),
+ 'app_id': appID,
+ });
});
}
- });
-}
-
+ return this._super.apply(this, arguments);
+ },
+});
});
diff --git a/addons/website/static/src/js/content/website_root.js b/addons/website/static/src/js/content/website_root.js
index ff398b2ff2d..ce4ebfec435 100644
--- a/addons/website/static/src/js/content/website_root.js
+++ b/addons/website/static/src/js/content/website_root.js
@@ -16,6 +16,7 @@ var WebsiteRoot = publicRootData.PublicRoot.extend({
'click .js_publish_management .js_publish_btn': '_onPublishBtnClick',
'click .js_multi_website_switch': '_onWebsiteSwitch',
'click .js_multi_company_switch': '_onCompanySwitch',
+ 'shown.bs.modal': '_onModalShown',
}),
custom_events: _.extend({}, publicRootData.PublicRoot.prototype.custom_events || {}, {
'ready_to_clean_for_save': '_onAnimationStopDemand',
@@ -167,6 +168,13 @@ var WebsiteRoot = publicRootData.PublicRoot.extend({
window.location.reload(true);
});
},
+ /**
+ * @private
+ * @param {Event} ev
+ */
+ _onModalShown: function (ev) {
+ $(ev.target).addClass('modal_shown');
+ },
});
return {
diff --git a/addons/website/static/src/js/website.js b/addons/website/static/src/js/website.js
deleted file mode 100644
index 66b410ee3c0..00000000000
--- a/addons/website/static/src/js/website.js
+++ /dev/null
@@ -1,9 +0,0 @@
-odoo.define('website.website_modal', function (require) {
-'use strict';
-
- require('web.dom_ready');
-
- $('body').on('shown.bs.modal', function (e) {
- $(e.target).addClass('modal_shown');
- });
-});
diff --git a/addons/website/views/website_templates.xml b/addons/website/views/website_templates.xml
index 6bf1c8614c1..5317f490ea8 100644
--- a/addons/website/views/website_templates.xml
+++ b/addons/website/views/website_templates.xml
@@ -63,7 +63,6 @@
</xpath>
<xpath expr="//script[last()]" position="after">
<script type="text/javascript" src="/website/static/src/js/utils.js"/>
- <script type="text/javascript" src="/website/static/src/js/website.js"/>
<script type="text/javascript" src="/website/static/src/js/content/website_root.js"/>
<script type="text/javascript" src="/website/static/src/js/content/compatibility.js"/>
diff --git a/addons/website_mail/static/src/js/website_mail.js b/addons/website_mail/static/src/js/website_mail.js
index 711df6ebbae..473ed4b4128 100644
--- a/addons/website_mail/static/src/js/website_mail.js
+++ b/addons/website_mail/static/src/js/website_mail.js
@@ -1,20 +1,13 @@
-odoo.define('website_mail.thread', function(require) {
+odoo.define('website_mail.thread', function (require) {
'use strict';
-var ajax = require('web.ajax');
-var core = require('web.core');
-
-var qweb = core.qweb;
-
-var PortalChatter = require('portal.chatter').PortalChatter;
+var portalChatter = require('portal.chatter');
/**
* Extends Frontend Chatter to handle rating
*/
-PortalChatter.include({
- _loadTemplates: function(){
- return $.when(this._super(), ajax.loadXML('/website_mail/static/src/xml/website_mail.xml', qweb));
- },
+portalChatter.PortalChatter.include({
+ xmlDependencies: (portalChatter.PortalChatter.prototype.xmlDependencies || [])
+ .concat(['/website_mail/static/src/xml/website_mail.xml']),
});
-
});
diff --git a/addons/website_rating/static/src/js/website_mail.js b/addons/website_rating/static/src/js/website_mail.js
index 6fd9a305e95..15b9b4ce503 100644
--- a/addons/website_rating/static/src/js/website_mail.js
+++ b/addons/website_rating/static/src/js/website_mail.js
@@ -1,335 +1,353 @@
-odoo.define('website_rating.thread', function(require) {
- 'use strict';
-
- var base = require('web_editor.base');
- var ajax = require('web.ajax');
- var core = require('web.core');
- var Widget = require('web.Widget');
- var rootWidget = require('web_editor.root_widget');
-
- var session = require('web.session');
-
- var qweb = core.qweb;
- var _t = core._t;
-
- var PortalComposer = require('portal.chatter').PortalComposer;
- var PortalChatter = require('portal.chatter').PortalChatter;
-
- var STAR_RATING_RATIO = 2; // conversion factor from the star (1-5) to the db rating range (1-10)
+odoo.define('website_rating.thread', function (require) {
+'use strict';
+
+var core = require('web.core');
+var publicWidget = require('web.public.widget');
+var session = require('web.session');
+var portalChatter = require('portal.chatter');
+
+var _t = core._t;
+
+var PortalComposer = portalChatter.PortalComposer;
+var PortalChatter = portalChatter.PortalChatter;
+
+var STAR_RATING_RATIO = 2; // conversion factor from the star (1-5) to the db rating range (1-10)
+
+/**
+ * PortalComposer
+ *
+ * Extends Frontend Composer to handle rating submission
+ */
+PortalComposer.include({
+ events: _.extend({}, PortalComposer.prototype.events, {
+ "mousemove .stars i": "_onMoveStar",
+ "mouseleave .stars i": "_onMoveOutStar",
+ "click .stars": "_onClickStar",
+ "mouseleave .stars": "_onMouseleaveStar",
+ }),
/**
- * PortalComposer
- *
- * Extends Frontend Composer to handle rating submission
+ * @constructor
+ */
+ init: function (parent, options) {
+ this._super.apply(this, arguments);
+
+ // apply ratio to default rating value
+ if (options.default_rating_value) {
+ options.default_rating_value = parseFloat(options.default_rating_value) / STAR_RATING_RATIO;
+ }
+
+ // default options
+ this.options = _.defaults(this.options, {
+ 'default_message': false,
+ 'default_message_id': false,
+ 'default_rating_value': false,
+ 'force_submit_url': false,
+ });
+ // star input widget
+ this.labels = {
+ '0': "",
+ '1': _t("I hate it"),
+ '2': _t("I don't like it"),
+ '3': _t("It's okay"),
+ '4': _t("I like it"),
+ '5': _t("I love it"),
+ };
+ this.user_click = false; // user has click or not
+ this.set("star_value", this.options.default_rating_value);
+ this.on("change:star_value", this, this._onChangeStarValue);
+ },
+ /**
+ * @override
*/
- PortalComposer.include({
- events: _.extend({}, PortalComposer.prototype.events, {
- "mousemove .stars i" : "_onMoveStar",
- "mouseleave .stars i" : "_onMoveOutStar",
- "click .stars" : "_onClickStar",
- "mouseleave .stars" : "_onMouseleaveStar",
- }),
+ start: function () {
+ var self = this;
+ return this._super.apply(this, arguments).then(function () {
+ // rating stars
+ self.$input = self.$('input[name="rating_value"]');
+ self.$star_list = self.$('.stars').find('i');
+ self.set("star_value", self.options.default_rating_value); // set the default value to trigger the display of star widget
+ });
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
- init: function(parent, options){
- this._super.apply(this, arguments);
+ /**
+ * @private
+ */
+ _onClickStar: function () {
+ this.user_click = true;
+ this.$input.val(this.get("star_value") * STAR_RATING_RATIO);
+ },
+ /**
+ * @private
+ */
+ _onChangeStarValue: function () {
+ var val = this.get("star_value");
+ var index = Math.floor(val);
+ var decimal = val - index;
+ // reset the stars
+ this.$star_list.removeClass('fa-star fa-star-half-o').addClass('fa-star-o');
+
+ this.$('.stars').find("i:lt(" + index + ")").removeClass('fa-star-o fa-star-half-o').addClass('fa-star');
+ if (decimal) {
+ this.$('.stars').find("i:eq(" + index + ")").removeClass('fa-star-o fa-star fa-star-half-o').addClass('fa-star-half-o');
+ }
+ this.$('.rate_text .badge').text(this.labels[index]);
+ },
+ /**
+ * @private
+ */
+ _onMouseleaveStar: function () {
+ this.$('.rate_text').hide();
+ },
+ /**
+ * @private
+ * @param {MouseEvent} ev
+ */
+ _onMoveStar: function (ev) {
+ var index = this.$('.stars i').index(ev.currentTarget);
+ this.$('.rate_text').show();
+ this.set("star_value", index + 1);
+ },
+ /**
+ * @private
+ */
+ _onMoveOutStar: function () {
+ if (!this.user_click) {
+ this.set("star_value", parseInt(this.$input.val()));
+ }
+ this.user_click = false;
+ },
+});
- // apply ratio to default rating value
- if (options.default_rating_value) {
- options.default_rating_value = parseFloat(options.default_rating_value) / STAR_RATING_RATIO;
- }
+/**
+ * PortalChatter
+ *
+ * Extends Frontend Chatter to handle rating
+ */
+PortalChatter.include({
+ events: _.extend({}, PortalChatter.prototype.events, {
+ "click .o_website_rating_select": "_onClickStarDomain",
+ "click .o_website_rating_select_text": "_onClickStarDomainReset",
+ }),
+ xmlDependencies: (PortalChatter.prototype.xmlDependencies || [])
+ .concat([
+ '/website_rating/static/src/xml/website_mail.xml',
+ '/website_rating/static/src/xml/portal_chatter.xml'
+ ]),
- // default options
+ /**
+ * @constructor
+ */
+ init: function (parent, options) {
+ this._super.apply(this, arguments);
+ // options
+ if (!_.contains(this.options, 'display_rating')) {
this.options = _.defaults(this.options, {
- 'default_message': false,
- 'default_message_id': false,
- 'default_rating_value': false,
- 'force_submit_url': false,
- });
- // star input widget
- this.labels = {
- '0': "",
- '1': _t("I hate it"),
- '2': _t("I don't like it"),
- '3': _t("It's okay"),
- '4': _t("I like it"),
- '5': _t("I love it"),
- };
- this.user_click = false; // user has click or not
- this.set("star_value", this.options.default_rating_value);
- this.on("change:star_value", this, this._onChangeStarValue);
- },
- start: function(){
- var self = this;
- return this._super.apply(this, arguments).then(function(){
- // rating stars
- self.$input = self.$('input[name="rating_value"]');
- self.$star_list = self.$('.stars').find('i');
- self.set("star_value", self.options.default_rating_value); // set the default value to trigger the display of star widget
+ 'display_rating': false,
+ 'rating_default_value': 0.0,
});
- },
-
- //--------------------------------------------------------------------------
- // Handlers
- //--------------------------------------------------------------------------
-
- /**
- * @private
- * @param {MouseEvent} event
- */
- _onClickStar: function(e){
- this.user_click = true;
- this.$input.val(this.get("star_value") * STAR_RATING_RATIO);
- },
- /**
- * @private
- */
- _onChangeStarValue: function(){
- var val = this.get("star_value");
- var index = Math.floor(val);
- var decimal = val - index;
- // reset the stars
- this.$star_list.removeClass('fa-star fa-star-half-o').addClass('fa-star-o');
-
- this.$('.stars').find("i:lt("+index+")").removeClass('fa-star-o fa-star-half-o').addClass('fa-star');
- if(decimal){
- this.$('.stars').find("i:eq("+(index)+")").removeClass('fa-star-o fa-star fa-star-half-o').addClass('fa-star-half-o');
- }
- this.$('.rate_text .badge').text(this.labels[index]);
- },
- _onMouseleaveStar: function(e){
- this.$('.rate_text').hide();
- },
- /**
- * @private
- * @param {MouseEvent} event
- */
- _onMoveStar: function(e){
- var index = this.$('.stars i').index(e.currentTarget);
- this.$('.rate_text').show();
- this.set("star_value", index+1);
- },
- /**
- * @private
- */
- _onMoveOutStar: function(){
- if(!this.user_click){
- this.set("star_value", parseInt(this.$input.val()));
- }
- this.user_click = false;
- },
- });
+ }
+ // rating card
+ this.set('rating_card_values', {});
+ this.set('rating_value', false);
+ this.on("change:rating_value", this, this._onChangeRatingDomain);
+ },
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
/**
- * PortalChatter
+ * Update the messages format
*
- * Extends Frontend Chatter to handle rating
+ * @param {Array<Object>} messages
+ * @returns {Array}
*/
- PortalChatter.include({
- events: _.extend({}, PortalChatter.prototype.events, {
- "click .o_website_rating_select": "_onClickStarDomain",
- "click .o_website_rating_select_text": "_onClickStarDomainReset",
- }),
- xmlDependencies: (PortalChatter.prototype.xmlDependencies || []).concat(['/website_rating/static/src/xml/website_mail.xml', '/website_rating/static/src/xml/portal_chatter.xml']),
+ preprocessMessages: function (messages) {
+ var self = this;
+ messages = this._super.apply(this, arguments);
+ if (this.options['display_rating']) {
+ _.each(messages, function (m) {
+ m['rating_value'] = self.roundToHalf(m['rating_value'] / STAR_RATING_RATIO);
+ });
+ }
+ return messages;
+ },
+ /**
+ * Round the given value with a precision of 0.5.
+ *
+ * Examples:
+ * - 1.2 --> 1.0
+ * - 1.7 --> 1.5
+ * - 1.9 --> 2.0
+ *
+ * @param {Number} value
+ * @returns Number
+ **/
+ roundToHalf: function (value) {
+ var converted = parseFloat(value); // Make sure we have a number
+ var decimal = (converted - parseInt(converted, 10));
+ decimal = Math.round(decimal * 10);
+ if (decimal === 5) {
+ return (parseInt(converted, 10) + 0.5);
+ }
+ if ((decimal < 3) || (decimal > 7)) {
+ return Math.round(converted);
+ } else {
+ return (parseInt(converted, 10) + 0.5);
+ }
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
- init: function(parent, options){
- this._super.apply(this, arguments);
- // options
- if(!_.contains(this.options, 'display_rating')){
- this.options = _.defaults(this.options, {
- 'display_rating': false,
- 'rating_default_value': 0.0,
- });
+ /**
+ * @override
+ */
+ _chatterInit: function () {
+ var self = this;
+ return this._super.apply(this, arguments).then(function (result) {
+ if (!result['rating_stats']) {
+ return;
}
- // rating card
- this.set('rating_card_values', {});
- this.set('rating_value', false);
- this.on("change:rating_value", this, this._onChangeRatingDomain);
- },
- willStart: function(){
- var self = this;
- return this._super.apply(this, arguments).then(function(result){
- // rating card
- if(result['rating_stats']){
- var rating_data = {
- 'avg': Math.round(result['rating_stats']['avg'] / STAR_RATING_RATIO * 100) / 100,
- 'percent': [],
- };
- _.each(_.keys(result['rating_stats']['percent']), function(rating){
-
- if (rating % 2 == 0) { // is even number
- rating_data['percent'].push({
- 'num': rating / STAR_RATING_RATIO,
- 'percent': result['rating_stats']['percent'][rating],
- });
- }
+ var ratingData = {
+ 'avg': Math.round(result['rating_stats']['avg'] / STAR_RATING_RATIO * 100) / 100,
+ 'percent': [],
+ };
+ _.each(_.keys(result['rating_stats']['percent']), function (rating) {
+ if (rating % 2 === 0) {
+ ratingData['percent'].push({
+ 'num': rating / STAR_RATING_RATIO,
+ 'percent': result['rating_stats']['percent'][rating],
});
- self.set('rating_card_values', rating_data);
}
});
- },
-
- //--------------------------------------------------------------------------
- // Public
- //--------------------------------------------------------------------------
-
- /**
- * Update the messages format
- *
- * @param {Array<Object>} messages
- * @returns {Array}
- */
- preprocessMessages: function(messages){
- var self = this;
- var messages = this._super.apply(this, arguments);
- if(this.options['display_rating']){
- _.each(messages, function(m){
- m['rating_value'] = self.round_to_half(m['rating_value'] / STAR_RATING_RATIO);
- });
- }
- return messages;
- },
- /**
- * Round the given value with a precision of 0.5.
- *
- * Examples:
- * - 1.2 --> 1.0
- * - 1.7 --> 1.5
- * - 1.9 --> 2.0
- *
- * @param {Number} value
- * @returns Number
- **/
- round_to_half: function(value) {
- var converted = parseFloat(value); // Make sure we have a number
- var decimal = (converted - parseInt(converted, 10));
- decimal = Math.round(decimal * 10);
- if(decimal === 5){
- return (parseInt(converted, 10)+0.5);
- }
- if((decimal < 3) || (decimal > 7)){
- return Math.round(converted);
- }else{
- return (parseInt(converted, 10)+0.5);
- }
- },
-
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
-
- _messageFetchPrepareParams: function(){
- var params = this._super.apply(this, arguments);
- if(this.options['display_rating']){
- params['rating_include'] = true;
- }
- return params;
- },
-
- //--------------------------------------------------------------------------
- // Handlers
- //--------------------------------------------------------------------------
+ self.set('rating_card_values', ratingData);
+ });
+ },
+ /**
+ * @override
+ */
+ _messageFetchPrepareParams: function () {
+ var params = this._super.apply(this, arguments);
+ if (this.options['display_rating']) {
+ params['rating_include'] = true;
+ }
+ return params;
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
- /**
- * @private
- * @param {MouseEvent} event
- */
- _onClickStarDomain: function(e){
- var $tr = this.$(e.currentTarget);
- var num = $tr.data('star');
- if($tr.css('opacity') == 1){
- this.set('rating_value', num);
- this.$('.o_website_rating_select').css({
- 'opacity': 0.5,
- });
- this.$('.o_website_rating_select_text[data-star="'+num+'"]').css({
- 'visibility': 'visible',
- 'opacity': 1,
- });
- this.$('.o_website_rating_select[data-star="'+num+'"]').css({
- 'opacity': 1,
- });
- }
- },
- /**
- * @private
- * @param {MouseEvent} event
- */
- _onClickStarDomainReset: function(e){
- e.stopPropagation();
- e.preventDefault();
- this.set('rating_value', false);
- this.$('.o_website_rating_select_text').css('visibility', 'hidden');
+ /**
+ * @private
+ * @param {MouseEvent} event
+ */
+ _onClickStarDomain: function (e) {
+ var $tr = this.$(e.currentTarget);
+ var num = $tr.data('star');
+ if ($tr.css('opacity') === '1') {
+ this.set('rating_value', num);
this.$('.o_website_rating_select').css({
+ 'opacity': 0.5,
+ });
+ this.$('.o_website_rating_select_text[data-star="' + num + '"]').css({
+ 'visibility': 'visible',
'opacity': 1,
});
- },
- /**
- * @private
- */
- _onChangeRatingDomain: function(){
- var domain = [];
- if(this.get('rating_value')){
- domain = [['rating_value', '=', this.get('rating_value') * STAR_RATING_RATIO]];
- }
- this._changeCurrentPage(1, domain);
- },
- });
-
-
- /**
- * RatingPopupComposer
- *
- * Display the rating average with a static star widget, and open
- * a popup with the portal composer when clicking on it.
- **/
- var RatingPopupComposer = Widget.extend({
- template: 'website_rating.PopupComposer',
- xmlDependencies: [
- '/portal/static/src/xml/portal_chatter.xml',
- '/website_rating/static/src/xml/website_mail.xml',
- '/website_rating/static/src/xml/portal_chatter.xml',
- ],
-
- init: function(parent, options){
- this._super.apply(this, arguments);
- this.rating_avg = Math.round(options['ratingAvg'] / STAR_RATING_RATIO * 100) / 100 || 0.0;
- this.rating_total = options['ratingTotal'] || 0.0;
-
- this.options = _.defaults({}, options, {
- 'token': false,
- 'res_model': false,
- 'res_id': false,
- 'pid': 0,
- 'display_composer': !session.is_website_user,
- 'display_rating': true,
- 'csrf_token': odoo.csrf_token,
- 'user_id': session.user_id,
+ this.$('.o_website_rating_select[data-star="' + num + '"]').css({
+ 'opacity': 1,
});
- },
- /**
- * @override
- */
- start: function () {
- var defs = [];
- defs.push(this._super.apply(this, arguments));
-
- // instanciate and insert composer widget
- this._composer = new PortalComposer(this, this.options);
- defs.push(this._composer.replace(this.$('.o_portal_chatter_composer')));
+ }
+ },
+ /**
+ * @private
+ * @param {MouseEvent} event
+ */
+ _onClickStarDomainReset: function (e) {
+ e.stopPropagation();
+ e.preventDefault();
+ this.set('rating_value', false);
+ this.$('.o_website_rating_select_text').css('visibility', 'hidden');
+ this.$('.o_website_rating_select').css({
+ 'opacity': 1,
+ });
+ },
+ /**
+ * @private
+ */
+ _onChangeRatingDomain: function () {
+ var domain = [];
+ if (this.get('rating_value')) {
+ domain = [['rating_value', '=', this.get('rating_value') * STAR_RATING_RATIO]];
+ }
+ this._changeCurrentPage(1, domain);
+ },
+});
- return $.when.apply($, defs);
- },
- });
+/**
+ * RatingPopupComposer
+ *
+ * Display the rating average with a static star widget, and open
+ * a popup with the portal composer when clicking on it.
+ **/
+var RatingPopupComposer = publicWidget.Widget.extend({
+ template: 'website_rating.PopupComposer',
+ xmlDependencies: [
+ '/portal/static/src/xml/portal_chatter.xml',
+ '/website_rating/static/src/xml/website_mail.xml',
+ '/website_rating/static/src/xml/portal_chatter.xml',
+ ],
+
+ init: function (parent, options) {
+ this._super.apply(this, arguments);
+ this.rating_avg = Math.round(options['ratingAvg'] / STAR_RATING_RATIO * 100) / 100 || 0.0;
+ this.rating_total = options['ratingTotal'] || 0.0;
+
+ this.options = _.defaults({}, options, {
+ 'token': false,
+ 'res_model': false,
+ 'res_id': false,
+ 'pid': 0,
+ 'display_composer': !session.is_website_user,
+ 'display_rating': true,
+ 'csrf_token': odoo.csrf_token,
+ 'user_id': session.user_id,
+ });
+ },
+ /**
+ * @override
+ */
+ start: function () {
+ var defs = [];
+ defs.push(this._super.apply(this, arguments));
+ // instanciate and insert composer widget
+ this._composer = new PortalComposer(this, this.options);
+ defs.push(this._composer.replace(this.$('.o_portal_chatter_composer')));
-base.ready().then(function () {
- $('.o_rating_popup_composer').each(function (index) {
- var $elem = $(this);
- var rating_popup = new RatingPopupComposer(rootWidget, $elem.data());
- rating_popup.appendTo($elem);
- });
+ return $.when.apply($, defs);
+ },
});
+publicWidget.registry.RatingPopupComposer = publicWidget.Widget.extend({
+ selector: '.o_rating_popup_composer',
+ /**
+ * @override
+ */
+ start: function () {
+ var ratingPopup = new RatingPopupComposer(this, this.$el.data());
+ return $.when(
+ this._super.apply(this, arguments),
+ ratingPopup.appendTo(this.$el)
+ );
+ },
+});
});
diff --git a/addons/website_sale/static/src/js/website_sale_payment.js b/addons/website_sale/static/src/js/website_sale_payment.js
index cc104fecc39..11edc7adc8d 100644
--- a/addons/website_sale/static/src/js/website_sale_payment.js
+++ b/addons/website_sale/static/src/js/website_sale_payment.js
@@ -1,18 +1,48 @@
odoo.define('website_sale.payment', function (require) {
'use strict';
-require('web.dom_ready');
-
-var $checkbox = $("#checkbox_cgv");
-if (!$checkbox.length) {
- return;
-}
-var $pay_button = $('button#o_payment_form_pay');
-
-$checkbox.on('change', function (ev) {
- $pay_button.data('disabled_reasons', $pay_button.data('disabled_reasons') || {});
- $pay_button.data('disabled_reasons').cgv = !ev.target.checked;
- $pay_button.prop('disabled', _.contains($pay_button.data('disabled_reasons'), true));
+var publicWidget = require('web.public.widget');
+
+publicWidget.registry.WebsiteSalePayment = publicWidget.Widget.extend({
+ selector: '#wrapwrap:has(#checkbox_cgv)',
+ events: {
+ 'change #checkbox_cgv': '_onCGVCheckboxClick',
+ },
+
+ /**
+ * @override
+ */
+ start: function () {
+ this.$checkbox = this.$('#checkbox_cgv');
+ this.$payButton = $('button#o_payment_form_pay');
+ this._adaptPayButton();
+ return this._super.apply(this, arguments);
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ _adaptPayButton: function () {
+ var disabledReasons = this.$payButton.data('disabled_reasons') || {};
+ disabledReasons.cgv = !this.$checkbox.prop('checked');
+ this.$payButton.data('disabled_reasons', disabledReasons);
+
+ this.$payButton.prop('disabled', _.contains(disabledReasons, true));
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ _onCGVCheckboxClick: function () {
+ this._adaptPayButton();
+ },
});
-$checkbox.change();
});