diff options
Diffstat (limited to 'addons/portal/static/src/js/portal.js')
| -rw-r--r-- | addons/portal/static/src/js/portal.js | 245 |
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, +} +}); |
