diff --git a/src/api/iframeFeatureEvent.api.js b/src/api/iframeFeatureEvent.api.js
index 5f14753ac..482765e4a 100644
--- a/src/api/iframeFeatureEvent.api.js
+++ b/src/api/iframeFeatureEvent.api.js
@@ -1,4 +1,27 @@
-import log from '@/utils/logging.js'
+import log from '@/utils/logging'
+
+const targetWindow = parent ?? window.parent ?? window.opener ?? window.top
+
+/**
+ * All events fired by the iFrame postMessage implementation.
+ *
+ * @enum
+ */
+export const IFRAME_EVENTS = {
+ /**
+ * Event raised whenever the app changes its state (the URL changed).
+ *
+ * Payload of this event : a String with the new URL of the viewer
+ */
+ CHANGE: 'gaChange',
+ /**
+ * Event raised when a feature has been selected. Will fire as many events as there are feature
+ * selected on the map (won't bundle all features into one event)
+ *
+ * Payload of this event : a JSON containing the layerId and featureId of the selected feature
+ */
+ FEATURE_SELECTION: 'gaFeatureSelection',
+}
/**
* Sends information to the iFrame's parent about features, through the use of the postMessage
@@ -7,9 +30,9 @@ import log from '@/utils/logging.js'
* @param {LayerFeature[]} features List of features for which we want to send information to the
* iFrame's parent
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
+ * @see https://codepen.io/geoadmin/pen/yOBzqM?editors=0010
*/
export function sendFeatureInformationToIFrameParent(features) {
- const targetWindow = parent ?? window.parent ?? window.opener ?? window.top
if (!targetWindow) {
log.debug(
'Embed view loaded as root document of a browser tab, cannot communicate with opener/parent'
@@ -26,7 +49,7 @@ export function sendFeatureInformationToIFrameParent(features) {
targetWindow.postMessage(
{
// see codepen above, for backward compatibility reasons we need to use the same type as mf-geoadmin3
- type: 'gaFeatureSelection',
+ type: IFRAME_EVENTS.FEATURE_SELECTION,
payload: {
layerId: feature.layer.id,
featureId: feature.id,
@@ -43,3 +66,29 @@ export function sendFeatureInformationToIFrameParent(features) {
// so let's not implement this format in the new viewer and see what happens.
})
}
+
+/**
+ * Is used to notify the parent the state of the app has changed. While embedding with VueJS, it's
+ * not possible to watch the iFrame src attribute, so an event is required to be notified of a
+ * children change.
+ *
+ * This is mainly used so that the iframe generator (menu share -> embed) can change the iframe
+ * snippet if the user decide to move / zoom the map while looking at the preview
+ */
+export function sendChangeEventToParent() {
+ if (!targetWindow) {
+ log.debug(
+ 'Embed view loaded as root document of a browser tab, cannot communicate with opener/parent'
+ )
+ return
+ }
+ targetWindow.postMessage(
+ {
+ type: IFRAME_EVENTS.CHANGE,
+ payload: {
+ newUrl: window.location.href,
+ },
+ },
+ '*'
+ )
+}
diff --git a/src/modules/menu/components/share/MenuShareEmbed.vue b/src/modules/menu/components/share/MenuShareEmbed.vue
index c1af4bea1..5adbd4a5b 100644
--- a/src/modules/menu/components/share/MenuShareEmbed.vue
+++ b/src/modules/menu/components/share/MenuShareEmbed.vue
@@ -9,12 +9,16 @@
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
// importing directly the vue component, see https://github.com/ivanvermeyen/vue-collapse-transition/issues/5
import CollapseTransition from '@ivanv/vue-collapse-transition/src/CollapseTransition.vue'
-import { computed, nextTick, ref, toRefs } from 'vue'
+import { computed, nextTick, ref, watch } from 'vue'
+import { useI18n } from 'vue-i18n'
+import { useRoute } from 'vue-router'
+import { IFRAME_EVENTS } from '@/api/iframeFeatureEvent.api'
import MenuShareInputCopyButton from '@/modules/menu/components/share/MenuShareInputCopyButton.vue'
import ModalWithBackdrop from '@/utils/components/ModalWithBackdrop.vue'
import { useTippyTooltip } from '@/utils/composables/useTippyTooltip'
import log from '@/utils/logging'
+import { transformUrlMapToEmbed } from '@/utils/utils'
/**
* Different pre-defined sizes that an iFrame can take
@@ -45,14 +49,6 @@ const EmbedSizes = {
useTippyTooltip('.menu-share-embed [data-tippy-content]')
-const props = defineProps({
- shortLink: {
- type: String,
- default: null,
- },
-})
-const { shortLink } = toRefs(props)
-
const embedInput = ref(null)
const showEmbedSharing = ref(false)
const showPreviewModal = ref(false)
@@ -64,6 +60,10 @@ const customSize = ref({
})
const copied = ref(false)
+const { t } = useI18n()
+const route = useRoute()
+
+const embedSource = ref(transformUrlMapToEmbed(window.location.href))
const embedPreviewModalWidth = computed(() => {
// Uses the iframe's width as maximal width for the entire modal window
let style = { 'max-width': iFrameWidth.value }
@@ -96,7 +96,7 @@ const iFrameStyle = computed(
)
const iFrameLink = computed(
() =>
- ``
+ ``
)
const buttonIcon = computed(() => {
if (copied.value) {
@@ -120,6 +120,18 @@ function toggleEmbedSharing() {
function togglePreviewModal() {
showPreviewModal.value = !showPreviewModal.value
+ if (showPreviewModal.value) {
+ window.addEventListener('message', onPreviewChange)
+ } else {
+ window.removeEventListener('message', onPreviewChange)
+ }
+}
+
+function onPreviewChange(e) {
+ if (e?.data?.type === IFRAME_EVENTS.CHANGE) {
+ // see iframeFeatureEvent.api.js -> sendChangeEventToParent
+ embedSource.value = e.data.payload.newUrl
+ }
}
async function copyValue() {
@@ -134,6 +146,13 @@ async function copyValue() {
log.error(`Failed to copy to clipboard:`, error)
}
}
+
+watch(
+ () => route.query,
+ () => {
+ embedSource.value = transformUrlMapToEmbed(window.location.href)
+ }
+)
@@ -149,7 +168,7 @@ async function copyValue() {
:class="{ 'text-primary': showEmbedSharing }"
:icon="`caret-${showEmbedSharing ? 'down' : 'right'}`"
/>
- {{ $t('share_more') }}
+ {{ t('share_more') }}