From 03e41cb55303174ae9ded7673524c21428b5be66 Mon Sep 17 00:00:00 2001 From: Alexander Kozlovskiy Date: Tue, 17 Sep 2024 16:23:16 -0500 Subject: [PATCH] Map: implement mapId and useAdvancedMarkers options (#28029) --- .../scss/widgets/base/_map.scss | 4 + .../devextreme/js/__internal/ui/map/m_map.ts | 15 + .../ui/map/m_provider.dynamic.google.ts | 45 +- .../testing/helpers/forMap/googleMock.js | 50 +- .../mapParts/googleTests.js | 951 +++++++++++------- 5 files changed, 666 insertions(+), 399 deletions(-) diff --git a/packages/devextreme-scss/scss/widgets/base/_map.scss b/packages/devextreme-scss/scss/widgets/base/_map.scss index 58e82fe831d6..f3ce7f0a3df5 100644 --- a/packages/devextreme-scss/scss/widgets/base/_map.scss +++ b/packages/devextreme-scss/scss/widgets/base/_map.scss @@ -14,3 +14,7 @@ background: rgba(0, 0, 0, 0.01); opacity: 0.01; } + +.dx-map-marker { + user-select: none; +} diff --git a/packages/devextreme/js/__internal/ui/map/m_map.ts b/packages/devextreme/js/__internal/ui/map/m_map.ts index fc70f764a4d7..2f70418c9eca 100644 --- a/packages/devextreme/js/__internal/ui/map/m_map.ts +++ b/packages/devextreme/js/__internal/ui/map/m_map.ts @@ -61,6 +61,10 @@ const Map = Widget.inherit({ google: '', googleStatic: '', }, + providerConfig: { + mapId: '', + useAdvancedMarkers: true, + }, controls: false, onReady: null, // for internal use only @@ -82,6 +86,13 @@ const Map = Widget.inherit({ ]); }, + _setDeprecatedOptions() { + this.callBase(); + extend(this._deprecatedOptions, { + 'providerConfig.useAdvancedMarkers': { since: '24.2', message: 'Google deprecated the original map markers. Transition to advanced markers for future compatibility.' }, + }); + }, + _renderFocusTarget: noop, _init() { @@ -239,6 +250,10 @@ const Map = Widget.inherit({ case 'markerIconSrc': this._queueAsyncAction('updateMarkers', this._rendered.markers, this._rendered.markers); break; + case 'providerConfig': + this._suppressAsyncAction = true; + this._invalidate(); + break; case 'onReady': case 'onUpdated': case 'onMarkerAdded': diff --git a/packages/devextreme/js/__internal/ui/map/m_provider.dynamic.google.ts b/packages/devextreme/js/__internal/ui/map/m_provider.dynamic.google.ts index 1d3e9ea0a876..ba43ef03c997 100644 --- a/packages/devextreme/js/__internal/ui/map/m_provider.dynamic.google.ts +++ b/packages/devextreme/js/__internal/ui/map/m_provider.dynamic.google.ts @@ -18,8 +18,9 @@ declare let google: any; const window = getWindow(); +const MAP_MARKER_CLASS = 'dx-map-marker'; const GOOGLE_MAP_READY = '_googleScriptReady'; -let GOOGLE_URL = `https://maps.googleapis.com/maps/api/js?callback=${GOOGLE_MAP_READY}`; +let GOOGLE_URL = `https://maps.googleapis.com/maps/api/js?callback=${GOOGLE_MAP_READY}&libraries=marker&loading=async`; const INFO_WINDOW_CLASS = 'gm-style-iw'; let CustomMarker; @@ -192,12 +193,14 @@ const GoogleProvider = DynamicProvider.inherit({ _init() { return new Promise((resolve) => { this._resolveLocation(this._option('center')).then((center) => { - const showDefaultUI = this._option('controls'); - + const disableDefaultUI = !this._option('controls'); + const providerConfig = this._option('providerConfig'); + const mapId = providerConfig?.mapId ?? ''; this._map = new google.maps.Map(this._$container[0], { - zoom: this._option('zoom'), center, - disableDefaultUI: !showDefaultUI, + disableDefaultUI, + mapId, + zoom: this._option('zoom'), }); const listener = google.maps.event.addListener(this._map, 'idle', () => { @@ -303,11 +306,23 @@ const GoogleProvider = DynamicProvider.inherit({ }, options.htmlOffset), }); } else { - marker = new google.maps.Marker({ - position: location, - map: this._map, - icon: options.iconSrc || this._option('markerIconSrc'), - }); + const providerConfig = this._option('providerConfig'); + const useAdvancedMarkers = providerConfig?.useAdvancedMarkers ?? true; + const icon = options.iconSrc || this._option('markerIconSrc'); + if (useAdvancedMarkers) { + const content = icon ? this._createIconTemplate(icon) : undefined; + marker = new google.maps.marker.AdvancedMarkerElement({ + position: location, + map: this._map, + content, + }); + } else { + marker = new google.maps.Marker({ + position: location, + map: this._map, + icon, + }); + } } const infoWindow = this._renderTooltip(marker, options.tooltip); @@ -335,6 +350,16 @@ const GoogleProvider = DynamicProvider.inherit({ }); }, + _createIconTemplate(iconSrc: string) { + const $img = $(''); + + $img.attr('src', iconSrc); + $img.attr('alt', 'Marker icon'); + $img.addClass(MAP_MARKER_CLASS); + + return $img[0]; + }, + _renderTooltip(marker, options) { if (!options) { return; diff --git a/packages/devextreme/testing/helpers/forMap/googleMock.js b/packages/devextreme/testing/helpers/forMap/googleMock.js index 641fa6898d6e..6b4d3ad88c20 100644 --- a/packages/devextreme/testing/helpers/forMap/googleMock.js +++ b/packages/devextreme/testing/helpers/forMap/googleMock.js @@ -225,6 +225,7 @@ }, Marker: function(options) { if(options) { + google.markerType = 'old'; google.markerOptionsSpecified = true; google.markerInstance = (google.markerInstance || 0) + 1; google.markerOptions = {}; @@ -267,6 +268,53 @@ this.setVisible = function() {}; this.setZIndex = function() {}; }, + marker: { + AdvancedMarkerElement: function(options) { + if(options) { + google.markerType = 'advanced'; + google.markerOptionsSpecified = true; + google.markerInstance = (google.markerInstance || 0) + 1; + google.markerOptions = {}; + google.markerOptions.mapSpecified = options.map instanceof google.maps.Map; + google.markerOptions.position = options.position; + google.markerOptions.icon = options.content?.src; + } + + this.getAnimation = function() {}; + this.getClickable = function() {}; + this.getCursor = function() {}; + this.getDraggable = function() {}; + this.getFlat = function() {}; + this.getMap = function() {}; + this.getPosition = function() {}; + this.getShadow = function() {}; + this.getShape = function() {}; + this.getTitle = function() {}; + this.getVisible = function() {}; + this.getZIndex = function() {}; + this.setAnimation = function() {}; + this.setClickable = function() {}; + this.setCursor = function() {}; + this.setDraggable = function() {}; + this.setFlat = function() {}; + this.getIcon = function() { + return options.content?.src; + }; + this.setIcon = function() {}; + this.setMap = function(map) { + if(map === null) { + google.markerRemoved = true; + } + }; + this.setOptions = function() {}; + this.setPosition = function() {}; + this.setShadow = function() {}; + this.setShape = function() {}; + this.setTitle = function() {}; + this.setVisible = function() {}; + this.setZIndex = function() {}; + } + }, OverlayView: function() { this.bindTo = function() {}; this.getPanes = function() { @@ -334,7 +382,7 @@ google.infoWindowOpened = (google.infoWindowOpened || 0) + 1; google.openInfoWindowOptions = {}; google.openInfoWindowOptions.mapSpecified = map instanceof google.maps.Map; - google.openInfoWindowOptions.markerSpecified = marker instanceof google.maps.Marker; + google.openInfoWindowOptions.markerSpecified = marker instanceof google.maps.Marker || marker instanceof google.maps.marker.AdvancedMarkerElement; }; this.close = function() {}; this.setMap = function() {}; diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets/mapParts/googleTests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets/mapParts/googleTests.js index 9179d16ed68d..f20cb50dc55f 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets/mapParts/googleTests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets/mapParts/googleTests.js @@ -3,6 +3,7 @@ import $ from 'jquery'; import { LOCATIONS, MARKERS, ROUTES } from './utils.js'; import devices from 'core/devices'; +import errorsLogger from 'core/errors'; import errors from 'ui/widget/ui.errors'; import GoogleProvider from '__internal/ui/map/m_provider.dynamic.google'; import ajaxMock from '../../../helpers/ajaxMock.js'; @@ -608,543 +609,717 @@ QUnit.test('controls', function(assert) { }); }); -QUnit.test('markers', function(assert) { +QUnit.test('providerConfig.useAdvancedMarkers using should raise a deprecation warning', function(assert) { + sinon.spy(errorsLogger, 'log'); + + try { + $('#map').dxMap({ + provider: 'google', + providerConfig: { + useAdvancedMarkers: false, + }, + }); + assert.deepEqual(errorsLogger.log.firstCall.args, [ + 'W0001', + 'dxMap', + 'providerConfig.useAdvancedMarkers', + '24.2', + 'Google deprecated the original map markers. Transition to advanced markers for future compatibility.' + ], 'warning is raised with correct parameters'); + } finally { + errorsLogger.log.restore(); + } +}); + +QUnit.test('should not throw an error if providerConfig is undefined', function(assert) { const done = assert.async(); - const d = $.Deferred(); - const $map = $('#map').dxMap({ + $('#map').dxMap({ provider: 'google', markers: [MARKERS[0]], + providerConfig: undefined, onReady: function() { - assert.equal(window.google.markerOptionsSpecified, true, 'marker options specified'); - assert.equal(window.google.markerOptions.mapSpecified, true, 'map specified correctly'); - assert.deepEqual(window.google.markerOptions.position, new google.maps.LatLng(MARKERS[0].location.lat, MARKERS[0].location.lng), 'location specified correctly'); - assert.equal(window.google.infoWindowOpened, 1, 'tooltip is opened'); - - d.resolve(); - } - }); - const map = $map.dxMap('instance'); - - d.done(function() { - map.option('onUpdated', function() { - assert.equal(window.google.markerInstance, 3, 'markers changed'); - assert.equal(window.google.markerRemoved, true, 'previous marker removed'); - assert.equal(window.google.clickHandlerRemoved, true, 'previous marker handler removed'); + assert.ok(true, 'there was no exceptions'); done(); - }); - - map.option('markers', [MARKERS[1], MARKERS[2]]); + } }); }); -QUnit.test('marker`s tooltip options', function(assert) { +QUnit.test('marker icon can be specified using either markerIconSrc or marker.iconSrc options', function(assert) { const done = assert.async(); const d = $.Deferred(); - const $map = $('#map').dxMap({ + const markerUrl1 = 'http://example.com/1.png'; + const markerUrl2 = 'http://example.com/2.png'; + + const markers = [ + { + location: '40.537102, -73.990318', + }, + { + location: '35.537102, -73.990318', + iconSrc: markerUrl2, + } + ]; + + const map = $('#map').dxMap({ provider: 'google', - markers: [MARKERS[0]], + markerIconSrc: markerUrl1, onReady: function() { - assert.equal(window.google.infoWindowOptionsSpecified, true, 'tooltip options specified'); - assert.equal(window.google.infoWindowOptions.content, 'A', 'tooltip content specified'); - assert.equal(window.google.openInfoWindowOptions.mapSpecified, true, 'tooltip opened with specified map'); - assert.equal(window.google.openInfoWindowOptions.markerSpecified, true, 'tooltip opened with specified marker'); - assert.equal(window.google.infoWindowOpened, 1, 'tooltip opened'); - d.resolve(); } - }); - const map = $map.dxMap('instance'); + }).dxMap('instance'); d.done(function() { - map.option('onUpdated', function() { - assert.equal(window.google.infoWindowOptions.content, 'B', 'tooltip content specified'); - assert.equal(window.google.infoWindowOpened, 1, 'tooltip is not opened'); + map.addMarker(markers).done((markers) => { + assert.equal(markers[0].getIcon(), markerUrl1, 'first marker has icon from markerIconSrc option'); + assert.equal(markers[1].getIcon(), markerUrl2, 'second marker has icon from marker.iconSrc option'); done(); }); - - map.option('markers', [MARKERS[1]]); }); }); -QUnit.test('marker integration', function(assert) { +QUnit.test('markerIconSrc src should be passed to marker config if markerIconSrc was defined', function(assert) { const done = assert.async(); - - let clickFired = 0; - const marker = { - tooltip: 'A', - location: [40.537102, -73.990318], - onClick: function(e) { - assert.deepEqual(e.location, { lat: 40.537102, lng: -73.990318 }, 'markers location set'); - clickFired++; - } - }; + const markerIconSrc = 'http://example.com/1.png'; $('#map').dxMap({ provider: 'google', - markers: [marker], + markers: [MARKERS[0]], + markerIconSrc, onReady: function() { - assert.equal(window.google.infoWindowOptionsSpecified, true, 'tooltip options specified'); - assert.equal(window.google.infoWindowOptions.content, 'A', 'tooltip content specified'); - window.google.clickActionCallback(); - assert.equal(clickFired, 1, 'click action fired'); - assert.equal(window.google.infoWindowOpened, 1, 'tooltip opened'); - assert.equal(window.google.openInfoWindowOptions.mapSpecified, true, 'tooltip opened with specified map'); - assert.equal(window.google.openInfoWindowOptions.markerSpecified, true, 'tooltip opened with specified marker'); + assert.equal(window.google.markerOptions.icon, markerIconSrc, 'icon src was passed to marker config'); done(); } - }); + }).dxMap('instance'); }); -QUnit.test('marker icon', function(assert) { +QUnit.test('icon should be undefined in marker config if markerIconSrc and marker.iconSrc were both not specified', function(assert) { const done = assert.async(); - const d1 = $.Deferred(); - const d2 = $.Deferred(); - - const markerUrl1 = 'http://example.com/1.png'; - const markerUrl2 = 'http://example.com/2.png'; - const $map = $('#map').dxMap({ + $('#map').dxMap({ provider: 'google', markers: [MARKERS[0]], - markerIconSrc: markerUrl1, onReady: function() { - assert.equal(window.google.markerOptions.icon, markerUrl1, 'marker options contains custom icon url'); - d1.resolve(); - } - }); - const map = $map.dxMap('instance'); + assert.equal(window.google.markerOptions.icon, undefined, 'tooltip options specified'); - d1.done(function() { - map.addMarker([$.extend({ iconSrc: markerUrl2 }, MARKERS[1]), MARKERS[2]]).done(function(instances) { - assert.equal(instances[0].getIcon(), markerUrl2, 'marker instance contains custom icon url'); - assert.equal(instances[1].getIcon(), markerUrl1, 'marker instance contains custom icon url'); + done(); + } + }).dxMap('instance'); +}); - d2.resolve(); +[ + { + name: 'old marker', + useAdvancedMarkers: false, + }, + { + name: 'advanced marker', + useAdvancedMarkers: true, + } +].forEach(({ name, useAdvancedMarkers }) => { + QUnit.test(`${name}s`, function(assert) { + const done = assert.async(); + const d = $.Deferred(); + + const $map = $('#map').dxMap({ + provider: 'google', + markers: [MARKERS[0]], + providerConfig: { + useAdvancedMarkers, + }, + onReady: function() { + assert.strictEqual(window.google.markerType, useAdvancedMarkers ? 'advanced' : 'old', 'marker has correct type'); + assert.strictEqual(window.google.markerOptionsSpecified, true, 'marker options specified'); + assert.strictEqual(window.google.markerOptions.mapSpecified, true, 'map specified correctly'); + assert.deepEqual(window.google.markerOptions.position, new google.maps.LatLng(MARKERS[0].location.lat, MARKERS[0].location.lng), 'location specified correctly'); + assert.strictEqual(window.google.infoWindowOpened, 1, 'tooltip is opened'); + + d.resolve(); + } }); - }); + const map = $map.dxMap('instance'); - d2.done(function() { - map.option('markerIconSrc', markerUrl2); + d.done(function() { + map.option('onUpdated', function() { + assert.equal(window.google.markerInstance, 3, 'markers changed'); + assert.equal(window.google.markerRemoved, true, 'previous marker removed'); + assert.equal(window.google.clickHandlerRemoved, true, 'previous marker handler removed'); - map.addMarker(MARKERS[3]).done(function(instance) { - assert.equal(instance.getIcon(), markerUrl2, 'marker instance contains custom icon url'); + done(); + }); - done(); + map.option('markers', [MARKERS[1], MARKERS[2]]); }); }); -}); - -QUnit.test('marker html', function(assert) { - const done = assert.async(); - const d = $.Deferred(); - - const $map = $('#map').dxMap({ - provider: 'google', - markers: [MARKERS[5]], - onReady: function() { - assert.equal(window.google.markerInstance, 0, 'markers not present'); - assert.equal(window.google.overlayInstance, 1, 'overlay created'); - const overlay = $(window.google.overlayMouseTarget).children(); - assert.equal(overlay.length, 1, 'overlay created'); - assert.deepEqual(window.google.overlayProjectedLocation, new google.maps.LatLng(MARKERS[5].location.lat, MARKERS[5].location.lng), 'correct location projected'); - assert.equal(overlay.css('top'), '200px', 'overlay created'); - assert.equal(overlay.css('left'), '100px', 'overlay created'); + QUnit.test(`${name}'s tooltip options`, function(assert) { + const done = assert.async(); + const d = $.Deferred(); + + const $map = $('#map').dxMap({ + provider: 'google', + markers: [MARKERS[0]], + providerConfig: { + useAdvancedMarkers, + }, + onReady: function() { + assert.strictEqual(window.google.markerType, useAdvancedMarkers ? 'advanced' : 'old', 'marker has correct type'); + assert.equal(window.google.infoWindowOptionsSpecified, true, 'tooltip options specified'); + assert.equal(window.google.infoWindowOptions.content, 'A', 'tooltip content specified'); + assert.equal(window.google.openInfoWindowOptions.mapSpecified, true, 'tooltip opened with specified map'); + assert.equal(window.google.openInfoWindowOptions.markerSpecified, true, 'tooltip opened with specified marker'); + assert.equal(window.google.infoWindowOpened, 1, 'tooltip opened'); + + d.resolve(); + } + }); + const map = $map.dxMap('instance'); - d.resolve(); - } - }); - const map = $map.dxMap('instance'); + d.done(function() { + map.option('onUpdated', function() { + assert.equal(window.google.infoWindowOptions.content, 'B', 'tooltip content specified'); + assert.equal(window.google.infoWindowOpened, 1, 'tooltip is not opened'); - d.done(function() { - map.removeMarker(MARKERS[5]).done(function() { - assert.equal(window.google.overlayRemoved, true, 'marker removed'); + done(); + }); - done(); + map.option('markers', [MARKERS[1]]); }); }); -}); -QUnit.test('marker html offset', function(assert) { - const done = assert.async(); - $('#map').dxMap({ - provider: 'google', - markers: [MARKERS[6]], - onReady: function() { - const overlay = $(window.google.overlayMouseTarget).children(); - assert.equal(overlay.css('top'), '215px', 'offset applied'); - assert.equal(overlay.css('left'), '125px', 'offset applied'); - done(); - } - }); + QUnit.test(`${name} integration`, function(assert) { + const done = assert.async(); + let clickFired = 0; + const marker = { + tooltip: 'A', + location: [40.537102, -73.990318], + onClick: function(e) { + assert.deepEqual(e.location, { lat: 40.537102, lng: -73.990318 }, 'markers location set'); + clickFired++; + } + }; -}); + $('#map').dxMap({ + provider: 'google', + markers: [marker], + providerConfig: { + useAdvancedMarkers, + }, + onReady: function() { + assert.strictEqual(window.google.markerType, useAdvancedMarkers ? 'advanced' : 'old', 'marker has correct type'); + assert.equal(window.google.infoWindowOptionsSpecified, true, 'tooltip options specified'); + assert.equal(window.google.infoWindowOptions.content, 'A', 'tooltip content specified'); + window.google.clickActionCallback(); + assert.equal(clickFired, 1, 'click action fired'); + assert.equal(window.google.infoWindowOpened, 1, 'tooltip opened'); + assert.equal(window.google.openInfoWindowOptions.mapSpecified, true, 'tooltip opened with specified map'); + assert.equal(window.google.openInfoWindowOptions.markerSpecified, true, 'tooltip opened with specified marker'); -QUnit.test('marker html interaction', function(assert) { - assert.expect(3); + done(); + } + }); + }); - const done = assert.async(); - const d = $.Deferred(); + QUnit.test(`${name} icon`, function(assert) { + const done = assert.async(); + const d1 = $.Deferred(); + const d2 = $.Deferred(); + + const markerUrl1 = 'http://example.com/1.png'; + const markerUrl2 = 'http://example.com/2.png'; + + const $map = $('#map').dxMap({ + provider: 'google', + markers: [MARKERS[0]], + providerConfig: { + useAdvancedMarkers, + }, + markerIconSrc: markerUrl1, + onReady: function() { + assert.equal(window.google.markerOptions.icon, markerUrl1, `${name} options contains custom icon url`); + d1.resolve(); + } + }); + const map = $map.dxMap('instance'); - const marker = $.extend({ - onClick: function() { - assert.ok(true, 'click handled'); - } - }, MARKERS[5]); + d1.done(function() { + map.addMarker([$.extend({ iconSrc: markerUrl2, }, MARKERS[1]), MARKERS[2]]).done(function(instances) { + assert.equal(instances[0].getIcon(), markerUrl2, `${name} instance contains custom icon url`); + assert.equal(instances[1].getIcon(), markerUrl1, `${name} instance contains custom icon url`); - const $map = $('#map').dxMap({ - provider: 'google', - markers: [marker], - onReady: function() { - window.google.domClickActionCallback({ - preventDefault: function() { - assert.ok(true, 'default prevented'); - } + d2.resolve(); }); + }); - d.resolve(); - } - }); - const map = $map.dxMap('instance'); + d2.done(function() { + map.option('markerIconSrc', markerUrl2); - d.done(function() { - map.removeMarker(marker).done(function() { - assert.equal(window.google.domClickHandlerRemoved, true, 'click listener removed'); + map.addMarker(MARKERS[3]).done(function(instance) { + assert.equal(instance.getIcon(), markerUrl2, `${name} instance contains custom icon url`); - done(); + done(); + }); }); }); -}); -QUnit.test('add marker', function(assert) { - const done = assert.async(); - const d = $.Deferred(); + QUnit.test(`marker html (useAdvancedMarkers=${useAdvancedMarkers})`, function(assert) { + const done = assert.async(); + const d = $.Deferred(); - const $map = $('#map').dxMap({ - provider: 'google', - markers: [MARKERS[0]], - onReady: function() { - d.resolve(); - } - }); - const map = $map.dxMap('instance'); - - d.done(function() { - map.addMarker(MARKERS[1]).done(function(instance) { - assert.ok(!window.google.markerRemoved, 'previous marker does not removed'); + const $map = $('#map').dxMap({ + provider: 'google', + markers: [MARKERS[5]], + providerConfig: { + useAdvancedMarkers, + }, + onReady: function() { + assert.equal(window.google.markerInstance, 0, `${name}s not present`); - assert.deepEqual(window.google.markerOptions.position, new google.maps.LatLng(MARKERS[0].location.lat, MARKERS[0].location.lng), 'marker created with correct location'); - assert.ok(instance instanceof google.maps.Marker, 'marker instance returned'); + assert.equal(window.google.overlayInstance, 1, 'overlay created'); + const overlay = $(window.google.overlayMouseTarget).children(); + assert.equal(overlay.length, 1, 'overlay created'); + assert.deepEqual(window.google.overlayProjectedLocation, new google.maps.LatLng(MARKERS[5].location.lat, MARKERS[5].location.lng), 'correct location projected'); + assert.equal(overlay.css('top'), '200px', 'overlay created'); + assert.equal(overlay.css('left'), '100px', 'overlay created'); - done(); + d.resolve(); + } }); - }); -}); + const map = $map.dxMap('instance'); -QUnit.test('add marker should extend bounds', function(assert) { - const done = assert.async(); - const d = $.Deferred(); + d.done(function() { + map.removeMarker(MARKERS[5]).done(function() { + assert.equal(window.google.overlayRemoved, true, `${name} removed`); - const $map = $('#map').dxMap({ - provider: 'google', - markers: [MARKERS[0]], - onReady: function() { - assert.equal(window.google.LatLngBoundsPoints.length, 1, 'extended by 1 location'); - assert.deepEqual(window.google.LatLngBoundsPoints[0], new google.maps.LatLng(MARKERS[0].location.lat, MARKERS[0].location.lng), 'bound extended correctly'); - assert.deepEqual(window.google.LatLngBoundsPoints, google.fittedBounds._points, 'map fitted correctly'); + done(); + }); + }); + }); - d.resolve(); - } + QUnit.test(`marker html offset (useAdvancedMarkers=${useAdvancedMarkers})`, function(assert) { + const done = assert.async(); + $('#map').dxMap({ + provider: 'google', + markers: [MARKERS[6]], + providerConfig: { + useAdvancedMarkers, + }, + onReady: function() { + const overlay = $(window.google.overlayMouseTarget).children(); + assert.equal(overlay.css('top'), '215px', 'offset applied'); + assert.equal(overlay.css('left'), '125px', 'offset applied'); + done(); + } + }); }); - const map = $map.dxMap('instance'); - d.done(function() { - map.option('onUpdated', function() { - assert.equal(window.google.LatLngBoundsPoints.length, 2, 'extended by 2 locations after changing markers'); + QUnit.test(`marker html interaction (useAdvancedMarkers=${useAdvancedMarkers})`, function(assert) { + assert.expect(3); - done(); - }); + const done = assert.async(); + const d = $.Deferred(); - map.addMarker(MARKERS[1]); - }); -}); + const marker = $.extend({ + onClick: function() { + assert.ok(true, 'click handled'); + } + }, MARKERS[5]); + + const $map = $('#map').dxMap({ + provider: 'google', + markers: [marker], + providerConfig: { + useAdvancedMarkers, + }, + onReady: function() { + window.google.domClickActionCallback({ + preventDefault: function() { + assert.ok(true, 'default prevented'); + } + }); -QUnit.test('add marker should extend visible bounds if autoAdjust = true', function(assert) { - const done = assert.async(); - const d = $.Deferred(); + d.resolve(); + } + }); + const map = $map.dxMap('instance'); - const $map = $('#map').dxMap({ - provider: 'google', - markers: [MARKERS[0]], - autoAdjust: true, - onReady: function() { - assert.equal(window.google.boundsFittedCount, 1, 'bounds fitted'); + d.done(function() { + map.removeMarker(marker).done(function() { + assert.equal(window.google.domClickHandlerRemoved, true, 'click listener removed'); - d.resolve(); - } + done(); + }); + }); }); - const map = $map.dxMap('instance'); - d.done(function() { - map.option('onUpdated', function() { - assert.equal(window.google.boundsFittedCount, 2, 'bounds fitted again'); + QUnit.test(`add ${name}`, function(assert) { + const done = assert.async(); + const d = $.Deferred(); - done(); + const $map = $('#map').dxMap({ + provider: 'google', + markers: [MARKERS[0]], + providerConfig: { + useAdvancedMarkers, + }, + onReady: function() { + d.resolve(); + } }); + const map = $map.dxMap('instance'); - map.addMarker(MARKERS[1]); - }); -}); + d.done(function() { + map.addMarker(MARKERS[1]).done(function(instance) { + assert.ok(!window.google.markerRemoved, `previous ${name} does not removed`); -QUnit.test('add marker should not extend visible bounds if autoAdjust = false', function(assert) { - const done = assert.async(); - const d = $.Deferred(); - - const $map = $('#map').dxMap({ - provider: 'google', - markers: [MARKERS[0]], - autoAdjust: false, - onReady: function() { - assert.equal(window.google.boundsFittedCount, 0, 'bounds not fitted'); + assert.deepEqual(window.google.markerOptions.position, new google.maps.LatLng(MARKERS[0].location.lat, MARKERS[0].location.lng), `${name} created with correct location`); + const expectedInstance = useAdvancedMarkers ? google.maps.marker.AdvancedMarkerElement : google.maps.Marker; + assert.ok(instance instanceof expectedInstance, `${name} instance returned`); - d.resolve(); - } + done(); + }); + }); }); - const map = $map.dxMap('instance'); - d.done(function() { - map.option('onUpdated', function() { - assert.equal(window.google.boundsFittedCount, 0, 'bounds not fitted again'); + QUnit.test(`add ${name} should extend bounds`, function(assert) { + const done = assert.async(); + const d = $.Deferred(); - done(); + const $map = $('#map').dxMap({ + provider: 'google', + markers: [MARKERS[0]], + providerConfig: { + useAdvancedMarkers: false, + }, + onReady: function() { + assert.equal(window.google.LatLngBoundsPoints.length, 1, 'extended by 1 location'); + assert.deepEqual(window.google.LatLngBoundsPoints[0], new google.maps.LatLng(MARKERS[0].location.lat, MARKERS[0].location.lng), 'bound extended correctly'); + assert.deepEqual(window.google.LatLngBoundsPoints, google.fittedBounds._points, 'map fitted correctly'); + + d.resolve(); + } }); + const map = $map.dxMap('instance'); - map.addMarker(MARKERS[1]); - }); -}); + d.done(function() { + map.option('onUpdated', function() { + assert.equal(window.google.LatLngBoundsPoints.length, 2, 'extended by 2 locations after changing markers'); -QUnit.test('add markers', function(assert) { - const done = assert.async(); - const d = $.Deferred(); + done(); + }); - const $map = $('#map').dxMap({ - provider: 'google', - onReady: function() { - d.resolve(); - } + map.addMarker(MARKERS[1]); + }); }); - const map = $map.dxMap('instance'); - d.done(function() { - map.addMarker([MARKERS[0], MARKERS[1]]).done(function(instances) { - assert.ok(instances[0] instanceof google.maps.Marker, 'marker instance returned'); - assert.ok(instances[1] instanceof google.maps.Marker, 'marker instance returned'); + QUnit.test(`add ${name} should extend visible bounds if autoAdjust = true`, function(assert) { + const done = assert.async(); + const d = $.Deferred(); - done(); + const $map = $('#map').dxMap({ + provider: 'google', + markers: [MARKERS[0]], + providerConfig: { + useAdvancedMarkers, + }, + autoAdjust: true, + onReady: function() { + assert.equal(window.google.boundsFittedCount, 1, 'bounds fitted'); + + d.resolve(); + } }); - }); -}); + const map = $map.dxMap('instance'); -QUnit.test('remove marker', function(assert) { - const done = assert.async(); - const d = $.Deferred(); + d.done(function() { + map.option('onUpdated', function() { + assert.equal(window.google.boundsFittedCount, 2, 'bounds fitted again'); - const $map = $('#map').dxMap({ - provider: 'google', - markers: [MARKERS[0]], - onReady: function() { - d.resolve(); - } - }); - const map = $map.dxMap('instance'); - - d.done(function() { - map.removeMarker(0).done(function() { - assert.equal(window.google.markerRemoved, true, 'marker removed'); - assert.equal(window.google.clickHandlerRemoved, true, 'previous marker handler removed'); + done(); + }); - done(); + map.addMarker(MARKERS[1]); }); }); -}); -QUnit.test('markerAdded', function(assert) { - const done = assert.async(); - let markerAddedFired = 0; + QUnit.test(`add ${name} should not extend visible bounds if autoAdjust = false`, function(assert) { + const done = assert.async(); + const d = $.Deferred(); - $('#map').dxMap({ - provider: 'google', - markers: [MARKERS[0]], - onMarkerAdded: function(args) { - assert.equal(args.options, MARKERS[0], 'correct options passed as parameter'); - assert.ok(args.originalMarker instanceof google.maps.Marker, 'marker instance returned'); - markerAddedFired++; - }, - onReady: function() { - assert.equal(markerAddedFired, 1, 'markerAdded fired'); + const $map = $('#map').dxMap({ + provider: 'google', + markers: [MARKERS[0]], + providerConfig: { + useAdvancedMarkers, + }, + autoAdjust: false, + onReady: function() { + assert.equal(window.google.boundsFittedCount, 0, 'bounds not fitted'); - done(); - } - }); -}); + d.resolve(); + } + }); + const map = $map.dxMap('instance'); -QUnit.test('markerRemoved', function(assert) { - const done = assert.async(); - const d = $.Deferred(); + d.done(function() { + map.option('onUpdated', function() { + assert.equal(window.google.boundsFittedCount, 0, 'bounds not fitted again'); - let markerRemovedFired = 0; + done(); + }); - const $map = $('#map').dxMap({ - provider: 'google', - markers: [MARKERS[0]], - onMarkerRemoved: function(args) { - assert.equal(args.options, MARKERS[0], 'correct options passed as parameter'); - markerRemovedFired++; - }, - onReady: function() { - d.resolve(); - } + map.addMarker(MARKERS[1]); + }); }); - const map = $map.dxMap('instance'); - d.done(function() { - map.option('onUpdated', function() { - assert.equal(markerRemovedFired, 1, 'markerRemoved fired'); + QUnit.test(`add ${name}s`, function(assert) { + const done = assert.async(); + const d = $.Deferred(); - done(); + const $map = $('#map').dxMap({ + provider: 'google', + providerConfig: { + useAdvancedMarkers, + }, + onReady: function() { + d.resolve(); + } }); + const map = $map.dxMap('instance'); + + d.done(function() { + map.addMarker([MARKERS[0], MARKERS[1]]).done(function(instances) { + const expectedInstance = useAdvancedMarkers ? google.maps.marker.AdvancedMarkerElement : google.maps.Marker; + assert.ok(instances[0] instanceof expectedInstance, 'marker instance returned'); + assert.ok(instances[1] instanceof expectedInstance, 'marker instance returned'); - map.option('markers', []); + done(); + }); + }); }); -}); -QUnit.test('autoAdjust', function(assert) { - const done = assert.async(); - const d = $.Deferred(); + QUnit.test(`remove ${name}`, function(assert) { + const done = assert.async(); + const d = $.Deferred(); - const $map = $('#map').dxMap({ - provider: 'google', - markers: [MARKERS[0]], - autoAdjust: false, - onReady: function() { - assert.equal(window.google.boundsFittedCount, 0, 'bounds not fitted'); + const $map = $('#map').dxMap({ + provider: 'google', + markers: [MARKERS[0]], + providerConfig: { + useAdvancedMarkers, + }, + onReady: function() { + d.resolve(); + } + }); + const map = $map.dxMap('instance'); - d.resolve(); - } + d.done(function() { + map.removeMarker(0).done(function() { + assert.equal(window.google.markerRemoved, true, 'marker removed'); + assert.equal(window.google.clickHandlerRemoved, true, 'previous marker handler removed'); + + done(); + }); + }); }); - const map = $map.dxMap('instance'); - d.done(function() { - map.option('onUpdated', function() { - assert.equal(window.google.boundsFittedCount, 1, 'bounds fitted'); + QUnit.test(`markerAdded (${name})`, function(assert) { + const done = assert.async(); + let markerAddedFired = 0; + + $('#map').dxMap({ + provider: 'google', + markers: [MARKERS[0]], + providerConfig: { + useAdvancedMarkers, + }, + onMarkerAdded: function(args) { + const expectedInstance = useAdvancedMarkers ? google.maps.marker.AdvancedMarkerElement : google.maps.Marker; + assert.equal(args.options, MARKERS[0], 'correct options passed as parameter'); + assert.ok(args.originalMarker instanceof expectedInstance, 'marker instance returned'); + markerAddedFired++; + }, + onReady: function() { + assert.equal(markerAddedFired, 1, 'markerAdded fired'); - done(); + done(); + } }); - - map.option('autoAdjust', true); }); -}); -QUnit.test('autoAdjust should not change zoom if marker is fitted', function(assert) { - const done = assert.async(); - const d = $.Deferred(); + QUnit.test(`markerRemoved (${name})`, function(assert) { + const done = assert.async(); + const d = $.Deferred(); + + let markerRemovedFired = 0; + + const $map = $('#map').dxMap({ + provider: 'google', + markers: [MARKERS[0]], + providerConfig: { + useAdvancedMarkers, + }, + onMarkerRemoved: function(args) { + assert.equal(args.options, MARKERS[0], 'correct options passed as parameter'); + markerRemovedFired++; + }, + onReady: function() { + d.resolve(); + } + }); + const map = $map.dxMap('instance'); - const $map = $('#map').dxMap({ - provider: 'google', - markers: [MARKERS[0]], - autoAdjust: false, - zoom: 5, - onReady: function() { - window.google.zoomValue = 5; - window.google.fitBoundsCallback = function() { - window.google.zoomValue = 10; - window.google.maps.event.trigger(null, 'bounds_changed'); - }; + d.done(function() { + map.option('onUpdated', function() { + assert.equal(markerRemovedFired, 1, 'markerRemoved fired'); - d.resolve(); - } + done(); + }); + + map.option('markers', []); + }); }); - const map = $map.dxMap('instance'); - d.done(function() { - map.option('onUpdated', function() { - assert.equal(window.google.boundsFittedCount, 1, 'bounds fitted'); - assert.equal(map.option('zoom'), 5, 'zoom not changed'); - assert.equal(window.google.assignedZoom, 5, 'zoom returned back'); + QUnit.test(`autoAdjust (${name})`, function(assert) { + const done = assert.async(); + const d = $.Deferred(); - window.google.fitBoundsCallback = null; - done(); + const $map = $('#map').dxMap({ + provider: 'google', + markers: [MARKERS[0]], + providerConfig: { + useAdvancedMarkers, + }, + autoAdjust: false, + onReady: function() { + assert.equal(window.google.boundsFittedCount, 0, 'bounds not fitted'); + + d.resolve(); + } }); + const map = $map.dxMap('instance'); - map.option('autoAdjust', true); + d.done(function() { + map.option('onUpdated', function() { + assert.equal(window.google.boundsFittedCount, 1, 'bounds fitted'); + + done(); + }); + + map.option('autoAdjust', true); + }); }); -}); -QUnit.test('autoAdjust should change zoom if marker is not fitted', function(assert) { - const done = assert.async(); - const d = $.Deferred(); + QUnit.test(`autoAdjust should not change zoom if ${name} is fitted`, function(assert) { + const done = assert.async(); + const d = $.Deferred(); - const $map = $('#map').dxMap({ - provider: 'google', - markers: [MARKERS[0]], - autoAdjust: false, - zoom: 10, - onReady: function() { - window.google.zoomValue = 10; - window.google.fitBoundsCallback = function() { + const $map = $('#map').dxMap({ + provider: 'google', + markers: [MARKERS[0]], + providerConfig: { + useAdvancedMarkers, + }, + autoAdjust: false, + zoom: 5, + onReady: function() { window.google.zoomValue = 5; - window.google.maps.event.trigger(null, 'bounds_changed'); - }; + window.google.fitBoundsCallback = function() { + window.google.zoomValue = 10; + window.google.maps.event.trigger(null, 'bounds_changed'); + }; - d.resolve(); - } + d.resolve(); + } + }); + const map = $map.dxMap('instance'); + + d.done(function() { + map.option('onUpdated', function() { + assert.equal(window.google.boundsFittedCount, 1, 'bounds fitted'); + assert.equal(map.option('zoom'), 5, 'zoom not changed'); + assert.equal(window.google.assignedZoom, 5, 'zoom returned back'); + + window.google.fitBoundsCallback = null; + done(); + }); + + map.option('autoAdjust', true); + }); }); - const map = $map.dxMap('instance'); - d.done(function() { - map.option('onUpdated', function() { - assert.equal(window.google.boundsFittedCount, 1, 'bounds fitted'); - assert.equal(map.option('zoom'), 5, 'zoom changed'); + QUnit.test(`autoAdjust should change zoom if ${name} is not fitted`, function(assert) { + const done = assert.async(); + const d = $.Deferred(); - window.google.fitBoundsCallback = null; - done(); + const $map = $('#map').dxMap({ + provider: 'google', + markers: [MARKERS[0]], + providerConfig: { + useAdvancedMarkers, + }, + autoAdjust: false, + zoom: 10, + onReady: function() { + window.google.zoomValue = 10; + window.google.fitBoundsCallback = function() { + window.google.zoomValue = 5; + window.google.maps.event.trigger(null, 'bounds_changed'); + }; + + d.resolve(); + } }); + const map = $map.dxMap('instance'); - map.option('autoAdjust', true); - }); -}); + d.done(function() { + map.option('onUpdated', function() { + assert.equal(window.google.boundsFittedCount, 1, 'bounds fitted'); + assert.equal(map.option('zoom'), 5, 'zoom changed'); -QUnit.test('autoAdjust should not prevent zoom changing', function(assert) { - const done = assert.async(); - const d = $.Deferred(); + window.google.fitBoundsCallback = null; + done(); + }); - const $map = $('#map').dxMap({ - provider: 'google', - markers: [MARKERS[0]], - autoAdjust: false, - zoom: 5, - onReady: function() { - d.resolve(); - } + map.option('autoAdjust', true); + }); }); - const map = $map.dxMap('instance'); - d.done(function() { - map.option('onUpdated', function() { - window.google.zoomValue = 10; - window.google.maps.event.trigger(null, 'bounds_changed'); - assert.equal(map.option('zoom'), 10, 'zoom change prevention is removed'); - - done(); + QUnit.test(`autoAdjust should not prevent zoom changing (${name})`, function(assert) { + const done = assert.async(); + const d = $.Deferred(); + + const $map = $('#map').dxMap({ + provider: 'google', + markers: [MARKERS[0]], + providerConfig: { + useAdvancedMarkers, + }, + autoAdjust: false, + zoom: 5, + onReady: function() { + d.resolve(); + } }); + const map = $map.dxMap('instance'); - map.option('autoAdjust', true); + d.done(function() { + map.option('onUpdated', function() { + window.google.zoomValue = 10; + window.google.maps.event.trigger(null, 'bounds_changed'); + assert.equal(map.option('zoom'), 10, 'zoom change prevention is removed'); + + done(); + }); + + map.option('autoAdjust', true); + }); }); });