diff --git a/addons/website/static/src/js/editor/snippets.options.js b/addons/website/static/src/js/editor/snippets.options.js index 341be487ff6..b8c7ae4aa83 100644 --- a/addons/website/static/src/js/editor/snippets.options.js +++ b/addons/website/static/src/js/editor/snippets.options.js @@ -1,4 +1,3 @@ -/* globals google*/ odoo.define('website.editor.snippets.options', function (require) { 'use strict'; @@ -316,6 +315,11 @@ const GPSPicker = InputUserValueWidget.extend({ init() { this._super(...arguments); this._gmapCacheGPSToPlace = {}; + + // The google API will be loaded inside the website iframe. Let's try + // not having to load it in the backend too and just using the iframe + // google object instead. + this.contentWindow = this.$target[0].ownerDocument.defaultView; }, /** * @override @@ -354,8 +358,23 @@ const GPSPicker = InputUserValueWidget.extend({ return; } - this._gmapAutocomplete = new google.maps.places.Autocomplete(this.inputEl, {types: ['geocode']}); - google.maps.event.addListener(this._gmapAutocomplete, 'place_changed', this._onPlaceChanged.bind(this)); + this._gmapAutocomplete = new this.contentWindow.google.maps.places.Autocomplete(this.inputEl, {types: ['geocode']}); + this.contentWindow.google.maps.event.addListener(this._gmapAutocomplete, 'place_changed', this._onPlaceChanged.bind(this)); + }, + /** + * @override + */ + destroy() { + this._super(...arguments); + + // Without this, the google library injects elements inside the backend + // DOM but do not remove them once the editor is left. Notice that + // this is also done when the widget is destroyed for another reason + // than leaving the editor, but if the google API needs that container + // again afterwards, it will simply recreate it. + for (const el of document.body.querySelectorAll('.pac-container')) { + el.remove(); + } }, //-------------------------------------------------------------------------- @@ -400,9 +419,9 @@ const GPSPicker = InputUserValueWidget.extend({ } const p = gps.substring(1).slice(0, -1).split(','); - const location = new google.maps.LatLng(p[0] || 0, p[1] || 0); + const location = new this.contentWindow.google.maps.LatLng(p[0] || 0, p[1] || 0); return new Promise(resolve => { - const service = new google.maps.places.PlacesService(document.createElement('div')); + const service = new this.contentWindow.google.maps.places.PlacesService(document.createElement('div')); service.nearbySearch({ // Do a 'nearbySearch' followed by 'getDetails' to avoid using // GMap Geocoder which the user may not have enabled... but @@ -411,13 +430,16 @@ const GPSPicker = InputUserValueWidget.extend({ location: location, radius: 1, }, (results, status) => { - const GMAP_CRITICAL_ERRORS = [google.maps.places.PlacesServiceStatus.REQUEST_DENIED, google.maps.places.PlacesServiceStatus.UNKNOWN_ERROR]; - if (status === google.maps.places.PlacesServiceStatus.OK) { + const GMAP_CRITICAL_ERRORS = [ + this.contentWindow.google.maps.places.PlacesServiceStatus.REQUEST_DENIED, + this.contentWindow.google.maps.places.PlacesServiceStatus.UNKNOWN_ERROR + ]; + if (status === this.contentWindow.google.maps.places.PlacesServiceStatus.OK) { service.getDetails({ placeId: results[0].place_id, fields: ['geometry', 'formatted_address'], }, (place, status) => { - if (status === google.maps.places.PlacesServiceStatus.OK) { + if (status === this.contentWindow.google.maps.places.PlacesServiceStatus.OK) { this._gmapCacheGPSToPlace[gps] = place; resolve(place); } else if (GMAP_CRITICAL_ERRORS.includes(status)) { diff --git a/addons/website/static/src/scss/website.wysiwyg.scss b/addons/website/static/src/scss/website.wysiwyg.scss index a25ffbdbbab..3ba0b52358d 100644 --- a/addons/website/static/src/scss/website.wysiwyg.scss +++ b/addons/website/static/src/scss/website.wysiwyg.scss @@ -231,29 +231,54 @@ $i: 1; border-bottom: none !important; } -.pac-container { // google map autosuggestion +.pac-container { // google map autosuggestion (note: their CSS lib is not used) z-index: $zindex-modal-backdrop; // > $o-we-zindex - width: $o-we-sidebar-width !important; + width: ceil($o-we-sidebar-width * 0.9) !important; font-size: $o-we-sidebar-font-size; margin-left: -$o-we-sidebar-width/2; + border: $o-we-sidebar-content-field-border-width solid $o-we-sidebar-content-field-dropdown-border-color; border-top: none; + border-radius: $o-we-item-border-radius; + overflow: hidden; background-color: $o-we-sidebar-content-field-dropdown-bg; box-shadow: $o-we-sidebar-content-field-dropdown-shadow; + margin-top: $o-we-sidebar-content-field-dropdown-spacing; + transform: translate(41px); + &:after { display: none; } + .pac-item { + @include o-text-overflow(block); + line-height: $o-we-sidebar-content-field-dropdown-item-height; + color: $o-we-sidebar-content-field-clickable-color; + padding: 0 1em 0 (2 * $o-we-sidebar-content-field-control-item-spacing + $o-we-sidebar-content-field-control-item-size); border-top: $o-we-sidebar-content-field-border-width solid lighten($o-we-sidebar-content-field-dropdown-border-color, 15%); border-radius: $o-we-sidebar-content-field-border-radius; background-color: $o-we-sidebar-content-field-clickable-bg; color: $o-we-sidebar-content-field-clickable-color; - &:hover { + font-size: $o-we-sidebar-font-size; + + &:hover, &:focus, &.pac-item-selected { background-color: $o-we-sidebar-content-field-dropdown-item-bg-hover; cursor: pointer; } - } - .pac-item-query { - color: $o-we-sidebar-content-field-clickable-color; + + .pac-icon-marker { + position: absolute; + margin-left: -1em; + + &::after { + content: '\f041'; + font-family: FontAwesome; + } + } + + .pac-item-query { + margin-right: 0.4em; + color: inherit; + } } }