[IMP] website, *: move all google map options to left panel
*: web_editor
-> Introduce the we-gpspicker widget and improve the way the gmap lib
is loaded (for Odoo / multiple snippets / ...).
Part of https://github.com/odoo/odoo/pull/49101
task-2091396
This commit is contained in:
@@ -1601,6 +1601,7 @@ const SnippetOptionWidget = Widget.extend({
|
||||
tagName: 'we-customizeblock-option',
|
||||
custom_events: {
|
||||
'user_value_update': '_onUserValueUpdate',
|
||||
'user_value_widget_critical': '_onUserValueWidgetCritical',
|
||||
},
|
||||
/**
|
||||
* Indicates if the option should be displayed in the button group at the
|
||||
@@ -2546,6 +2547,14 @@ const SnippetOptionWidget = Widget.extend({
|
||||
});
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onUserValueWidgetCritical() {
|
||||
this.trigger_up('remove_snippet', {
|
||||
$snippet: this.$target,
|
||||
});
|
||||
},
|
||||
});
|
||||
const registry = {};
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
odoo.define('website.root', function (require) {
|
||||
'use strict';
|
||||
|
||||
var core = require('web.core');
|
||||
const ajax = require('web.ajax');
|
||||
const {_t} = require('web.core');
|
||||
var Dialog = require('web.Dialog');
|
||||
const KeyboardNavigationMixin = require('web.KeyboardNavigationMixin');
|
||||
const session = require('web.session');
|
||||
var publicRootData = require('web.public.root');
|
||||
require("web.zoomodoo");
|
||||
|
||||
var _t = core._t;
|
||||
|
||||
var websiteRootRegistry = publicRootData.publicRootRegistry;
|
||||
|
||||
var WebsiteRoot = publicRootData.PublicRoot.extend(KeyboardNavigationMixin, {
|
||||
@@ -20,8 +19,10 @@ var WebsiteRoot = publicRootData.PublicRoot.extend(KeyboardNavigationMixin, {
|
||||
'shown.bs.modal': '_onModalShown',
|
||||
}),
|
||||
custom_events: _.extend({}, publicRootData.PublicRoot.prototype.custom_events || {}, {
|
||||
'gmap_api_request': '_onGMapAPIRequest',
|
||||
'gmap_api_key_request': '_onGMapAPIKeyRequest',
|
||||
'ready_to_clean_for_save': '_onWidgetsStopRequest',
|
||||
seo_object_request: '_onSeoObjectRequest',
|
||||
'seo_object_request': '_onSeoObjectRequest',
|
||||
}),
|
||||
|
||||
/**
|
||||
@@ -90,6 +91,21 @@ var WebsiteRoot = publicRootData.PublicRoot.extend(KeyboardNavigationMixin, {
|
||||
'edit_translations': !!html.dataset.edit_translations,
|
||||
}, this._super.apply(this, arguments));
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {boolean} [refetch=false]
|
||||
*/
|
||||
async _getGMapAPIKey(refetch) {
|
||||
if (refetch || !this._gmapAPIKeyProm) {
|
||||
this._gmapAPIKeyProm = new Promise(async resolve => {
|
||||
const data = await this._rpc({
|
||||
route: '/website/google_maps_api_key',
|
||||
});
|
||||
resolve(JSON.parse(data).google_maps_api_key || '');
|
||||
});
|
||||
}
|
||||
return this._gmapAPIKeyProm;
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
@@ -102,6 +118,50 @@ var WebsiteRoot = publicRootData.PublicRoot.extend(KeyboardNavigationMixin, {
|
||||
}
|
||||
return registry;
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {boolean} [editableMode=false]
|
||||
* @param {boolean} [refetch=false]
|
||||
*/
|
||||
async _loadGMapAPI(editableMode, refetch) {
|
||||
// Note: only need refetch to reload a configured key and load the
|
||||
// library. If the library was loaded with a correct key and that the
|
||||
// key changes meanwhile... it will not work but we can agree the user
|
||||
// can bother to reload the page at that moment.
|
||||
if (refetch || !this._gmapAPILoading) {
|
||||
this._gmapAPILoading = new Promise(async resolve => {
|
||||
const key = await this._getGMapAPIKey(refetch);
|
||||
|
||||
window.odoo_gmap_api_post_load = (async function odoo_gmap_api_post_load() {
|
||||
await this._startWidgets(undefined, {editableMode: editableMode});
|
||||
resolve(key);
|
||||
}).bind(this);
|
||||
|
||||
if (!key) {
|
||||
if (!editableMode && session.is_admin) {
|
||||
this.displayNotification({
|
||||
type: 'warning',
|
||||
sticky: true,
|
||||
message:
|
||||
$('<div/>').append(
|
||||
$('<span/>', {text: _t("Cannot load google map.")}),
|
||||
$('<br/>'),
|
||||
$('<a/>', {
|
||||
href: "/web#action=website.action_website_configuration",
|
||||
text: _t("Check your configuration."),
|
||||
}),
|
||||
)[0].outerHTML,
|
||||
});
|
||||
}
|
||||
resolve(false);
|
||||
this._gmapAPILoading = false;
|
||||
return;
|
||||
}
|
||||
await ajax.loadJS(`https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=places&callback=odoo_gmap_api_post_load&key=${key}`);
|
||||
});
|
||||
}
|
||||
return this._gmapAPILoading;
|
||||
},
|
||||
/**
|
||||
* Toggles the fullscreen mode.
|
||||
*
|
||||
@@ -163,6 +223,24 @@ var WebsiteRoot = publicRootData.PublicRoot.extend(KeyboardNavigationMixin, {
|
||||
};
|
||||
window.location.href = _.str.sprintf("/website/lang/%(lang)s?r=%(url)s%(hash)s", redirect);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {OdooEvent} ev
|
||||
*/
|
||||
async _onGMapAPIRequest(ev) {
|
||||
ev.stopPropagation();
|
||||
const apiKey = await this._loadGMapAPI(ev.data.editableMode, ev.data.refetch);
|
||||
ev.data.onSuccess(apiKey);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {OdooEvent} ev
|
||||
*/
|
||||
async _onGMapAPIKeyRequest(ev) {
|
||||
ev.stopPropagation();
|
||||
const apiKey = await this._getGMapAPIKey(ev.data.refetch);
|
||||
ev.data.onSuccess(apiKey);
|
||||
},
|
||||
/**
|
||||
/**
|
||||
* Checks information about the page SEO object.
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
odoo.define('website.snippet.editor', function (require) {
|
||||
'use strict';
|
||||
|
||||
const {_t} = require('web.core');
|
||||
const {qweb, _t} = require('web.core');
|
||||
const Dialog = require('web.Dialog');
|
||||
const weSnippetEditor = require('web_editor.snippet.editor');
|
||||
const wSnippetOptions = require('website.editor.snippets.options');
|
||||
|
||||
const FontFamilyPickerUserValueWidget = wSnippetOptions.FontFamilyPickerUserValueWidget;
|
||||
|
||||
weSnippetEditor.Class.include({
|
||||
xmlDependencies: (weSnippetEditor.Class.prototype.xmlDependencies || [])
|
||||
.concat(['/website/static/src/xml/website.editor.xml']),
|
||||
events: _.extend({}, weSnippetEditor.Class.prototype.events, {
|
||||
'click .o_we_customize_theme_btn': '_onThemeTabClick',
|
||||
}),
|
||||
custom_events: Object.assign({}, weSnippetEditor.Class.prototype.custom_events, {
|
||||
'gmap_api_request': '_onGMapAPIRequest',
|
||||
'gmap_api_key_request': '_onGMapAPIKeyRequest',
|
||||
}),
|
||||
tabs: _.extend({}, weSnippetEditor.Class.prototype.tabs, {
|
||||
THEME: 'theme',
|
||||
}),
|
||||
@@ -31,6 +38,55 @@ weSnippetEditor.Class.include({
|
||||
|
||||
return this._super(...arguments);
|
||||
},
|
||||
/**
|
||||
* Depending of the demand, reconfigure they gmap key or configure it
|
||||
* if not already defined.
|
||||
*
|
||||
* @private
|
||||
* @param {boolean} [reconfigure=false]
|
||||
* @param {boolean} [onlyIfUndefined=false]
|
||||
*/
|
||||
async _configureGMapAPI({reconfigure, onlyIfUndefined}) {
|
||||
const apiKey = await new Promise(resolve => {
|
||||
this.getParent().trigger_up('gmap_api_key_request', {
|
||||
onSuccess: key => resolve(key),
|
||||
});
|
||||
});
|
||||
if (!reconfigure && (apiKey || !onlyIfUndefined)) {
|
||||
return false;
|
||||
}
|
||||
let websiteId;
|
||||
this.trigger_up('context_get', {
|
||||
callback: ctx => websiteId = ctx['website_id'],
|
||||
});
|
||||
return new Promise(resolve => {
|
||||
let invalidated = false;
|
||||
const dialog = new Dialog(this, {
|
||||
size: 'medium',
|
||||
title: _t("Google Map API Key"),
|
||||
buttons: [
|
||||
{text: _t("Save"), classes: 'btn-primary', close: true, click: async () => {
|
||||
const newAPIKey = dialog.$('#api_key_input').val() || false;
|
||||
await this._rpc({
|
||||
model: 'website',
|
||||
method: 'write',
|
||||
args: [
|
||||
[websiteId],
|
||||
{google_maps_api_key: newAPIKey},
|
||||
],
|
||||
});
|
||||
invalidated = true;
|
||||
}},
|
||||
{text: _t("Cancel"), close: true}
|
||||
],
|
||||
$content: $(qweb.render('website.s_google_map_modal', {
|
||||
apiKey: apiKey,
|
||||
})),
|
||||
});
|
||||
dialog.on('closed', this, () => resolve(invalidated));
|
||||
dialog.open();
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
@@ -44,6 +100,23 @@ weSnippetEditor.Class.include({
|
||||
}
|
||||
return finalOptions;
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {OdooEvent} ev
|
||||
* @param {string} gmapRequestEventName
|
||||
*/
|
||||
async _handleGMapRequest(ev, gmapRequestEventName) {
|
||||
ev.stopPropagation();
|
||||
const reconfigured = await this._configureGMapAPI({
|
||||
reconfigure: ev.data.reconfigure,
|
||||
onlyIfUndefined: ev.data.configureIfNecessary,
|
||||
});
|
||||
this.getParent().trigger_up(gmapRequestEventName, {
|
||||
refetch: reconfigured,
|
||||
editableMode: true,
|
||||
onSuccess: key => ev.data.onSuccess(key),
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
@@ -56,6 +129,20 @@ weSnippetEditor.Class.include({
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {OdooEvent} ev
|
||||
*/
|
||||
_onGMapAPIRequest(ev) {
|
||||
this._handleGMapRequest(ev, 'gmap_api_request');
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {OdooEvent} ev
|
||||
*/
|
||||
_onGMapAPIKeyRequest(ev) {
|
||||
this._handleGMapRequest(ev, 'gmap_api_key_request');
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
||||
@@ -211,8 +211,133 @@ const FontFamilyPickerUserValueWidget = SelectUserValueWidget.extend({
|
||||
},
|
||||
});
|
||||
|
||||
const GPSPicker = InputUserValueWidget.extend({
|
||||
events: { // Explicitely not consider all InputUserValueWidget events
|
||||
'blur input': '_onInputBlur',
|
||||
},
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
this._gmapCacheGPSToPlace = {};
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
async willStart() {
|
||||
await this._super(...arguments);
|
||||
this._gmapLoaded = await new Promise(resolve => {
|
||||
this.trigger_up('gmap_api_request', {
|
||||
editableMode: true,
|
||||
configureIfNecessary: true,
|
||||
onSuccess: key => resolve(!!key),
|
||||
});
|
||||
});
|
||||
if (!this._gmapLoaded) {
|
||||
this.trigger_up('user_value_widget_critical');
|
||||
return;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
async start() {
|
||||
await this._super(...arguments);
|
||||
this.el.classList.add('o_we_large_input');
|
||||
if (!this._gmapLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._gmapAutocomplete = new google.maps.places.Autocomplete(this.inputEl, {types: ['geocode']});
|
||||
google.maps.event.addListener(this._gmapAutocomplete, 'place_changed', this._onPlaceChanged.bind(this));
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
getMethodsParams: function (methodName) {
|
||||
return Object.assign({gmapPlace: this._gmapPlace || {}}, this._super(...arguments));
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
_updateUI: async function () {
|
||||
await this._super(...arguments);
|
||||
|
||||
await new Promise(resolve => {
|
||||
const gps = this._value;
|
||||
if (this._gmapCacheGPSToPlace[gps]) {
|
||||
this._gmapPlace = this._gmapCacheGPSToPlace[gps];
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
const service = new google.maps.places.PlacesService(document.createElement('div'));
|
||||
const p = gps.substring(1).slice(0, -1).split(',');
|
||||
const location = new google.maps.LatLng(p[0] || 0, p[1] || 0);
|
||||
service.nearbySearch({
|
||||
// Do a 'nearbySearch' followed by 'getDetails' to avoid using
|
||||
// GMap Geocoder which the user may not have enabled... but
|
||||
// ideally Geocoder should be used to get the exact location at
|
||||
// those coordinates and to limit billing query count.
|
||||
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) {
|
||||
service.getDetails({
|
||||
placeId: results[0].place_id,
|
||||
fields: ['geometry', 'formatted_address'],
|
||||
}, (place, status) => {
|
||||
resolve();
|
||||
if (status === google.maps.places.PlacesServiceStatus.OK) {
|
||||
this._gmapCacheGPSToPlace[gps] = place;
|
||||
this._gmapPlace = place;
|
||||
} else if (GMAP_CRITICAL_ERRORS.includes(status)) {
|
||||
this.trigger_up('user_value_widget_critical');
|
||||
}
|
||||
});
|
||||
} else if (GMAP_CRITICAL_ERRORS.includes(status)) {
|
||||
resolve();
|
||||
this.trigger_up('user_value_widget_critical');
|
||||
}
|
||||
});
|
||||
});
|
||||
this.inputEl.value = this._gmapPlace.formatted_address;
|
||||
},
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Event} ev
|
||||
*/
|
||||
_onPlaceChanged(ev) {
|
||||
const gmapPlace = this._gmapAutocomplete.getPlace();
|
||||
if (gmapPlace && gmapPlace.geometry) {
|
||||
this._gmapPlace = gmapPlace;
|
||||
const location = this._gmapPlace.geometry.location;
|
||||
this._value = `(${location.lat()},${location.lng()})`;
|
||||
this._gmapCacheGPSToPlace[this._value] = gmapPlace;
|
||||
this._onUserValueChange(ev);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
options.userValueWidgetsRegistry['we-urlpicker'] = UrlPickerUserValueWidget;
|
||||
options.userValueWidgetsRegistry['we-fontfamilypicker'] = FontFamilyPickerUserValueWidget;
|
||||
options.userValueWidgetsRegistry['we-gpspicker'] = GPSPicker;
|
||||
|
||||
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
|
||||
@@ -135,3 +135,12 @@ we-collapse {
|
||||
border-width: 4px;
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
.pac-container { // google map autosuggestion
|
||||
z-index: $zindex-modal-backdrop; // > $o-we-zindex
|
||||
min-width: 400px;
|
||||
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
odoo.define('website.s_google_map', function (require) {
|
||||
'use strict';
|
||||
|
||||
const ajax = require('web.ajax');
|
||||
const {_t} = require('web.core');
|
||||
const publicWidget = require('web.public.widget');
|
||||
|
||||
let googleScriptLoadedResolve = null;
|
||||
const googleScriptLoaded = new Promise(resolve => googleScriptLoadedResolve = resolve);
|
||||
|
||||
publicWidget.registry.GoogleMap = publicWidget.Widget.extend({
|
||||
selector: '.s_google_map',
|
||||
disabledInEditableMode: false,
|
||||
@@ -31,42 +26,12 @@ publicWidget.registry.GoogleMap = publicWidget.Widget.extend({
|
||||
await this._super(...arguments);
|
||||
|
||||
if (typeof google !== 'object' || typeof google.maps !== 'object') {
|
||||
if (!publicWidget.registry.GoogleMap.isScriptLoading) {
|
||||
publicWidget.registry.GoogleMap.isScriptLoading = true;
|
||||
const self = this;
|
||||
window.odoo_s_google_map_redraw_all = function odoo_s_google_map_redraw_all() {
|
||||
for (const map of $('section.s_google_map')) {
|
||||
self.trigger_up('widgets_start_request', {
|
||||
editableMode: self.editableMode,
|
||||
$target: $(map),
|
||||
});
|
||||
}
|
||||
publicWidget.registry.GoogleMap.isScriptLoading = false;
|
||||
googleScriptLoadedResolve();
|
||||
};
|
||||
|
||||
const data = await this._rpc({
|
||||
route: '/website/google_maps_api_key',
|
||||
await new Promise(resolve => {
|
||||
this.trigger_up('gmap_api_request', {
|
||||
editableMode: this.editableMode,
|
||||
onSuccess: () => resolve(),
|
||||
});
|
||||
|
||||
const key = JSON.parse(data).google_maps_api_key;
|
||||
if (!key) {
|
||||
publicWidget.registry.GoogleMap.isScriptLoading = false;
|
||||
if (this.editableMode) {
|
||||
this.$loadingWarning = $('<div/>', {
|
||||
class: 'alert alert-warning alert-link',
|
||||
}).append($('<a/>', {
|
||||
href: "#",
|
||||
text: _t("Cannot load google map, check your configuration !"),
|
||||
})).click(function (e) {
|
||||
window.location.href = "/web#action=website.action_website_configuration";
|
||||
});
|
||||
this.$('.map_container').append(this.$loadingWarning);
|
||||
}
|
||||
return;
|
||||
}
|
||||
await ajax.loadJS(`https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=places&callback=odoo_s_google_map_redraw_all&key=${key}`);
|
||||
}
|
||||
});
|
||||
// The animation will be restarted for all maps as soon as the
|
||||
// google map script has been executed.
|
||||
return;
|
||||
@@ -127,25 +92,5 @@ publicWidget.registry.GoogleMap = publicWidget.Widget.extend({
|
||||
map.setMapTypeId('map_style');
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
destroy() {
|
||||
this._super(...arguments);
|
||||
if (this.$loadingWarning) {
|
||||
this.$loadingWarning.remove();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// This allows to save if the google maps script is already loading or not.
|
||||
// This script cannot be loaded 2 times, so if we have 2 snippets in the same
|
||||
// page we don't want to load the script 2 times.
|
||||
// And we cannot put the script in an asset because we don't want to load it
|
||||
// on each page, but only on pages with a google maps snippet...
|
||||
publicWidget.registry.GoogleMap.prototype.isScriptLoading = false;
|
||||
|
||||
return {
|
||||
googleScriptLoaded: googleScriptLoaded,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -5,9 +5,8 @@ $s-google-map-desc-hover-bg: theme-color('primary') !default;
|
||||
$s-google-map-desc-hover-alpha: 0.55 !default;
|
||||
|
||||
.s_google_map {
|
||||
height: 100%;
|
||||
min-height: 100px;
|
||||
position: relative;
|
||||
min-height: 100px;
|
||||
|
||||
.map_container {
|
||||
@include o-position-absolute(0, 0, 0, 0);
|
||||
@@ -16,8 +15,8 @@ $s-google-map-desc-hover-alpha: 0.55 !default;
|
||||
@include o-position-absolute(auto, 0, 0, 0);
|
||||
z-index: 99;
|
||||
padding: 0 1em;
|
||||
background: rgba($s-google-map-desc-bg , $s-google-map-desc-alpha);
|
||||
color: color-yiq(rgba($s-google-map-desc-bg , $s-google-map-desc-alpha));
|
||||
background: rgba($s-google-map-desc-bg, $s-google-map-desc-alpha);
|
||||
color: color-yiq(rgba($s-google-map-desc-bg, $s-google-map-desc-alpha));
|
||||
transition: background-color 250ms ease;
|
||||
|
||||
font {
|
||||
@@ -41,14 +40,3 @@ $s-google-map-desc-hover-alpha: 0.55 !default;
|
||||
color: color-yiq(rgba($s-google-map-desc-hover-bg, $s-google-map-desc-hover-alpha));
|
||||
}
|
||||
}
|
||||
|
||||
#mapModal {
|
||||
z-index: 3000;
|
||||
}
|
||||
.pac-container { // google map autosuggestion
|
||||
z-index: 3001;
|
||||
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,78 +1,56 @@
|
||||
odoo.define('options.s_google_map_options', function (require) {
|
||||
'use strict';
|
||||
|
||||
const {Dialog} = require('web_editor.widget');
|
||||
const {_t, qweb} = require('web.core');
|
||||
const {_t} = require('web.core');
|
||||
const options = require('web_editor.snippets.options');
|
||||
const {googleScriptLoaded} = require('website.s_google_map');
|
||||
|
||||
options.registry.GoogleMap = options.Class.extend({
|
||||
xmlDependencies: ['/website/static/src/xml/s_google_map_modal.xml'],
|
||||
defaultLocation: '(50.854975,4.3753899)',
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
onBuilt() {
|
||||
this._super(...arguments);
|
||||
|
||||
let widget = null;
|
||||
this.trigger_up('user_value_widget_request', {
|
||||
name: 'map_options_opt',
|
||||
onSuccess: _widget => widget = _widget,
|
||||
});
|
||||
widget.$el.click();
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Options
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Opens the customization dialog.
|
||||
*
|
||||
* @see this.selectClass for parameters
|
||||
*/
|
||||
async map(previewMode, widgetValue, params) {
|
||||
await new Promise(resolve => {
|
||||
this.dialog = new Dialog(this, {
|
||||
size: 'medium',
|
||||
title: _t("Customize your map"),
|
||||
buttons: [
|
||||
{text: _t("Save"), classes: 'btn-primary', close: true, click: () => {
|
||||
if (!this.dialog.$('#placeBk').val()) {
|
||||
this.dialog.$('#placeBk').val(this.defaultLocation);
|
||||
}
|
||||
this.$target[0].dataset.mapGps = this.dialog.$('#placeBk').val();
|
||||
this.$target[0].dataset.pinStyle = this.dialog.$('#pin_style').val();
|
||||
this.$target[0].dataset.pinAddress = this.dialog.$('#pin_address').val();
|
||||
}},
|
||||
{text: _t("Cancel"), close: true}
|
||||
],
|
||||
$content: $(qweb.render('website.s_google_map_modal'))
|
||||
});
|
||||
|
||||
this.dialog.opened().then(() => {
|
||||
this.dialog.$('#pin_address').val(this.$target[0].dataset.pinAddress);
|
||||
this.dialog.$('#pin_style').val(this.$target[0].dataset.pinStyle);
|
||||
this.dialog.$('#placeBk').val(this.$target[0].dataset.mapGps);
|
||||
const autocomplete = new google.maps.places.Autocomplete(this.dialog.$('#pin_address').get(0), {types: ['geocode']});
|
||||
google.maps.event.addListener(autocomplete, 'place_changed', () => {
|
||||
const place = autocomplete.getPlace();
|
||||
this.dialog.$('#placeBk').val(place.geometry ? place.geometry.location : this.defaultLocation);
|
||||
});
|
||||
});
|
||||
|
||||
this.dialog.on('closed', this, () => resolve());
|
||||
|
||||
googleScriptLoaded.then(() => this.dialog.open());
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @see this.selectClass for parameters
|
||||
*/
|
||||
resetMapColor(previewMode, widgetValue, params) {
|
||||
this.$target[0].dataset.mapColor = '';
|
||||
},
|
||||
/**
|
||||
* @see this.selectClass for parameters
|
||||
*/
|
||||
setFormattedAddress(previewMode, widgetValue, params) {
|
||||
this.$target[0].dataset.pinAddress = params.gmapPlace.formatted_address;
|
||||
},
|
||||
/**
|
||||
* @see this.selectClass for parameters
|
||||
*/
|
||||
async showDescription(previewMode, widgetValue, params) {
|
||||
const descriptionEl = this.$target[0].querySelector('.description');
|
||||
if (widgetValue && !descriptionEl) {
|
||||
this.$target.append($(`
|
||||
<div class="description">
|
||||
<font>${_t('Visit us:')}</font>
|
||||
<span>${_t('Our office is located in the northeast of Brussels. TEL (555) 432 2365')}</span>
|
||||
</div>`)
|
||||
);
|
||||
} else if (!widgetValue && descriptionEl) {
|
||||
descriptionEl.remove();
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
_computeWidgetState(methodName, params) {
|
||||
if (methodName === 'showDescription') {
|
||||
return this.$target[0].querySelector('.description') ? 'true' : '';
|
||||
}
|
||||
return this._super(...arguments);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
<div t-name="website.s_google_map_modal">
|
||||
<div class="form-group form-row">
|
||||
<label for="pin_address" class="col-md-3 col-form-label text-right">Address</label>
|
||||
<div class="col-md-9">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text"><i class="fa fa-building-o"/></div>
|
||||
</div>
|
||||
<input type="text" class="form-control" id="pin_address" placeholder="Your address"/>
|
||||
<input type="hidden" id="placeBk"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-9 offset-md-3">
|
||||
<small class="form-text">e.g. De Brouckere, Brussels, Belgium</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group form-row">
|
||||
<label for="pin_style" class="col-md-3 col-form-label text-right">Marker Style</label>
|
||||
<div class="col-md-9">
|
||||
<select id="pin_style" name="pin_style" class="col-md-5">
|
||||
<option value="flat">Flat</option>
|
||||
<option>Default</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</templates>
|
||||
@@ -107,6 +107,35 @@
|
||||
</we-row>
|
||||
</div>
|
||||
</t>
|
||||
<div t-name="website.s_google_map_modal">
|
||||
<p>Use Google Map on your website (Contact Us page, snippets, etc).</p>
|
||||
<div class="form-group row mb-0">
|
||||
<label class="col-sm-2 col-form-label" for="pin_address">API Key</label>
|
||||
<div class="col">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text"><i class="fa fa-key"/></div>
|
||||
</div>
|
||||
<input type="text" class="form-control" id="api_key_input"
|
||||
t-att-value="apiKey or ''"
|
||||
placeholder="BSgzTvR5L1GB9jriT451iTN4huVPxHmltG6T6eo"/>
|
||||
</div>
|
||||
<div class="small form-text text-muted">
|
||||
Hint: How to use Google Map on your website (Contact Us page and as a snippet)
|
||||
<br/>
|
||||
<a target="_blank" href="https://console.developers.google.com/flows/enableapi?apiid=maps_backend,static_maps_backend&keyType=CLIENT_SIDE&reusekey=true">
|
||||
<i class="fa fa-arrow-right"/>
|
||||
Create a Google Project and Get a Key
|
||||
</a>
|
||||
<br/>
|
||||
<a target="_blank" href="https://cloud.google.com/maps-platform/pricing">
|
||||
<i class="fa fa-arrow-right"/>
|
||||
Enable billing on your Google Project
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Theme - custom code -->
|
||||
<div t-name="website.custom_code_dialog_content">
|
||||
|
||||
@@ -4,18 +4,22 @@
|
||||
<template name="Google Map" id="s_google_map">
|
||||
<section class="s_google_map pt256 pb256" data-map-type="ROADMAP" data-map-color="" data-map-zoom="12" data-map-gps="(50.854975,4.3753899)" data-pin-style="flat">
|
||||
<div class="map_container"/>
|
||||
<div class="description">
|
||||
<font>Visit us:</font>
|
||||
<span>Our office is located in the northeast of Brussels. TEL (555) 432 2365</span>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<!-- Snippet's Options -->
|
||||
<template id="s_google_map_option" inherit_id="website.snippet_options">
|
||||
<template id="s_google_map_options" inherit_id="website.snippet_options">
|
||||
<xpath expr="//div[@data-js='parallax']" position="before">
|
||||
<div data-js="GoogleMap" data-selector="section.s_google_map">
|
||||
<we-button data-name="map_options_opt" data-map="" data-no-preview="true">Map Options</we-button>
|
||||
<div data-js="GoogleMap" data-selector=".s_google_map">
|
||||
<we-gpspicker string="Address"
|
||||
data-select-data-attribute="" data-attribute-name="mapGps"
|
||||
data-set-formatted-address=""
|
||||
placeholder="e.g. De Brouckere, Brussels, Belgium"
|
||||
data-no-preview="true"/>
|
||||
<we-select string="Marker style" data-attribute-name="pinStyle">
|
||||
<we-button data-select-data-attribute="">Default</we-button>
|
||||
<we-button data-select-data-attribute="flat">Flat</we-button>
|
||||
</we-select>
|
||||
<we-select string="Type" data-no-preview="true" data-reset-map-color="" data-attribute-name="mapType">
|
||||
<we-button data-name="roadmap_opt" data-select-data-attribute="ROADMAP">RoadMap</we-button>
|
||||
<we-button data-select-data-attribute="TERRAIN">Terrain</we-button>
|
||||
@@ -45,6 +49,7 @@
|
||||
data-img="/website/static/src/snippets/s_google_map/img/thumbs/map-bw.jpg"/>
|
||||
</we-select>
|
||||
<we-input string="Zoom" data-select-data-attribute="12" data-no-preview="true" data-attribute-name="mapZoom" data-step="1"/>
|
||||
<we-checkbox string="Description" data-no-preview="true" data-show-description="true"/>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
@@ -374,7 +374,7 @@
|
||||
t-att-data-selector="so_snippet_addition_selector"
|
||||
data-drop-in=":not(p).oe_structure:not(.oe_structure_solo), :not(p)[data-oe-type=html], :not(p).oe_structure.oe_structure_solo:not(:has(> section, > div))"/>
|
||||
|
||||
<t t-set="so_content_addition_selector" t-translation="off">blockquote, .s_card:not(.s_timeline_card), .s_alert, .o_facebook_page, .s_share, .s_rating, .s_hr, .s_countdown, .s_chart, .s_text_highlight, .s_progress_bar, .s_badge</t>
|
||||
<t t-set="so_content_addition_selector" t-translation="off">blockquote, .s_card:not(.s_timeline_card), .s_alert, .o_facebook_page, .s_share, .s_rating, .s_hr, .s_google_map, .s_countdown, .s_chart, .s_text_highlight, .s_progress_bar, .s_badge</t>
|
||||
<div id="so_content_addition"
|
||||
t-att-data-selector="so_content_addition_selector"
|
||||
t-attf-data-drop-near="p, h1, h2, h3, .row > div > img, #{so_content_addition_selector}"
|
||||
|
||||
Reference in New Issue
Block a user