summaryrefslogtreecommitdiff
path: root/addons/portal/static/src/js/portal.js
diff options
context:
space:
mode:
Diffstat (limited to 'addons/portal/static/src/js/portal.js')
-rw-r--r--addons/portal/static/src/js/portal.js245
1 files changed, 245 insertions, 0 deletions
diff --git a/addons/portal/static/src/js/portal.js b/addons/portal/static/src/js/portal.js
new file mode 100644
index 00000000..610e58b5
--- /dev/null
+++ b/addons/portal/static/src/js/portal.js
@@ -0,0 +1,245 @@
+odoo.define('portal.portal', function (require) {
+'use strict';
+
+var publicWidget = require('web.public.widget');
+const Dialog = require('web.Dialog');
+const {_t, qweb} = require('web.core');
+const ajax = require('web.ajax');
+
+publicWidget.registry.portalDetails = publicWidget.Widget.extend({
+ selector: '.o_portal_details',
+ events: {
+ 'change select[name="country_id"]': '_onCountryChange',
+ },
+
+ /**
+ * @override
+ */
+ start: function () {
+ var def = this._super.apply(this, arguments);
+
+ 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().length;
+ this.$state.parent().toggle(nb >= 1);
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ _onCountryChange: function () {
+ this._adaptAddressForm();
+ },
+});
+
+publicWidget.registry.PortalHomeCounters = publicWidget.Widget.extend({
+ selector: '.o_portal_my_home',
+
+ /**
+ * @override
+ */
+ start: function () {
+ var def = this._super.apply(this, arguments);
+ this._updateCounters();
+ return def;
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ async _updateCounters(elem) {
+ const numberRpc = 3;
+ const needed = this.$('[data-placeholder_count]')
+ .map((i, o) => $(o).data('placeholder_count'))
+ .toArray();
+ const counterByRpc = Math.ceil(needed.length / numberRpc); // max counter, last can be less
+
+ const proms = [...Array(Math.min(numberRpc, needed.length)).keys()].map(async i => {
+ await this._rpc({
+ route: "/my/counters",
+ params: {
+ counters: needed.slice(i * counterByRpc, (i + 1) * counterByRpc)
+ },
+ }).then(data => {
+ Object.keys(data).map(k => this.$("[data-placeholder_count='" + k + "']").text(data[k]));
+ });
+ });
+ return Promise.all(proms);
+ },
+});
+
+publicWidget.registry.portalSearchPanel = publicWidget.Widget.extend({
+ selector: '.o_portal_search_panel',
+ events: {
+ 'click .search-submit': '_onSearchSubmitClick',
+ 'click .dropdown-item': '_onDropdownItemClick',
+ 'keyup input[name="search"]': '_onSearchInputKeyup',
+ },
+
+ /**
+ * @override
+ */
+ start: function () {
+ var def = this._super.apply(this, arguments);
+ 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();
+ }
+ },
+});
+
+/**
+ * Wraps an RPC call in a check for the result being an identity check action
+ * descriptor. If no such result is found, just returns the wrapped promise's
+ * result as-is; otherwise shows an identity check dialog and resumes the call
+ * on success.
+ *
+ * Warning: does not in and of itself trigger an identity check, a promise which
+ * never triggers and identity check internally will do nothing of use.
+ *
+ * @param {Function} rpc Widget#_rpc bound do the widget
+ * @param {Promise} wrapped promise to check for an identity check request
+ * @returns {Promise} result of the original call
+ */
+function handleCheckIdentity(rpc, wrapped) {
+ return wrapped.then((r) => {
+ if (!_.isMatch(r, {type: 'ir.actions.act_window', res_model: 'res.users.identitycheck'})) {
+ return r;
+ }
+ const check_id = r.res_id;
+ return ajax.loadXML('/portal/static/src/xml/portal_security.xml', qweb).then(() => new Promise((resolve, reject) => {
+ const d = new Dialog(null, {
+ title: _t("Security Control"),
+ $content: qweb.render('portal.identitycheck'),
+ buttons: [{
+ text: _t("Confirm Password"), classes: 'btn btn-primary',
+ // nb: if click & close, waits for click to resolve before closing
+ click() {
+ const password_input = this.el.querySelector('[name=password]');
+ if (!password_input.reportValidity()) {
+ password_input.classList.add('is-invalid');
+ return;
+ }
+ return rpc({
+ model: 'res.users.identitycheck',
+ method: 'write',
+ args: [check_id, {password: password_input.value}]
+ }).then(() => rpc({
+ model: 'res.users.identitycheck',
+ method: 'run_check',
+ args: [check_id]
+ })).then((r) => {
+ this.close();
+ resolve(r);
+ }, (err) => {
+ err.event.preventDefault(); // suppress crashmanager
+ password_input.classList.add('is-invalid');
+ password_input.setCustomValidity(_t("Check failed"));
+ password_input.reportValidity();
+ });
+ }
+ }, {
+ text: _t('Cancel'), close: true
+ }, {
+ text: _t('Forgot password?'), classes: 'btn btn-link',
+ click() { window.location.href = "/web/reset_password/"; }
+ }]
+ }).on('close', null, () => {
+ // unlink wizard object?
+ reject();
+ });
+ d.opened(() => {
+ const pw = d.el.querySelector('[name="password"]');
+ pw.focus();
+ pw.addEventListener('input', () => {
+ pw.classList.remove('is-invalid');
+ pw.setCustomValidity('');
+ });
+ d.el.addEventListener('submit', (e) => {
+ e.preventDefault();
+ d.$footer.find('.btn-primary').click();
+ });
+ });
+ d.open();
+ }));
+ });
+}
+return {
+ handleCheckIdentity,
+}
+});