refactor du système de routing (EXPORTS DES SETTINGS DRUPAL)
This commit is contained in:
parent
74f099ebdd
commit
d5c5d81841
|
@ -0,0 +1,18 @@
|
|||
uuid: f904b753-75c5-477e-bd9c-7259f9bfdf9b
|
||||
langcode: fr
|
||||
status: false
|
||||
dependencies:
|
||||
module:
|
||||
- path_alias
|
||||
- serialization
|
||||
- user
|
||||
id: entity.path_alias
|
||||
plugin_id: 'entity:path_alias'
|
||||
granularity: resource
|
||||
configuration:
|
||||
methods:
|
||||
- GET
|
||||
formats:
|
||||
- json
|
||||
authentication:
|
||||
- cookie
|
|
@ -269,7 +269,7 @@ display:
|
|||
popupAnchor:
|
||||
x: ''
|
||||
'y': ''
|
||||
html: "<div></div>\r\n<div></div>\r\n<div></div>\r\n<div class=\"nid\">{{ nid }}</div>\r\n<div class=\"couleur\">{{ field_couleur }}</div>"
|
||||
html: "<div></div>\r\n<div></div>\r\n<div></div>\r\n<div class=\"url\">[node:url]</div>\r\n<div class=\"couleur\">[node:field_couleur]</div>"
|
||||
html_class: 'leaflet-map-divicon '
|
||||
circle_marker_options: '{"radius":100,"color":"red","fillColor":"#f03","fillOpacity":0.5}'
|
||||
leaflet_markercluster:
|
||||
|
|
|
@ -1,253 +1,49 @@
|
|||
import { createApp } from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
import { initVueContentModale } from './utils/vue-setup';
|
||||
import { processClickableElements } from './utils/process-clickable-elements';
|
||||
import { setMenuToggle, setHamburgerWhenLogged } from './utils/layout-setup';
|
||||
import { initFirstLoadRouting, handleClickableElements } from './utils/handle-navigation';
|
||||
import { setupMapStore } from './utils/map-setup';
|
||||
|
||||
import '../scss/main.scss'
|
||||
import Modale from './vuejs/Modale.vue'
|
||||
|
||||
import VueImageZoomer from 'vue-image-zoomer'
|
||||
import 'vue-image-zoomer/dist/style.css';
|
||||
|
||||
import { useContentStore } from './stores/content';
|
||||
import { useMapStore } from './stores/mapState';
|
||||
import router from './router/router';
|
||||
|
||||
// Working with the history API
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/History_API/Working_with_the_History_API
|
||||
|
||||
// /**
|
||||
// * @file
|
||||
// * reha behaviors.
|
||||
// * https://www.drupal.org/docs/drupal-apis/javascript-api/javascript-api-overview
|
||||
// */
|
||||
// (function (Drupal) {
|
||||
|
||||
// 'use strict';
|
||||
|
||||
// Drupal.behaviors.reha = {
|
||||
// attach: function (context, settings) {
|
||||
// console.log('It works!');
|
||||
// }
|
||||
// };
|
||||
|
||||
// } (Drupal));
|
||||
// https://www.drupal.org/docs/drupal-apis/javascript-api/javascript-api-overview
|
||||
|
||||
(function ($, Drupal, drupalSettings) {
|
||||
const CaravaneTheme = function () {
|
||||
const _is_front = drupalSettings.path.isFront;
|
||||
console.log('drupalSettings', drupalSettings);
|
||||
const CaravaneTheme = function () {
|
||||
function init () {
|
||||
console.log('DrupalSettings', drupalSettings);
|
||||
|
||||
function init () {
|
||||
console.log('CaravaneTheme init()');
|
||||
initVues();
|
||||
toggleMenu();
|
||||
}
|
||||
const baseUrl = window.location.protocol + "//" + window.location.host;
|
||||
const siteName = document.querySelector('#site_name').innerText;
|
||||
const { store, mapStore, router, route } = initVueContentModale();
|
||||
|
||||
function initVues(){
|
||||
initVueContentModale();
|
||||
setMenuToggle();
|
||||
setHamburgerWhenLogged(drupalSettings);
|
||||
|
||||
}
|
||||
// https://www.drupal.org/docs/extending-drupal/contributed-modules/contributed-module-documentation/leaflet/leaflet-api
|
||||
|
||||
function initVueContentModale(){
|
||||
const app = createApp(Modale)
|
||||
.use(createPinia()).use(router)
|
||||
.use(VueImageZoomer);
|
||||
const store = useContentStore();
|
||||
const mapStore = useMapStore();
|
||||
app.mount('#content-modale');
|
||||
Drupal.behaviors.customLeafletInteraction = {
|
||||
attach: function(context, settings) {
|
||||
$(context).on('leafletMapInit', function (e, settings, map, mapid, markers) {
|
||||
const {
|
||||
etapeListLinks,
|
||||
generalListLinks,
|
||||
logoLink,
|
||||
mapIcons,
|
||||
} = processClickableElements();
|
||||
const clickableElements = [...etapeListLinks, ...generalListLinks, logoLink, ...mapIcons];
|
||||
|
||||
setHamburgerWhenLogged();
|
||||
setupMapStore(mapStore, map, settings);
|
||||
|
||||
Drupal.behaviors.customLeafletInteraction = {
|
||||
attach: function(context, settings) {
|
||||
$(context).on('leafletMapInit', function (e, settings, map, mapid, markers) {
|
||||
mapStore.defaultMapCenter = map.getCenter();
|
||||
mapStore.maxZoom = settings.settings.maxZoom;
|
||||
mapStore.defaultZoom = settings.settings.minZoom;
|
||||
|
||||
initFirstLoadRouting(store, router, baseUrl, siteName);
|
||||
|
||||
initFirstLoadRouting(store, map);
|
||||
processEtapeLinks(store, map);
|
||||
processStaticLinks(store, map);
|
||||
processHeaderLogo(store, map);
|
||||
setupEtapeMapPopup(store, map);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initFirstLoadRouting(store, map){
|
||||
var decoupled_origin = JSON.parse(window.localStorage.getItem('decoupled_origin'));
|
||||
console.log('decoupled_origin', decoupled_origin);
|
||||
|
||||
|
||||
if(decoupled_origin && decoupled_origin.entity_id){
|
||||
// Si c'était moi je ne ferais qu'une seule function fetchdata capable de dealer avec les différent type de contenus
|
||||
switch (decoupled_origin.entity_bundle) {
|
||||
case 'etape':
|
||||
store.fetchEtapeData(decoupled_origin.entity_id, map);
|
||||
break;
|
||||
case 'static':
|
||||
store.fetchEtapeData(decoupled_origin.entity_id, map);
|
||||
break;
|
||||
handleClickableElements(clickableElements, store, router, baseUrl, siteName, mapStore);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
router.push({
|
||||
// name: decoupled_origin.entity_bundle,
|
||||
path: decoupled_origin.url,
|
||||
// params: {
|
||||
// title: decoupled_origin.entity_uuid
|
||||
// },
|
||||
// props: {
|
||||
// nid: decoupled_origin.entity_id
|
||||
// }
|
||||
});
|
||||
|
||||
// reset the storage
|
||||
window.localStorage.removeItem("decoupled_origin");
|
||||
}
|
||||
init()
|
||||
}
|
||||
|
||||
function onClickContentLink(e, store, map, category){
|
||||
e.preventDefault();
|
||||
let a;
|
||||
|
||||
if (e.target.tagName !== 'IMG') {
|
||||
const li = e.target.closest('li');
|
||||
a = li.querySelector('a');
|
||||
} else {
|
||||
a = e.target.closest('a');
|
||||
}
|
||||
|
||||
let nid = a.dataset.nid;
|
||||
|
||||
if (category === 'etape') {
|
||||
store.fetchEtapeData(nid, map);
|
||||
} else if (category === 'static') {
|
||||
if (nid) {
|
||||
store.fetchStaticData(nid, map);
|
||||
} else {
|
||||
store.emptyAll(null, map);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function processStaticLinks(store, map) {
|
||||
let general_link_fields = document.querySelectorAll('#menu > ul > li > a');
|
||||
for (let i =1; i < general_link_fields.length; i ++) {
|
||||
let general_link_path = general_link_fields[i].getAttribute('data-drupal-link-system-path');
|
||||
const match = [...general_link_path.match(/^node\/(\d+)$/)];
|
||||
if (match) {
|
||||
const nid = match[1];
|
||||
general_link_fields[i].setAttribute('data-nid', parseInt(nid));
|
||||
general_link_fields[i].addEventListener('click', (e) => onClickContentLink(e, store, map, 'static'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function processHeaderLogo(store, map) {
|
||||
const logo = document.querySelector('#block-caravane-logocaravane a');
|
||||
logo.addEventListener('click', (e) => onClickContentLink(e, store, map, 'static'));
|
||||
}
|
||||
|
||||
function processEtapeLinks(store, map) {
|
||||
let etape_li = document.querySelectorAll('#etapes-liste li');
|
||||
etape_li.forEach((li) => {
|
||||
let etape_link = li.querySelector('a.etape-link');
|
||||
let nid = etape_link.dataset.nid;
|
||||
|
||||
if (nid) {
|
||||
li.addEventListener('click', (e) => onClickContentLink(e, store, map, 'etape'));
|
||||
}
|
||||
let couleur = etape_link.dataset.couleur;
|
||||
let iconElements = li.querySelectorAll('.icone-arret > div');
|
||||
for (let element of iconElements) {
|
||||
element.style.backgroundColor = couleur;
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
function toggleMenu() {
|
||||
const menuButton = document.querySelector('#block-caravane-mainnavigation > #menu');
|
||||
const menuContainer = document.querySelector('#block-caravane-mainnavigation > #menu > ul');
|
||||
const menuTitle = document.querySelector('#menu-title');
|
||||
const menuBurger = document.querySelector('#hamburger');
|
||||
const menuH2 = document.querySelector('#menu > h2');
|
||||
menuButton.addEventListener('click', (e) => {
|
||||
setTimeout(() => {
|
||||
menuContainer.classList.toggle('open');
|
||||
menuTitle.classList.toggle('open');
|
||||
menuBurger.classList.toggle('open');
|
||||
menuH2.classList.toggle('open');
|
||||
}, 50);
|
||||
})
|
||||
document.addEventListener('click', (e) => {
|
||||
if (!menuContainer.contains(e.target) && !menuBurger.contains(e.target)) {
|
||||
menuContainer.classList.remove('open');
|
||||
menuTitle.classList.remove('open');
|
||||
menuBurger.classList.remove('open');
|
||||
menuH2.classList.remove('open');
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function setHamburgerWhenLogged() {
|
||||
if (drupalSettings.user.uid != 0) {
|
||||
const menuBurger = document.querySelector('#hamburger');
|
||||
const menuTitle = document.querySelector('#menu-title');
|
||||
const menuContainer = document.querySelector('#block-caravane-mainnavigation > #menu > ul');
|
||||
const header = document.querySelector('.dialog-off-canvas-main-canvas');
|
||||
const headerTop = header.getBoundingClientRect().top;
|
||||
|
||||
menuTitle.style.top = `${headerTop}px`;
|
||||
menuBurger.style.top = `${headerTop}px`;
|
||||
menuContainer.style.paddingTop = `${headerTop}px`;
|
||||
}
|
||||
}
|
||||
|
||||
function setupEtapeMapPopup(store, map) {
|
||||
const icons = document.querySelectorAll('.leaflet-map-divicon');
|
||||
for (let icon of icons) {
|
||||
const colorContainer = icon.querySelector('.couleur');
|
||||
let colorDivs = colorContainer.querySelectorAll('.separated-content');
|
||||
let color;
|
||||
colorDivs.forEach((div) => {
|
||||
if (div.innerText.startsWith('<div class="snippets-description">')) {
|
||||
color = div.innerText;
|
||||
}
|
||||
});
|
||||
color = color.substring(color.indexOf('>') + 1, color.indexOf('<', color.indexOf('>') + 1)).trim();
|
||||
|
||||
const nid = icon.querySelector('.nid');
|
||||
const nidValue = nid.querySelector('.separated-content').innerText;
|
||||
|
||||
icon.addEventListener('click', function(event) {
|
||||
store.fetchEtapeData(nidValue, map);
|
||||
});
|
||||
|
||||
colorContainer.style.display = "none";
|
||||
nid.style.display = "none";
|
||||
const iconElements = icon.querySelectorAll('div');
|
||||
for (let iconElement of iconElements) {
|
||||
iconElement.style.backgroundColor = color;
|
||||
}
|
||||
icon.removeAttribute('title');
|
||||
|
||||
icon.addEventListener('mouseenter', function (event) {
|
||||
icon.style.transform = `${icon.style.transform} scale(1.1)`;
|
||||
const popup = document.querySelector('.leaflet-tooltip-center > div');
|
||||
popup.style.opacity = "1";
|
||||
});
|
||||
|
||||
icon.addEventListener('mouseleave', function (event) {
|
||||
icon.style.transform = icon.style.transform.split(' ')[0] + icon.style.transform.split(' ')[1] + icon.style.transform.split(' ')[2];
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
init()
|
||||
} // end CaravaneTheme()
|
||||
|
||||
CaravaneTheme()
|
||||
CaravaneTheme()
|
||||
})(jQuery, Drupal, drupalSettings)
|
|
@ -6,6 +6,7 @@ if(drupalDecoupled.redirect){
|
|||
console.log('window.location', window.location);
|
||||
|
||||
drupalDecoupled.sys_path = drupalDecoupled.sys_path.replace(/^\//, '');
|
||||
|
||||
drupalDecoupled.url = window.location.pathname;
|
||||
drupalDecoupled.hash = window.location.hash;
|
||||
window.localStorage.setItem('decoupled_origin', JSON.stringify(drupalDecoupled));
|
||||
|
|
|
@ -2,17 +2,23 @@ import { createRouter, createWebHistory } from 'vue-router';
|
|||
import ModaleView from '../vuejs/Modale.vue';
|
||||
|
||||
const routes = [
|
||||
{
|
||||
/* {
|
||||
name: 'etape',
|
||||
path: '/etapes/:title?',
|
||||
component: ModaleView,
|
||||
props: {id: null}
|
||||
props: {id: null},
|
||||
},
|
||||
{
|
||||
name: 'home',
|
||||
path: '/',
|
||||
component: ModaleView
|
||||
component: ModaleView,
|
||||
},
|
||||
*/
|
||||
// Not much to do here nah ?
|
||||
{
|
||||
path: '/:catchAll(.*)',
|
||||
component: ModaleView,
|
||||
}
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
|
|
|
@ -5,33 +5,17 @@ import REST from '../api/rest-axios';
|
|||
|
||||
export const useContentStore = defineStore('content', {
|
||||
state: () => ({
|
||||
href: '',
|
||||
map: {},
|
||||
etape: {
|
||||
title: '',
|
||||
adresse: {},
|
||||
contentType: '',
|
||||
pageTitle: '',
|
||||
content: {
|
||||
contentTitle: '',
|
||||
coordinates: {},
|
||||
adresse: {},
|
||||
etape_number: '',
|
||||
vignette: {},
|
||||
couleur: '',
|
||||
previous: {},
|
||||
dates: {},
|
||||
previous : {},
|
||||
next: {},
|
||||
dates: {
|
||||
start: {
|
||||
d: '',
|
||||
m: '',
|
||||
y: '',
|
||||
},
|
||||
end: {
|
||||
d: '',
|
||||
m: '',
|
||||
y: '',
|
||||
},
|
||||
},
|
||||
parties: [],
|
||||
},
|
||||
page: {
|
||||
title: '',
|
||||
vignette: {},
|
||||
parties: [],
|
||||
},
|
||||
|
@ -39,320 +23,237 @@ export const useContentStore = defineStore('content', {
|
|||
error: null,
|
||||
}),
|
||||
actions: {
|
||||
async fetchEtapeData(nid, map) {
|
||||
this.resetStore();
|
||||
this.map = map;
|
||||
async fetchContentData(path) {
|
||||
this.resetStore(false);
|
||||
const contentTypes = [ 'etape', 'static' ];
|
||||
try {
|
||||
const response = await REST.get(`/jsonapi/node/etape/`);
|
||||
for (let etape of response.data.data) {
|
||||
if (etape.attributes.drupal_internal__nid == nid) {
|
||||
for (let metatag of etape.attributes.metatag) {
|
||||
if (metatag.tag === "link") {
|
||||
this.href = metatag.attributes.href;
|
||||
}
|
||||
}
|
||||
this.etape.coordinates = {
|
||||
lat: etape.attributes.field_geofield.lat,
|
||||
lon: etape.attributes.field_geofield.lon,
|
||||
};
|
||||
this.etape.title = etape.attributes.title;
|
||||
this.etape.adresse = etape.attributes.field_adresse;
|
||||
this.etape.etape_number = etape.attributes.field_arret_numero;
|
||||
const vignetteFetch = await this.fetchContent('field_vignette', etape.relationships);
|
||||
if (vignetteFetch) {
|
||||
this.etape.vignette = {
|
||||
url: vignetteFetch.attributes.uri.url,
|
||||
alt: etape.relationships.field_vignette.data.meta.alt
|
||||
};
|
||||
}
|
||||
this.etape.couleur = etape.attributes.field_couleur;
|
||||
let rawContent,
|
||||
contentType,
|
||||
response;
|
||||
|
||||
this.etape.dates = {
|
||||
start: this.getCleanDate(etape.attributes.field_dates.value),
|
||||
end: this.getCleanDate(etape.attributes.field_dates.end_value),
|
||||
}
|
||||
|
||||
const partiesFetch = await this.fetchContent('field_parties', etape.relationships);
|
||||
if (partiesFetch) {
|
||||
this.etape.parties = [];
|
||||
for (let partie of partiesFetch) {
|
||||
const partieType = partie.type.replace(/^paragraph--/, "");
|
||||
let partieContent = {
|
||||
type: partieType,
|
||||
};
|
||||
|
||||
switch (partieType) {
|
||||
case 'carte_sensible':
|
||||
const carteSensibleFetch = await this.fetchContent('field_image_carte', partie.relationships);
|
||||
if (carteSensibleFetch) {
|
||||
partieContent.carteSensible = {
|
||||
url: carteSensibleFetch.attributes.uri.url,
|
||||
alt: partie.relationships.field_image_carte.data.meta.alt,
|
||||
};
|
||||
}
|
||||
break;
|
||||
case 'titre_texte':
|
||||
partieContent.titre = partie.attributes.field_titre;
|
||||
partieContent.texte = partie.attributes.field_texte.value;
|
||||
break;
|
||||
case 'chiffres_cles':
|
||||
const chiffresClesFetch = await this.fetchContent('field_chiffres_clefs', partie.relationships);
|
||||
if (chiffresClesFetch) {
|
||||
partieContent.chiffresCles = [];
|
||||
for (let chiffre of chiffresClesFetch) {
|
||||
partieContent.chiffresCles.push({
|
||||
chiffre: chiffre.attributes.field_chiffre,
|
||||
description: chiffre.attributes.field_description,
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'diaporama':
|
||||
const diaporamaFetch = await this.fetchContent('field_diaporama', partie.relationships);
|
||||
if (diaporamaFetch) {
|
||||
partieContent.diaporama = [];
|
||||
for (let [index, image] of diaporamaFetch.entries()) {
|
||||
partieContent.diaporama.push({
|
||||
url: image.attributes.uri.url,
|
||||
alt: partie.relationships.field_diaporama.data[index].meta.alt,
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'entretien':
|
||||
partieContent.entretien = {};
|
||||
const personnesFetch = await this.fetchContent('field_personne_s', partie.relationships);
|
||||
const questionsReponsesFetch = await this.fetchContent('field_questions_reponses', partie.relationships);
|
||||
if (personnesFetch && questionsReponsesFetch) {
|
||||
partieContent.entretien.personnes = [];
|
||||
for (let personne of personnesFetch) {
|
||||
const portraitFetch = await this.fetchContent('field_portrait', personne.relationships);
|
||||
if (portraitFetch) {
|
||||
partieContent.entretien.personnes.push({
|
||||
portrait: portraitFetch.attributes.uri.url,
|
||||
alt: personne.relationships.field_portrait.data.meta.alt,
|
||||
description: personne.attributes.field_description,
|
||||
});
|
||||
}
|
||||
}
|
||||
partieContent.entretien.questionsReponses = [];
|
||||
for (let qr of questionsReponsesFetch) {
|
||||
partieContent.entretien.questionsReponses.push({
|
||||
question: qr.attributes.field_question,
|
||||
reponse: qr.attributes.field_reponse.value,
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'exergue':
|
||||
partieContent.exergue = partie.attributes.field_texte_exergue.value;
|
||||
break;
|
||||
case 'video':
|
||||
partieContent.videos = [];
|
||||
for (let video of partie.attributes.field_videos) {
|
||||
const videoId = video.split('?v=')[1];
|
||||
const videoUrl = `https://www.youtube.com/embed/${videoId}`;
|
||||
partieContent.videos.push(videoUrl);
|
||||
}
|
||||
break;
|
||||
}
|
||||
this.etape.parties.push(partieContent);
|
||||
}
|
||||
}
|
||||
|
||||
// get previous and next étape infos
|
||||
// the list from the json api /node is not ordered
|
||||
// and i need authentification to get the json view ordered list
|
||||
// so i get it from the displayed list in the page
|
||||
const orderedEtapesList = document.querySelectorAll('#etapes-liste li');
|
||||
|
||||
if (orderedEtapesList) {
|
||||
const processEtape = async (etapeItemNid, etapesList, key) => {
|
||||
for (let etape of etapesList) {
|
||||
if (etape.attributes.drupal_internal__nid == etapeItemNid) {
|
||||
const vignetteFetch = await REST.get(etape.relationships.field_vignette.links.related.href);
|
||||
this.etape[key] = {
|
||||
nid: etape.attributes.drupal_internal__nid,
|
||||
couleur: etape.attributes.field_couleur,
|
||||
title: etape.attributes.title,
|
||||
postalCode: etape.attributes.field_adresse.postal_code,
|
||||
dates: {
|
||||
start: this.getCleanDate(etape.attributes.field_dates.value),
|
||||
end: this.getCleanDate(etape.attributes.field_dates.end_value),
|
||||
},
|
||||
vignette: {
|
||||
url: vignetteFetch.data.data.attributes.uri.url,
|
||||
alt: etape.relationships.field_vignette.data.meta.alt,
|
||||
},
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (let li of orderedEtapesList) {
|
||||
if (li.querySelector('a').dataset.nodeNid == nid) {
|
||||
const previousEtapeItemNid = li.previousElementSibling?.querySelector('a').dataset.nodeNid;
|
||||
const nextEtapeItemNid = li.nextElementSibling?.querySelector('a').dataset.nodeNid;
|
||||
if (previousEtapeItemNid) {
|
||||
await processEtape(previousEtapeItemNid, response.data.data, 'previous');
|
||||
}
|
||||
if (nextEtapeItemNid) {
|
||||
await processEtape(nextEtapeItemNid, response.data.data, 'next');
|
||||
}
|
||||
}
|
||||
contentTypesLoop:
|
||||
for (let type of contentTypes) {
|
||||
response = await REST.get(`/jsonapi/node/${type}/`);
|
||||
for (let content of response.data.data) {
|
||||
for (let tag of content.attributes.metatag) {
|
||||
if (tag.tag === "link" && tag.attributes.href === path) {
|
||||
this.contentType = type;
|
||||
rawContent = content;
|
||||
contentType = type;
|
||||
break contentTypesLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// pageTitle
|
||||
for (let tag of rawContent.attributes.metatag) {
|
||||
if (tag.tag === "meta") {
|
||||
this.pageTitle = tag.attributes.content;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.setActiveItemInMenu(nid);
|
||||
// contentTitle
|
||||
this.content.contentTitle = rawContent.attributes.title;
|
||||
|
||||
// vignette
|
||||
const vignetteFetch = await this.fetchDeeperContent('field_vignette', rawContent.relationships);
|
||||
if (vignetteFetch) {
|
||||
this.content.vignette = {
|
||||
url: vignetteFetch.attributes.uri.url,
|
||||
alt: rawContent.relationships.field_vignette.data.meta.alt
|
||||
};
|
||||
}
|
||||
|
||||
if (contentType === 'etape') {
|
||||
// coordinates
|
||||
this.content.coordinates = {
|
||||
lat: rawContent.attributes.field_geofield.lat,
|
||||
lon: rawContent.attributes.field_geofield.lon,
|
||||
};
|
||||
// adresse
|
||||
this.content.adresse = rawContent.attributes.field_adresse;
|
||||
// étape number
|
||||
this.content.etape_number = rawContent.attributes.field_arret_numero;
|
||||
// couleur
|
||||
this.content.couleur = rawContent.attributes.field_couleur;
|
||||
// dates
|
||||
this.content.dates = {
|
||||
start: this.getCleanDate(rawContent.attributes.field_dates.value),
|
||||
end: this.getCleanDate(rawContent.attributes.field_dates.end_value),
|
||||
}
|
||||
// previous / next
|
||||
await this.getRelatedEtape('previous', response.data.data, path);
|
||||
await this.getRelatedEtape('next', response.data.data, path);
|
||||
}
|
||||
|
||||
// parties
|
||||
const fieldParties = contentType === 'etape' ? 'field_parties' : 'field_parties_static';
|
||||
const partiesFetch = await this.fetchDeeperContent(fieldParties, rawContent.relationships);
|
||||
|
||||
if (partiesFetch) {
|
||||
this.content.parties = [];
|
||||
for (let partie of partiesFetch) {
|
||||
const partieType = partie.type.replace(/^paragraph--/, "");
|
||||
let partieContent = {
|
||||
type: partieType,
|
||||
};
|
||||
|
||||
switch (partieType) {
|
||||
case 'carte_sensible':
|
||||
const carteSensibleFetch = await this.fetchDeeperContent('field_image_carte', partie.relationships);
|
||||
if (carteSensibleFetch) {
|
||||
partieContent.carteSensible = {
|
||||
url: carteSensibleFetch.attributes.uri.url,
|
||||
alt: partie.relationships.field_image_carte.data.meta.alt,
|
||||
};
|
||||
}
|
||||
break;
|
||||
case 'titre_texte':
|
||||
partieContent.titre = partie.attributes.field_titre;
|
||||
partieContent.texte = partie.attributes.field_texte.value;
|
||||
break;
|
||||
case 'chiffres_cles':
|
||||
const chiffresClesFetch = await this.fetchDeeperContent('field_chiffres_clefs', partie.relationships);
|
||||
if (chiffresClesFetch) {
|
||||
partieContent.chiffresCles = [];
|
||||
for (let chiffre of chiffresClesFetch) {
|
||||
partieContent.chiffresCles.push({
|
||||
chiffre: chiffre.attributes.field_chiffre,
|
||||
description: chiffre.attributes.field_description,
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'diaporama':
|
||||
const diaporamaFetch = await this.fetchDeeperContent('field_diaporama', partie.relationships);
|
||||
if (diaporamaFetch) {
|
||||
partieContent.diaporama = [];
|
||||
for (let [index, image] of diaporamaFetch.entries()) {
|
||||
partieContent.diaporama.push({
|
||||
url: image.attributes.uri.url,
|
||||
alt: partie.relationships.field_diaporama.data[index].meta.alt,
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'entretien':
|
||||
partieContent.entretien = {};
|
||||
const personnesFetch = await this.fetchDeeperContent('field_personne_s', partie.relationships);
|
||||
const questionsReponsesFetch = await this.fetchDeeperContent('field_questions_reponses', partie.relationships);
|
||||
if (personnesFetch && questionsReponsesFetch) {
|
||||
partieContent.entretien.personnes = [];
|
||||
for (let personne of personnesFetch) {
|
||||
const portraitFetch = await this.fetchDeeperContent('field_portrait', personne.relationships);
|
||||
if (portraitFetch) {
|
||||
partieContent.entretien.personnes.push({
|
||||
portrait: portraitFetch.attributes.uri.url,
|
||||
alt: personne.relationships.field_portrait.data.meta.alt,
|
||||
description: personne.attributes.field_description,
|
||||
});
|
||||
}
|
||||
}
|
||||
partieContent.entretien.questionsReponses = [];
|
||||
for (let qr of questionsReponsesFetch) {
|
||||
partieContent.entretien.questionsReponses.push({
|
||||
question: qr.attributes.field_question,
|
||||
reponse: qr.attributes.field_reponse.value,
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'exergue':
|
||||
partieContent.exergue = partie.attributes.field_texte_exergue.value;
|
||||
break;
|
||||
case 'video':
|
||||
partieContent.videos = [];
|
||||
for (let video of partie.attributes.field_videos) {
|
||||
const videoId = video.split('?v=')[1];
|
||||
const videoUrl = `https://www.youtube.com/embed/${videoId}`;
|
||||
partieContent.videos.push(videoUrl);
|
||||
}
|
||||
break;
|
||||
}
|
||||
this.content.parties.push(partieContent);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
this.error = 'Failed to fetch data';
|
||||
console.error('Issue with getNodeData', error);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
async fetchStaticData(nid, map) {
|
||||
this.resetStore();
|
||||
this.map = map;
|
||||
try {
|
||||
const response = await REST.get(`/jsonapi/node/static/`);
|
||||
for (let page of response.data.data) {
|
||||
if (page.attributes.drupal_internal__nid == nid) {
|
||||
for (let metatag of page.attributes.metatag) {
|
||||
if (metatag.tag === "link") {
|
||||
this.href = metatag.attributes.href;
|
||||
}
|
||||
}
|
||||
this.page.title = page.attributes.title;
|
||||
const vignetteFetch = await this.fetchContent('field_vignette', page.relationships);
|
||||
if (vignetteFetch) {
|
||||
this.page.vignette = {
|
||||
url: vignetteFetch.attributes.uri.url,
|
||||
alt: page.relationships.field_vignette.data.meta.alt
|
||||
};
|
||||
}
|
||||
|
||||
const partiesFetch = await this.fetchContent('field_parties_static', page.relationships);
|
||||
if (partiesFetch) {
|
||||
this.page.parties = [];
|
||||
|
||||
for (let partie of partiesFetch) {
|
||||
const partieType = partie.type.replace(/^paragraph--/, "");
|
||||
let partieContent = {
|
||||
type: partieType,
|
||||
};
|
||||
|
||||
switch (partieType) {
|
||||
case 'titre_texte':
|
||||
partieContent.titre = partie.attributes.field_titre;
|
||||
partieContent.texte = partie.attributes.field_texte.value;
|
||||
break;
|
||||
case 'diaporama':
|
||||
const diaporamaFetch = await this.fetchContent('field_diaporama', partie.relationships);
|
||||
if (diaporamaFetch) {
|
||||
partieContent.diaporama = [];
|
||||
for (let [index, image] of diaporamaFetch.entries()) {
|
||||
partieContent.diaporama.push({
|
||||
url: image.attributes.uri.url,
|
||||
alt: partie.relationships.field_diaporama.data[index].meta.alt,
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'exergue':
|
||||
partieContent.exergue = partie.attributes.field_texte_exergue.value;
|
||||
break;
|
||||
case 'video':
|
||||
partieContent.videos = [];
|
||||
for (let video of partie.attributes.field_videos) {
|
||||
const videoId = video.split('?v=')[1];
|
||||
const videoUrl = `https://www.youtube.com/embed/${videoId}`;
|
||||
partieContent.videos.push(videoUrl);
|
||||
}
|
||||
break;
|
||||
}
|
||||
this.page.parties.push(partieContent);
|
||||
getCleanDate(date) {
|
||||
return {
|
||||
d: date.split('-')[2],
|
||||
m: new Intl.DateTimeFormat('fr-FR', { month: 'long' }).format(new Date(date)),
|
||||
y: date.split('-')[0],
|
||||
}
|
||||
},
|
||||
async getRelatedEtape(direction, allEtapesData, path) {
|
||||
const getRelatedEtapeContent = async (relatedPath, allEtapesData) => {
|
||||
const baseUrl = window.location.protocol + "//" + window.location.host;
|
||||
for (let etape of allEtapesData) {
|
||||
for (let tag of etape.attributes.metatag) {
|
||||
if (tag.tag === "link" && tag.attributes.href === baseUrl + relatedPath) {
|
||||
const vignetteFetch = await REST.get(etape.relationships.field_vignette.links.related.href);
|
||||
this.content[direction] = {
|
||||
url: tag.attributes.href,
|
||||
couleur: etape.attributes.field_couleur,
|
||||
title: etape.attributes.title,
|
||||
postalCode: etape.attributes.field_adresse.postal_code,
|
||||
dates: {
|
||||
start: this.getCleanDate(etape.attributes.field_dates.value),
|
||||
end: this.getCleanDate(etape.attributes.field_dates.end_value),
|
||||
},
|
||||
vignette: {
|
||||
url: vignetteFetch.data.data.attributes.uri.url,
|
||||
alt: etape.relationships.field_vignette.data.meta.alt,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.setActiveItemInMenu(nid);
|
||||
} catch (error) {
|
||||
}
|
||||
|
||||
const orderedEtapesList = document.querySelectorAll('#etapes-liste li');
|
||||
if (orderedEtapesList) {
|
||||
for (let li of orderedEtapesList) {
|
||||
const liHref = li.querySelector('a').getAttribute('href');
|
||||
if (path.endsWith(liHref)) {
|
||||
const previousEtapeItemPath = li.previousElementSibling?.querySelector('a').getAttribute('href');
|
||||
const nextEtapeItemPath = li.nextElementSibling?.querySelector('a').getAttribute('href');
|
||||
|
||||
if (previousEtapeItemPath && direction === 'previous') {
|
||||
let prevContent = await getRelatedEtapeContent(previousEtapeItemPath, allEtapesData);
|
||||
return prevContent;
|
||||
}
|
||||
if (nextEtapeItemPath && direction === 'next') {
|
||||
let nextContent = await getRelatedEtapeContent(nextEtapeItemPath, allEtapesData);
|
||||
return nextContent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
async fetchDeeperContent(field, relationships) {
|
||||
if (relationships[field].data) {
|
||||
try {
|
||||
const contentLink = relationships[field].links.related.href;
|
||||
const contentFetch = await REST.get(contentLink);
|
||||
return contentFetch.data.data;
|
||||
} catch (error) {
|
||||
this.error = 'Failed to fetch data';
|
||||
console.error('Issue with getNodeData', error);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
async fetchContent(field, relationships) {
|
||||
if (relationships[field].data) {
|
||||
try {
|
||||
const contentLink = relationships[field].links.related.href;
|
||||
const contentFetch = await REST.get(contentLink);
|
||||
return contentFetch.data.data;
|
||||
} catch (error) {
|
||||
this.error = 'Failed to fetch data';
|
||||
console.error('Issue with getNodeData', error);
|
||||
}
|
||||
}
|
||||
},
|
||||
emptyAll(nid, map) {
|
||||
this.href = '';
|
||||
this.map = map;
|
||||
this.etape = {};
|
||||
this.page = {};
|
||||
this.setActiveItemInMenu(nid);
|
||||
},
|
||||
setActiveItemInMenu(nid) {
|
||||
const title = this.etape.title || this.page.title;
|
||||
|
||||
const generalLinks = document.querySelectorAll('#menu > ul > li > a');
|
||||
if (Object.entries(this.etape).length === 0 && Object.entries(this.page).length === 0) {
|
||||
for (let link of generalLinks) {
|
||||
link.classList.remove('is-active');
|
||||
}
|
||||
generalLinks[0].classList.add('is-active');
|
||||
} else {
|
||||
for (let link of generalLinks) {
|
||||
if (link.dataset.nodeNid == nid) {
|
||||
link.classList.add('is-active');
|
||||
} else {
|
||||
link.classList.remove('is-active');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const etapeLinks = document.querySelectorAll('#etapes-liste li');
|
||||
for (let link of etapeLinks) {
|
||||
const a = link.querySelector('a');
|
||||
if (a.innerText === title) {
|
||||
link.classList.remove('inactive');
|
||||
} else {
|
||||
link.classList.add('inactive');
|
||||
}
|
||||
}
|
||||
const inactiveLinks = document.querySelectorAll('#etapes-liste li.inactive');
|
||||
if (inactiveLinks.length === etapeLinks.length) {
|
||||
for (let link of inactiveLinks) {
|
||||
link.classList.remove('inactive');
|
||||
}
|
||||
}
|
||||
},
|
||||
resetStore() {
|
||||
this.loading = true;
|
||||
resetStore(forFrontDisplay) {
|
||||
this.contentType = '';
|
||||
this.pageTitle = '';
|
||||
this.content = {};
|
||||
this.loading = !forFrontDisplay;
|
||||
this.error = null;
|
||||
this.etape = {};
|
||||
this.page = {};
|
||||
},
|
||||
getCleanDate(date) {
|
||||
return {
|
||||
d: date.split('-')[2],
|
||||
m: new Intl.DateTimeFormat('fr-FR', { month: 'long' }).format(new Date(date)),
|
||||
y: date.split('-')[0],
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
});
|
|
@ -2,6 +2,7 @@ import { defineStore } from 'pinia';
|
|||
|
||||
export const useMapStore = defineStore('mapState', {
|
||||
state: () => ({
|
||||
map: Object,
|
||||
defaultZoom: Number,
|
||||
defaultMapCenter: Object,
|
||||
currentPlace: Object,
|
||||
|
@ -10,36 +11,36 @@ export const useMapStore = defineStore('mapState', {
|
|||
duration: 3,
|
||||
}),
|
||||
actions: {
|
||||
zoomToPlace(map, lat, long) {
|
||||
map.flyTo([lat, long], this.maxZoom, { duration: this.duration });
|
||||
this.currentZoom = this.maxZoom;
|
||||
zoomToPlace(lat, long) {
|
||||
this.map.flyTo([lat, long], this.maxZoom, { duration: this.duration });
|
||||
this.currentZoom = this.maxZoom;
|
||||
},
|
||||
resetMap(map) {
|
||||
map.flyTo(this.defaultMapCenter, this.defaultZoom, { duration: this.duration });
|
||||
resetMap() {
|
||||
this.map.flyTo(this.defaultMapCenter, this.defaultZoom, { duration: this.duration });
|
||||
this.currentZoom = this.defaultZoom;
|
||||
},
|
||||
lockMap(map) {
|
||||
lockMap() {
|
||||
setTimeout(() => {
|
||||
map.options.minZoom = this.currentZoom;
|
||||
map.options.maxZoom = this.currentZoom;
|
||||
this.map.options.minZoom = this.currentZoom;
|
||||
this.map.options.maxZoom = this.currentZoom;
|
||||
}, this.duration * 1000 + 100);
|
||||
map.dragging.disable();
|
||||
map.touchZoom.disable();
|
||||
map.doubleClickZoom.disable();
|
||||
map.scrollWheelZoom.disable();
|
||||
map.boxZoom.disable();
|
||||
map.keyboard.disable();
|
||||
this.map.dragging.disable();
|
||||
this.map.touchZoom.disable();
|
||||
this.map.doubleClickZoom.disable();
|
||||
this.map.scrollWheelZoom.disable();
|
||||
this.map.boxZoom.disable();
|
||||
this.map.keyboard.disable();
|
||||
// map.tap.disable();
|
||||
},
|
||||
unlockMap(map) {
|
||||
map.options.minZoom = this.defaultZoom;
|
||||
map.options.maxZoom = this.maxZoom;
|
||||
map.dragging.enable();
|
||||
map.touchZoom.enable();
|
||||
map.doubleClickZoom.enable();
|
||||
map.scrollWheelZoom.enable();
|
||||
map.boxZoom.enable();
|
||||
map.keyboard.enable();
|
||||
unlockMap() {
|
||||
this.map.options.minZoom = this.defaultZoom;
|
||||
this.map.options.maxZoom = this.maxZoom;
|
||||
this.map.dragging.enable();
|
||||
this.map.touchZoom.enable();
|
||||
this.map.doubleClickZoom.enable();
|
||||
this.map.scrollWheelZoom.enable();
|
||||
this.map.boxZoom.enable();
|
||||
this.map.keyboard.enable();
|
||||
// map.tap.enable();
|
||||
},
|
||||
},
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
import { setActiveNavItem } from "./set-active-nav-item";
|
||||
|
||||
export async function initFirstLoadRouting(store, router, baseUrl, siteName) {
|
||||
const decoupled_origin = JSON.parse(window.localStorage.getItem('decoupled_origin'));
|
||||
|
||||
if(decoupled_origin) {
|
||||
await store.fetchContentData(baseUrl + decoupled_origin.url);
|
||||
router.push(decoupled_origin.url);
|
||||
window.localStorage.removeItem("decoupled_origin");
|
||||
document.title = store.pageTitle;
|
||||
setActiveNavItem(store.contentType, decoupled_origin.url);
|
||||
} else {
|
||||
document.title = siteName;
|
||||
}
|
||||
}
|
||||
|
||||
export function handleClickableElements(clickableElements, store, router, baseUrl, siteName, mapStore) {
|
||||
for (const link of clickableElements) {
|
||||
let href = link.href || link.dataset.href;
|
||||
if (href.startsWith(baseUrl)) href = href.replace(baseUrl, '');
|
||||
|
||||
link.onclick = async function (e) {
|
||||
router.push(href);
|
||||
if (href !== window.location.pathname) {
|
||||
if (href === '/') {
|
||||
store.resetStore(true);
|
||||
document.title = siteName;
|
||||
mapStore.resetMap();
|
||||
} else {
|
||||
await store.fetchContentData(baseUrl + href);
|
||||
document.title = store.pageTitle;
|
||||
}
|
||||
setActiveNavItem(store.contentType, href);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
export function setMenuToggle() {
|
||||
const menuButton = document.querySelector('#block-caravane-mainnavigation > #menu');
|
||||
const menuContainer = document.querySelector('#block-caravane-mainnavigation > #menu > ul');
|
||||
const menuTitle = document.querySelector('#menu-title');
|
||||
const menuBurger = document.querySelector('#hamburger');
|
||||
const menuH2 = document.querySelector('#menu > h2');
|
||||
menuButton.addEventListener('click', (e) => {
|
||||
setTimeout(() => {
|
||||
menuContainer.classList.toggle('open');
|
||||
menuTitle.classList.toggle('open');
|
||||
menuBurger.classList.toggle('open');
|
||||
menuH2.classList.toggle('open');
|
||||
}, 50);
|
||||
});
|
||||
document.addEventListener('click', (e) => {
|
||||
if (!menuContainer.contains(e.target) && !menuBurger.contains(e.target)) {
|
||||
menuContainer.classList.remove('open');
|
||||
menuTitle.classList.remove('open');
|
||||
menuBurger.classList.remove('open');
|
||||
menuH2.classList.remove('open');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function setHamburgerWhenLogged(drupalSettings) {
|
||||
if (drupalSettings.user.uid != 0) {
|
||||
const menuBurger = document.querySelector('#hamburger');
|
||||
const menuTitle = document.querySelector('#menu-title');
|
||||
const menuContainer = document.querySelector('#block-caravane-mainnavigation > #menu > ul');
|
||||
const header = document.querySelector('.dialog-off-canvas-main-canvas');
|
||||
const headerTop = header.getBoundingClientRect().top;
|
||||
|
||||
menuTitle.style.top = `${headerTop}px`;
|
||||
menuBurger.style.top = `${headerTop}px`;
|
||||
menuContainer.style.paddingTop = `${headerTop}px`;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
export function setupMapStore(mapStore, map, settings) {
|
||||
mapStore.map = map;
|
||||
mapStore.defaultMapCenter = map.getCenter();
|
||||
mapStore.maxZoom = settings.settings.maxZoom;
|
||||
mapStore.defaultZoom = settings.settings.minZoom;
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
export function processClickableElements() {
|
||||
return {
|
||||
etapeListLinks: processEtapeLinks(),
|
||||
generalListLinks: processStaticLinks(),
|
||||
logoLink: processLogoLink(),
|
||||
mapIcons: processMapIcons(),
|
||||
};
|
||||
}
|
||||
|
||||
function processEtapeLinks() {
|
||||
const etape_li = document.querySelectorAll('#etapes-liste li');
|
||||
etape_li.forEach((li) => {
|
||||
const etape_link = li.querySelector('a.etape-link');
|
||||
etape_link.addEventListener('click', (e) => e.preventDefault());
|
||||
const couleur = etape_link.dataset.couleur;
|
||||
li.dataset.href = etape_link.attributes.href.value;
|
||||
const iconElements = li.querySelectorAll('.icone-arret > div');
|
||||
for (let element of iconElements) {
|
||||
element.style.backgroundColor = couleur;
|
||||
}
|
||||
});
|
||||
|
||||
return etape_li;
|
||||
}
|
||||
|
||||
function processStaticLinks() {
|
||||
const general_link_fields = document.querySelectorAll('#menu > ul > li > a');
|
||||
for (let i = 0; i < general_link_fields.length; i ++) {
|
||||
let general_link_path = general_link_fields[i].getAttribute('data-drupal-link-system-path');
|
||||
if (general_link_path && general_link_path !== '<front>') {
|
||||
const match = [...general_link_path.match(/^node\/(\d+)$/)];
|
||||
if (match) {
|
||||
const nid = match[1];
|
||||
general_link_fields[i].setAttribute('data-nid', parseInt(nid));
|
||||
}
|
||||
}
|
||||
general_link_fields[i].addEventListener('click', (e) => e.preventDefault());
|
||||
}
|
||||
|
||||
return general_link_fields;
|
||||
}
|
||||
|
||||
function processLogoLink() {
|
||||
const logo = document.querySelector('#block-caravane-logocaravane a');
|
||||
logo.addEventListener('click', (e) => e.preventDefault());
|
||||
|
||||
return logo;
|
||||
}
|
||||
|
||||
function processMapIcons() {
|
||||
const icons = document.querySelectorAll('.leaflet-map-divicon');
|
||||
for (let icon of icons) {
|
||||
icon.setAttribute('title', '');
|
||||
|
||||
const hrefContainer = icon.querySelector('.url');
|
||||
icon.dataset.href = hrefContainer.innerText;
|
||||
hrefContainer.style.display = "none";
|
||||
|
||||
const colorContainer = icon.querySelector('.couleur');
|
||||
let color = colorContainer.innerText;
|
||||
colorContainer.style.display = "none";
|
||||
|
||||
const iconElements = icon.querySelectorAll('div');
|
||||
for (let iconElement of iconElements) {
|
||||
iconElement.style.backgroundColor = color;
|
||||
}
|
||||
|
||||
icon.addEventListener('mouseenter', () => {
|
||||
icon.style.transform = `${icon.style.transform} scale(1.1)`;
|
||||
const popup = document.querySelector('.leaflet-tooltip-center > div');
|
||||
popup.style.opacity = "1";
|
||||
});
|
||||
|
||||
icon.addEventListener('mouseleave', () => {
|
||||
icon.style.transform = icon.style.transform.split(' ')[0] + icon.style.transform.split(' ')[1] + icon.style.transform.split(' ')[2];
|
||||
});
|
||||
}
|
||||
|
||||
return icons;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
export function setActiveNavItem(contentType, href) {
|
||||
const staticNavItems = document.querySelectorAll('#menu > ul > li > a');
|
||||
const etapeNavItems = document.querySelectorAll('#etapes-liste li a');
|
||||
|
||||
for (let item of staticNavItems) {
|
||||
item.classList.remove('is-active');
|
||||
}
|
||||
|
||||
for (let item of etapeNavItems) {
|
||||
item.closest('li').classList.add('inactive');
|
||||
}
|
||||
|
||||
if (href === '/' || href === '') {
|
||||
staticNavItems[0].classList.add('is-active');
|
||||
for (let item of etapeNavItems) {
|
||||
item.closest('li').classList.remove('inactive');
|
||||
}
|
||||
|
||||
} else {
|
||||
if (contentType === 'static') {
|
||||
for (let item of staticNavItems) {
|
||||
if (item.getAttribute('href') === href) {
|
||||
item.classList.add('is-active');
|
||||
}
|
||||
}
|
||||
} else if (contentType === 'etape') {
|
||||
for (let item of etapeNavItems) {
|
||||
if (item.getAttribute('href') === href) {
|
||||
item.closest('li').classList.remove('inactive');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { createApp } from 'vue';
|
||||
import { createPinia } from 'pinia';
|
||||
import router from '../router/router';
|
||||
import Modale from '../vuejs/Modale.vue';
|
||||
import VueImageZoomer from 'vue-image-zoomer';
|
||||
import 'vue-image-zoomer/dist/style.css';
|
||||
|
||||
import { useContentStore } from '../stores/content';
|
||||
import { useMapStore } from '../stores/mapState';
|
||||
|
||||
export function initVueContentModale() {
|
||||
const app = createApp(Modale)
|
||||
.use(createPinia())
|
||||
.use(router)
|
||||
.use(VueImageZoomer);
|
||||
|
||||
const store = useContentStore();
|
||||
const mapStore = useMapStore();
|
||||
app.mount('#content-modale');
|
||||
|
||||
return { store, mapStore, router };
|
||||
}
|
|
@ -1,44 +1,46 @@
|
|||
<template>
|
||||
<Transition>
|
||||
<div v-if="isEtapeValid || isPageValid">
|
||||
<div v-if="!loading && (contentType === 'etape' || contentType === 'static')">
|
||||
<div class="content-wrapper">
|
||||
<ModaleHeader
|
||||
:content="etape.title ? etape : page"
|
||||
:couleur="etape.couleur || brandColor" />
|
||||
<ModaleHeader
|
||||
:contentType="contentType"
|
||||
:content="content"
|
||||
:couleur="content.couleur || brandColor" />
|
||||
<main>
|
||||
<div v-for="partie in etape.parties || page.parties" class="partie">
|
||||
<div v-for="partie in content.parties" class="partie">
|
||||
<ModaleCarteSensible
|
||||
v-if="partie.type === 'carte_sensible'"
|
||||
:partie="partie" />
|
||||
<ModaleTitreTexte
|
||||
v-if="partie.type === 'titre_texte'"
|
||||
:partie="partie"
|
||||
:couleur="etape.couleur || brandColor" />
|
||||
:couleur="content.couleur || brandColor" />
|
||||
<ModaleChiffresCles
|
||||
v-if="partie.type === 'chiffres_cles'"
|
||||
:partie="partie"
|
||||
:couleur="etape.couleur || brandColor" />
|
||||
:couleur="content.couleur || brandColor" />
|
||||
<ModaleDiaporama
|
||||
v-if="partie.type === 'diaporama'"
|
||||
:partie="partie"
|
||||
:couleur="etape.couleur || brandColor" />
|
||||
:couleur="content.couleur || brandColor" />
|
||||
<ModaleEntretien
|
||||
v-if="partie.type === 'entretien'"
|
||||
:partie="partie"
|
||||
:couleur="etape.couleur || brandColor" />
|
||||
:couleur="content.couleur || brandColor" />
|
||||
<ModaleExergue
|
||||
v-if="partie.type === 'exergue'"
|
||||
:partie="partie"
|
||||
:couleur="etape.couleur || brandColor" />
|
||||
:couleur="content.couleur || brandColor" />
|
||||
<ModaleVideos
|
||||
v-if="partie.type === 'video'"
|
||||
:partie="partie" />
|
||||
</div>
|
||||
</main>
|
||||
<ModaleFooter
|
||||
:content="etape || page"
|
||||
:couleur="etape.couleur || brandColor"
|
||||
:map="map" />
|
||||
:contentType="contentType"
|
||||
:content="content"
|
||||
:couleur="content.couleur || brandColor"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
|
@ -46,10 +48,10 @@
|
|||
|
||||
<script setup>
|
||||
import { computed, watch, onMounted } from 'vue';
|
||||
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useContentStore } from '../stores/content';
|
||||
import { useMapStore } from '../stores/mapState';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import ModaleHeader from './components/ModaleHeader.vue';
|
||||
import ModaleFooter from './components/ModaleFooter.vue';
|
||||
|
@ -62,132 +64,95 @@ import ModaleEntretien from './components/parties/ModaleEntretien.vue';
|
|||
import ModaleExergue from './components/parties/ModaleExergue.vue';
|
||||
import ModaleVideos from './components/parties/ModaleVideos.vue';
|
||||
|
||||
import { useUtils } from './composables/useUtils';
|
||||
const { isObjectEmpty, scrollTop } = useUtils();
|
||||
|
||||
const router = useRouter();
|
||||
const store = useContentStore();
|
||||
const mapState = useMapStore();
|
||||
const route = useRoute();
|
||||
|
||||
const { loading, error, href, map, etape, page } = storeToRefs(store);
|
||||
const { duration } = storeToRefs(mapState);
|
||||
const {
|
||||
contentType,
|
||||
content,
|
||||
loading,
|
||||
error,
|
||||
} = storeToRefs(store);
|
||||
|
||||
const isEtapeValid = computed(() => !error.value && !loading.value && etape.value && !isObjectEmpty(etape.value));
|
||||
const isPageValid = computed(() => !error.value && !loading.value && page.value && !isObjectEmpty(page.value));
|
||||
const { map, duration } = storeToRefs(mapState);
|
||||
|
||||
let isModaleEtape, wasModaleEtape;
|
||||
|
||||
const brandColor = "#80c8bf";
|
||||
|
||||
let isProgrammaticNavigation = false;
|
||||
|
||||
const handleRouteChange = () => {
|
||||
watch(
|
||||
() => route.params.id,
|
||||
(newId) => {
|
||||
if (isProgrammaticNavigation) {
|
||||
isProgrammaticNavigation = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!newId) {
|
||||
store.emptyAll(map.value);
|
||||
} else {
|
||||
store.fetchEtapeData(newId, map.value);
|
||||
if (!etape.value?.data) {
|
||||
store.fetchStaticData(newId, map.value);
|
||||
}
|
||||
scrollTop();
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
};
|
||||
|
||||
const handleColorChange = () => {
|
||||
watch(
|
||||
() => href.value,
|
||||
() => {
|
||||
document.documentElement.style.setProperty('--etape-couleur', etape.value.couleur || brandColor);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const handleHrefChange = () => {
|
||||
watch(
|
||||
() => href.value,
|
||||
(newHref) => {
|
||||
const relativePath = newHref.split('.fr')[1];
|
||||
isProgrammaticNavigation = true;
|
||||
if (newHref == '') {
|
||||
router.push('/');
|
||||
mapState.unlockMap(map.value)
|
||||
} else {
|
||||
if (relativePath && relativePath !== '' && relativePath !== '/') {
|
||||
mapState.lockMap(map.value);
|
||||
router.push(relativePath);
|
||||
scrollTop();
|
||||
}
|
||||
}
|
||||
() => content.value.couleur,
|
||||
() => {
|
||||
if (contentType.value === 'etape' && content.value.couleur) {
|
||||
document.documentElement.style.setProperty('--etape-couleur', content.value.couleur || brandColor);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const handleMapMovement = () => {
|
||||
watch(
|
||||
() => href.value,
|
||||
() => loading.value,
|
||||
() => {
|
||||
isModaleEtape = !isObjectEmpty(etape.value);
|
||||
|
||||
if (!wasModaleEtape && isModaleEtape) {
|
||||
document.documentElement.style.setProperty('--modale-enter-delay', `${duration.value}s`);
|
||||
mapState.zoomToPlace(map.value, etape.value.coordinates.lat, etape.value.coordinates.lon);
|
||||
|
||||
} else if (wasModaleEtape && isModaleEtape) {
|
||||
document.documentElement.style.setProperty('--modale-leave-delay', 0);
|
||||
document.documentElement.style.setProperty('--modale-enter-delay', `${duration.value * 2}s`);
|
||||
mapState.resetMap(map.value);
|
||||
setTimeout(() => {
|
||||
mapState.zoomToPlace(map.value, etape.value.coordinates.lat, etape.value.coordinates.lon);
|
||||
}, duration.value * 1000);
|
||||
|
||||
} else if (wasModaleEtape && !isModaleEtape) {
|
||||
document.documentElement.style.setProperty('--modale-leave-delay', 0);
|
||||
mapState.resetMap(map.value);
|
||||
}
|
||||
|
||||
wasModaleEtape = isModaleEtape;
|
||||
if (!loading.value) {
|
||||
isModaleEtape = contentType.value === 'etape';
|
||||
|
||||
if (!wasModaleEtape && isModaleEtape) {
|
||||
// national -> détail
|
||||
document.documentElement.style.setProperty('--modale-enter-delay', `${duration.value}s`);
|
||||
mapState.zoomToPlace(content.value.coordinates.lat, content.value.coordinates.lon);
|
||||
} else if (wasModaleEtape && isModaleEtape) {
|
||||
// détail -> détail
|
||||
document.documentElement.style.setProperty('--modale-leave-delay', 0);
|
||||
document.documentElement.style.setProperty('--modale-enter-delay', `${duration.value * 2}s`);
|
||||
mapState.resetMap(map.value);
|
||||
setTimeout(() => {
|
||||
mapState.zoomToPlace(content.value.coordinates.lat, content.value.coordinates.lon);
|
||||
}, duration.value * 1000);
|
||||
|
||||
} else if (wasModaleEtape && !isModaleEtape) {
|
||||
// détail -> national
|
||||
document.documentElement.style.setProperty('--modale-leave-delay', 0);
|
||||
document.documentElement.style.setProperty('--modale-enter-delay', `${duration.value}s`);
|
||||
mapState.resetMap();
|
||||
} else if (!wasModaleEtape && !isModaleEtape) {
|
||||
// national -> national
|
||||
console.log('national -> national');
|
||||
document.documentElement.style.setProperty('--modale-leave-delay', 0);
|
||||
document.documentElement.style.setProperty('--modale-enter-delay', '0.5s');
|
||||
}
|
||||
|
||||
wasModaleEtape = isModaleEtape;
|
||||
}
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
isModaleEtape = !isObjectEmpty(etape.value);
|
||||
wasModaleEtape = isModaleEtape;
|
||||
handleRouteChange();
|
||||
handleColorChange();
|
||||
handleHrefChange();
|
||||
handleMapMovement();
|
||||
isModaleEtape = contentType.value === 'etape';
|
||||
wasModaleEtape = isModaleEtape;
|
||||
handleColorChange();
|
||||
handleMapMovement();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scss>
|
||||
<style scoped scss>
|
||||
.v-enter-active {
|
||||
transition: all 0.5s linear var(--modale-enter-delay);
|
||||
transition: margin-top 0.5s ease-out var(--modale-enter-delay);
|
||||
}
|
||||
|
||||
.v-leave-active {
|
||||
transition: all 0.5s linear var(--modale-leave-delay);
|
||||
transition: margin-top 0.5s ease-in var(--modale-leave-delay);
|
||||
}
|
||||
|
||||
.v-enter-from,
|
||||
.v-leave-to {
|
||||
transform: translateY(20vh);
|
||||
margin-top: 150vh;
|
||||
}
|
||||
|
||||
.v-enter-to,
|
||||
.v-leave-from {
|
||||
transform: translateY(0vh);
|
||||
margin-top: 0vh;
|
||||
}
|
||||
</style>
|
|
@ -4,8 +4,8 @@
|
|||
<div class="pattern"></div>
|
||||
</div>
|
||||
|
||||
<div v-if="content.previous || content.next" class="related-etape-links">
|
||||
<div v-if="content.previous" class="card previous" @click="store.fetchEtapeData(content.previous.nid, map)">
|
||||
<div v-if="contentType === 'etape' && (content.previous || content.next)" class="related-etape-links">
|
||||
<div v-if="content.previous" class="card previous" @click="displayRelatedElement(content.previous.url)">
|
||||
<div class="icon">
|
||||
<div :style="{ backgroundColor: content.previous.couleur }"></div>
|
||||
<div :style="{ backgroundColor: content.previous.couleur }"></div>
|
||||
|
@ -21,7 +21,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="content.next" class="card next" @click="store.fetchEtapeData(content.next.nid, map)">
|
||||
<div v-if="content.next" class="card next" @click="displayRelatedElement(content.next.url)">
|
||||
<div class="icon">
|
||||
<div :style="{ backgroundColor: content.next.couleur }"></div>
|
||||
<div :style="{ backgroundColor: content.next.couleur }"></div>
|
||||
|
@ -42,14 +42,25 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import router from '../../router/router.js';
|
||||
import { useContentStore } from '../../stores/content';
|
||||
|
||||
const brandColor = "#80c8bf";
|
||||
|
||||
const store = useContentStore();
|
||||
const props = defineProps({
|
||||
contentType: String,
|
||||
content: Object,
|
||||
couleur: String,
|
||||
map: Object,
|
||||
});
|
||||
|
||||
async function displayRelatedElement(href) {
|
||||
const baseUrl = window.location.protocol + "//" + window.location.host;
|
||||
if (href.startsWith(baseUrl)) href = href.replace(baseUrl, '');
|
||||
|
||||
router.push(href);
|
||||
await store.fetchContentData(baseUrl + href);
|
||||
document.title = store.pageTitle;
|
||||
}
|
||||
</script>
|
|
@ -1,9 +1,9 @@
|
|||
<template>
|
||||
<header :style="content.vignette ? '' : { marginTop: '20vh' }">
|
||||
<div class="cover">
|
||||
<img v-if="content.vignette" :src="content.vignette.url" :alt="content.vignette.alt">
|
||||
<img v-if="content.vignette" :src="content.vignette.url" :alt="content.vignette.alt">
|
||||
</div>
|
||||
<div v-if="content.dates" class="cartouche" :style="{ backgroundColor: couleur }">
|
||||
<div v-if="contentType === 'etape' && content.dates" class="cartouche" :style="{ backgroundColor: couleur }">
|
||||
<p>Étape n°{{content.etape_number}}</p>
|
||||
<p>Du {{content.dates.start.d}} {{content.dates.start.m}} au {{ content.dates.end.d }} {{ content.dates.end.m }} {{ content.dates.end.y }}</p>
|
||||
</div>
|
||||
|
@ -13,7 +13,7 @@
|
|||
<div class="locality">
|
||||
<div class="top-triangle"></div>
|
||||
<div class="locality-title">
|
||||
<h1>{{content.title}} <em v-if="content.adresse">({{ content.adresse.postal_code.slice(0, 2) }})</em></h1>
|
||||
<h1>{{content.contentTitle}} <em v-if="content.adresse">({{ content.adresse.postal_code.slice(0, 2) }})</em></h1>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
@ -21,6 +21,7 @@
|
|||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
contentType: String,
|
||||
content: Object,
|
||||
couleur: String,
|
||||
});
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
export function useUtils() {
|
||||
const isObjectEmpty = (obj) => {
|
||||
if (!obj || typeof obj !== 'object') return true;
|
||||
|
||||
return !Object.keys(obj).some((key) => {
|
||||
const value = obj[key];
|
||||
if (Array.isArray(value)) return value.length > 0;
|
||||
if (typeof value === 'object') return !isObjectEmpty(value);
|
||||
return value !== null && value !== undefined && value !== '';
|
||||
});
|
||||
};
|
||||
|
||||
const scrollTop = () => {
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
};
|
||||
|
||||
return {
|
||||
isObjectEmpty,
|
||||
scrollTop,
|
||||
};
|
||||
}
|
|
@ -253,6 +253,9 @@ body{
|
|||
top: 0;
|
||||
width: 100vw;
|
||||
.leaflet-container {
|
||||
.leaflet-popup {
|
||||
display: none;
|
||||
}
|
||||
// add map style here
|
||||
.leaflet-control-zoom {
|
||||
border: none;
|
||||
|
|
|
@ -27,7 +27,8 @@ function caravane_preprocess_html(&$variables) {
|
|||
* Implements hook_preprocess_HOOK() for page.html.twig.
|
||||
*/
|
||||
function caravane_preprocess_page(&$variables) {
|
||||
|
||||
$config = \Drupal::config('system.site');
|
||||
$variables['site_name'] = $config->get('name');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -89,3 +89,4 @@
|
|||
{% endif %}
|
||||
|
||||
</div>{# /.layout-container #}
|
||||
<div id="site_name" style="display: none;">{{ site_name }}</div>
|
Loading…
Reference in New Issue