|
|
@@ -1,923 +0,0 @@
|
|
|
-// Specific code for the 'federation-structures' page
|
|
|
-
|
|
|
-const apiGetAllUrl = "/typo3/index.php?route=/otcore/structures/all";
|
|
|
-const apiGetByIdUrl = "/typo3/index.php?route=/otcore/structures/get";
|
|
|
-
|
|
|
-// Converts numeric degrees to radians
|
|
|
-function toRad(Value)
|
|
|
-{
|
|
|
- return Value * Math.PI / 180;
|
|
|
-}
|
|
|
-
|
|
|
-//This function takes in latitude and longitude of two location and returns the distance between them as the crow flies (in km)
|
|
|
-function sphericDistance(lat1, lon1, lat2, lon2)
|
|
|
-{
|
|
|
- let R = 6371; // km
|
|
|
- let dLat = toRad(lat2-lat1);
|
|
|
- let dLon = toRad(lon2-lon1);
|
|
|
- lat1 = toRad(lat1);
|
|
|
- lat2 = toRad(lat2);
|
|
|
-
|
|
|
- let a = Math.sin(dLat/2) * Math.sin(dLat/2) +
|
|
|
- Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
|
|
|
- let c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
|
|
|
- return R * c;
|
|
|
-}
|
|
|
-
|
|
|
-const practicesFr = {
|
|
|
- "BIG_BAND": "Big band",
|
|
|
- "BRASS_BAND": "Brass band",
|
|
|
- "ORCHESTRA_CLASS": "Classe d'orchestre",
|
|
|
- "ACCORDION_ORCHESTRA": "Orchestre d'accordéons",
|
|
|
- "HARMONY_ORCHESTRA": "Orchestre d'harmonie",
|
|
|
- "PHILHARMONIC_ORCHESTRA": "Orchestre philharmonique",
|
|
|
- "SYMPHONY_ORCHESTRA": "Orchestre symphonique",
|
|
|
- "STRING_ORCHESTRA": "Orchestre à cordes",
|
|
|
- "PLUCKED_ORCHESTRA": "Orchestre à plectres",
|
|
|
- "FANFARE_BAND": "Orchestre de fanfare",
|
|
|
- "BAGAD": "Bagad",
|
|
|
- "BANDAS": "Bandas ou Fanfare de rue",
|
|
|
- "BATTERY_FANFARE": "Batterie fanfare",
|
|
|
- "BATTUCADA": "Battucada",
|
|
|
- "FOLKLORIC_BAND": "Ensemble folklorique",
|
|
|
- "FIFE_AND_DRUM": "Fifres et tambours",
|
|
|
- "MARCHING_BAND": "Marching band ou Show parade",
|
|
|
- "HUNTING_HORNS": "Trompes de chasse",
|
|
|
- "CHILDRENS_CHOIR": "Choeur d'enfants",
|
|
|
- "FEMAL_CHOIR": "Choeur de femmes",
|
|
|
- "MENS_CHOIR": "Choeur d'hommes",
|
|
|
- "MIXED_CHORUS": "Choeur mixte",
|
|
|
- "VOCAL_BAND_UP_16": "Ensemble vocal (jusqu'à 16)",
|
|
|
- "CLARINET_CHOIR": "Ensemble de clarinettes",
|
|
|
- "COPPER_BAND": "Ensemble de cuivres",
|
|
|
- "FLUTE_ENSEMBLE": "Ensemble de flûtes",
|
|
|
- "SAXOPHONES_BAND": "Ensemble de saxophones",
|
|
|
- "VIOLIN_BAND": "Ensemble de violons",
|
|
|
- "PERCUSSION_BAND": "Ensemble de percussions",
|
|
|
- "CURRENT_MUSIC_GROUP": "Groupe de Musique actuelle",
|
|
|
- "CHAMBER_MUSIC_ENSEMBLE": "Ensemble de Musique de chambre",
|
|
|
- "TRADITIONAL_MUSIC_ENSEMBLE": "Ensemble de Musique traditionnelle",
|
|
|
- "JAZZ_BAND": "Ensemble de Jazz",
|
|
|
- "EDUCATION": "Enseignement",
|
|
|
- "CHEERLEADER": "Majorettes",
|
|
|
- "TROOP": "Troupe",
|
|
|
- "OTHER": "Autre"
|
|
|
-}
|
|
|
-
|
|
|
-// Specific JS used for the Structures layout
|
|
|
-// > Needs to be loaded after the main.js script
|
|
|
-$(document).ready(function() {
|
|
|
-
|
|
|
- const queryParameters = new URLSearchParams(window.location.search);
|
|
|
-
|
|
|
- // Init
|
|
|
- let document = $('html, body');
|
|
|
- let structureFrame = $('.ot-structures-frame').first();
|
|
|
- let structureFrameDetails = $('.ot-structures-frame-details').first();
|
|
|
-
|
|
|
- // let organizationId = structureFrame.data('org-id');
|
|
|
-
|
|
|
- let resultsPageDiv = structureFrame.find('.structures-page').first();
|
|
|
- let pleaseWaitSpan = structureFrame.find('.please-wait').first();
|
|
|
- let noResultSpan = structureFrame.find('.no-result').first();
|
|
|
- let errorMsgSpan = structureFrame.find(".error-message").first();
|
|
|
- let cardDivModel = structureFrame.find('.structure-card-model').first();
|
|
|
- let paginationBar = structureFrame.find('.pagination-bar').first();
|
|
|
- let paginationList = structureFrame.find('.pagination-list').first();
|
|
|
- let gotoFirstPage = structureFrame.find('.goto-first-page').first();
|
|
|
- let gotoLastPage = structureFrame.find('.goto-last-page').first();
|
|
|
- let resultsCountMessage = structureFrame.find('.results-count-message').first();
|
|
|
- let resultsCountVar = resultsCountMessage.find('.count').first();
|
|
|
- let detailsSection = structureFrame.find('.structure-see').first();
|
|
|
-
|
|
|
- let form = $("#structure-search-form");
|
|
|
- let whatInput = form.find("input[name='search-query']").first();
|
|
|
- let cityInput = form.find("input[name='search-city']").first();
|
|
|
- let latInput = form.find("input[name='lat']").first();
|
|
|
- let longInput = form.find("input[name='long']").first();
|
|
|
- let practiceSelect = form.find("select[name='search-practice']").first();
|
|
|
- let provinceSelect = form.find("select[name='search-province']").first();
|
|
|
- let federationSelect = form.find("select[name='search-federation']").first();
|
|
|
- let radiusSelect = form.find("select[name='search-radius']").first();
|
|
|
- let resetButton = form.find("button.reset-search").first();
|
|
|
- let submitButton = form.find("button.submit-search").first();
|
|
|
-
|
|
|
- let organizationId = parseInt(queryParameters.get('organization-id') || structureFrame.data('organization-id'));
|
|
|
- if (!organizationId) {
|
|
|
- pleaseWaitSpan.hide();
|
|
|
- errorMsgSpan.show();
|
|
|
- throw 'Missing organization-id parameter';
|
|
|
- }
|
|
|
-
|
|
|
- // #### Instanciate and populate leaflet maps
|
|
|
- let mapDiv = $('#structure-map').first();
|
|
|
- let mapId = $(mapDiv).attr("id");
|
|
|
-
|
|
|
- // Instanciate the map object @see https://leafletjs.com/reference-1.6.0.html#map-factory
|
|
|
- const mapOptions = {scrollWheelZoom: false, zoomSnap: 0.25};
|
|
|
- map = L.map(mapId, mapOptions);
|
|
|
- map.setView([46.71, 2.14], 6);
|
|
|
- L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
|
|
|
- attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
|
|
|
- }).addTo(map);
|
|
|
-
|
|
|
- var listenMapMoves = false;
|
|
|
-
|
|
|
- var defaultsBounds = [51.03, -5.78, 41.2, 9.70];
|
|
|
-
|
|
|
- // Set the view
|
|
|
- let resetMapBounds = function () {
|
|
|
- area = null;
|
|
|
- bounds = L.latLngBounds(
|
|
|
- L.latLng(defaultsBounds[0], defaultsBounds[1]),
|
|
|
- L.latLng(defaultsBounds[2], defaultsBounds[3])
|
|
|
- );
|
|
|
- map.fitBounds(bounds);
|
|
|
- }
|
|
|
- resetMapBounds();
|
|
|
-
|
|
|
- var clusters = null;
|
|
|
-
|
|
|
- // Details view map
|
|
|
- const structureMapOptions = {scrollWheelZoom: true, zoomSnap: 0.25};
|
|
|
- let structureMap = L.map('structure-details-map', structureMapOptions);
|
|
|
- L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
|
|
|
- attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
|
|
|
- }).addTo(structureMap);
|
|
|
-
|
|
|
- // Call this method when a map is hidden or shown to force a re-rendering
|
|
|
- function resizeMaps() {
|
|
|
- map.invalidateSize();
|
|
|
- structureMap.invalidateSize();
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- // #### Filters
|
|
|
-
|
|
|
- // The current query
|
|
|
- var query = {};
|
|
|
- var area = null;
|
|
|
-
|
|
|
- // Update the current query with form data
|
|
|
- function updateQuery() {
|
|
|
- query['what'] = whatInput.val();
|
|
|
- query['lat'] = latInput.val();
|
|
|
- query['long'] = longInput.val();
|
|
|
- query['practice'] = practiceSelect.val();
|
|
|
- query['province'] = provinceSelect.val();
|
|
|
- query['federation'] = federationSelect.val();
|
|
|
- query['radius'] = radiusSelect.val();
|
|
|
- }
|
|
|
-
|
|
|
- function updateArea(long1, lat1, long2, lat2) {
|
|
|
- area = [long1, lat1, long2, lat2];
|
|
|
- }
|
|
|
-
|
|
|
- // Does the given structure match the current query
|
|
|
- function matchCurrentQuery(structure) {
|
|
|
- // Is the structure a member of the website federation?
|
|
|
- if (![structure.n1Id, structure.n2Id, structure.n3Id, structure.n4Id, structure.n5Id].includes(organizationId)) {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- // Filter by name
|
|
|
- if (query['what'] && !structure.name.toLowerCase().includes(query['what'].toLowerCase())) {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- // filter by geographical position
|
|
|
- if (query['lat'] && query['long']) {
|
|
|
- if (!structure.latitude || !structure.longitude) {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- let radius = Number(query['radius']) ?? 0;
|
|
|
-
|
|
|
- // radius is increased by 10km to approximate the city radius
|
|
|
- radius += 10;
|
|
|
-
|
|
|
- if (sphericDistance(query['lat'], query['long'], structure.latitude, structure.longitude) > radius) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // filter by practice
|
|
|
- if (query['practice'] && !structure.practices.includes(query['practice'])) {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- if (query['province']) {
|
|
|
- let province = query['province'];
|
|
|
-
|
|
|
- // A leading '_' may have been added to prevent the '0' from being stripped by fluid
|
|
|
- province = province.replace('_', '');
|
|
|
-
|
|
|
- if (!structure.postalCode.startsWith(province)) {
|
|
|
- return false
|
|
|
- }
|
|
|
- }
|
|
|
- if (query['federation'] && !structure.parents.includes(Number(query['federation']))) {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- // filter by map bounds
|
|
|
- if (area !== null) {
|
|
|
- if (structure.longitude < area[0] ||
|
|
|
- structure.latitude < area[1] ||
|
|
|
- structure.longitude > area[2] ||
|
|
|
- structure.latitude > area[3]
|
|
|
- ) {
|
|
|
- if (structure.id == 498) {
|
|
|
- console.log(structure.longitude, structure.latitude, area);
|
|
|
- console.log(structure.longitude < area[0], structure.latitude < area[1], structure.longitude > area[2], structure.latitude > area[3])
|
|
|
- }
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- function populatePracticeSelect() {
|
|
|
- practiceSelect.children('option:not(:first)').remove();
|
|
|
- let has_options = false;
|
|
|
-
|
|
|
- for (const key in practicesFr) {
|
|
|
- let option = '<option value="' + key + '">' + practicesFr[key] + '</option>';
|
|
|
- practiceSelect.append(option);
|
|
|
- has_options = true;
|
|
|
- }
|
|
|
- if (has_options) {
|
|
|
- practiceSelect.prop("disabled", false);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- function populateFederationsSelect() {
|
|
|
- federationSelect.children('option:not(:first)').remove();
|
|
|
- let has_options = false;
|
|
|
-
|
|
|
- structures.forEach(function (structure) {
|
|
|
- if (structure.n1Id === organizationId && structure.principalType.endsWith('FEDERATION')) {
|
|
|
- let option = '<option value="' + structure.id + '">' + structure.name + '</option>';
|
|
|
- federationSelect.append(option);
|
|
|
- has_options = true;
|
|
|
- }
|
|
|
- })
|
|
|
- if (has_options) {
|
|
|
- federationSelect.prop("disabled", false);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // #### Display results
|
|
|
- const itemsPerPage = 8;
|
|
|
- let currentPage = 1;
|
|
|
-
|
|
|
- updateQuery();
|
|
|
-
|
|
|
- // on page link clicked event
|
|
|
- function pageLinkClicked(e) {
|
|
|
- e.preventDefault();
|
|
|
- let page = $(this).data('page');
|
|
|
- if (page > 0) {
|
|
|
- currentPage = page;
|
|
|
- }
|
|
|
- refresh();
|
|
|
- $('body,html').animate({scrollTop: 0},500);
|
|
|
- }
|
|
|
- gotoFirstPage.on('click', pageLinkClicked);
|
|
|
- gotoLastPage.on('click', pageLinkClicked);
|
|
|
-
|
|
|
- function refresh(listOnly=false) {
|
|
|
-
|
|
|
- // Reinitialize current results
|
|
|
- pleaseWaitSpan.show();
|
|
|
- listenMapMoves = false;
|
|
|
-
|
|
|
- resultsPageDiv.find('.structure-card').remove();
|
|
|
- paginationList.find('.goto-page-li').remove();
|
|
|
- paginationList.hide();
|
|
|
- if (!listOnly && clusters !== null) {
|
|
|
- map.removeLayer(clusters);
|
|
|
- }
|
|
|
-
|
|
|
- // ** Update results
|
|
|
- let results = [];
|
|
|
- structures.forEach(function(structure) {
|
|
|
- if (matchCurrentQuery(structure)) {
|
|
|
- results.push(structure)
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- sortKeys = function (x) {
|
|
|
- return x.addressCity.toLowerCase() + x.name.toLowerCase();
|
|
|
- }
|
|
|
- results.sort((a, b) => sortKeys(a).localeCompare(sortKeys(b)));
|
|
|
-
|
|
|
- // ** Show the results for the current page
|
|
|
- let index = 0;
|
|
|
-
|
|
|
- results.forEach(function(structure) {
|
|
|
- if (((currentPage - 1) * itemsPerPage) <= index && index < (currentPage * itemsPerPage)) {
|
|
|
- let cardDiv = $(cardDivModel).clone();
|
|
|
- let practiceTagModel = cardDiv.find('.structure-practice-model').first();
|
|
|
-
|
|
|
- cardDiv.data('id', structure.id);
|
|
|
-
|
|
|
- if (structure.practices !== null) {
|
|
|
- let i = 1;
|
|
|
- for (const practice of structure.practices) {
|
|
|
- let tag = practiceTagModel.clone();
|
|
|
-
|
|
|
- if (i <= 3) {
|
|
|
- tag.text(practicesFr[practice]);
|
|
|
- } else {
|
|
|
- tag.text('+ ' + (practice.length - 3) + ' ...');
|
|
|
- }
|
|
|
- tag.removeClass('structure-practice-model')
|
|
|
- tag.addClass('structure-practice')
|
|
|
- tag.show();
|
|
|
- practiceTagModel.parent().append(tag);
|
|
|
-
|
|
|
- if (i > 3) { break; }
|
|
|
- i++;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (structure.logoId) {
|
|
|
- let poster = cardDiv.find('.structure-poster').first().children('img').first();
|
|
|
- poster.attr('src', 'https://api.opentalent.fr/app.php/_internal/secure/files/' + structure.logoId + '/0x60');
|
|
|
- }
|
|
|
-
|
|
|
- let cardTitle = cardDiv.find('.structure-name a').first();
|
|
|
- cardTitle.text(structure.name);
|
|
|
- cardTitle.attr('href', structure.website);
|
|
|
-
|
|
|
- cardDiv.find('.structure-details-address').first().text(
|
|
|
- [structure.streetAddress, structure.postalCode, structure.addressCity].join(" ")
|
|
|
- );
|
|
|
- cardDiv.find('.structure-details-federation').first().text(structure.n1Name);
|
|
|
-
|
|
|
- cardDiv.find('.structure-see').first().data('organization-id', structure.id)
|
|
|
-
|
|
|
- cardDiv.show();
|
|
|
- cardDiv.removeClass('structure-card-model');
|
|
|
- cardDiv.addClass('structure-card');
|
|
|
- cardDiv.appendTo(resultsPageDiv);
|
|
|
- }
|
|
|
- index++;
|
|
|
- });
|
|
|
-
|
|
|
- // ** Update results on map
|
|
|
- if (!listOnly) {
|
|
|
- clusters = L.markerClusterGroup();
|
|
|
-
|
|
|
- results.forEach(function (item) {
|
|
|
- if (item.longitude && item.latitude) {
|
|
|
- let marker = L.marker([item.latitude, item.longitude]);
|
|
|
- marker.bindPopup(`<b>${item.name}</b><br/>${item.postalCode} ${item.addressCity}<br/><a href="${item.website}" target="_blank">${item.website}</a>`);
|
|
|
- clusters.addLayer(marker);
|
|
|
- }
|
|
|
- });
|
|
|
- map.addLayer(clusters);
|
|
|
- }
|
|
|
-
|
|
|
- // ** Update results count and pagination
|
|
|
- let resultsCount = results.length;
|
|
|
-
|
|
|
- resultsCountMessage.show();
|
|
|
- resultsCountVar.text("" + resultsCount);
|
|
|
-
|
|
|
- let pagesCount = Math.floor(resultsCount / itemsPerPage) + 1;
|
|
|
- gotoLastPage.data("page", pagesCount);
|
|
|
-
|
|
|
- let pageLiModel = paginationList.find('.goto-page-li-model').first();
|
|
|
-
|
|
|
- let page_min = currentPage > 5 ? currentPage - 5 : 1;
|
|
|
- let page_max = currentPage < (pagesCount - 5) ? currentPage + 5 : pagesCount;
|
|
|
-
|
|
|
- for (let i = page_min; i <= page_max; i++) {
|
|
|
- let pageLi = pageLiModel.clone();
|
|
|
-
|
|
|
- let pageLink = pageLi.children('a').first();
|
|
|
-
|
|
|
- pageLink.text("" + i);
|
|
|
- pageLink.attr("data-page", i);
|
|
|
- pageLink.on('click', pageLinkClicked)
|
|
|
-
|
|
|
- if (i === currentPage) {
|
|
|
- pageLi.addClass('current');
|
|
|
- }
|
|
|
- pageLi.removeClass('goto-page-li-model')
|
|
|
- pageLi.addClass('goto-page-li')
|
|
|
-
|
|
|
- pageLi.show();
|
|
|
-
|
|
|
- pageLi.appendTo(paginationList);
|
|
|
- }
|
|
|
- paginationBar.show()
|
|
|
- paginationList.show()
|
|
|
-
|
|
|
- // Finalize
|
|
|
- pleaseWaitSpan.hide();
|
|
|
- listenMapMoves = true;
|
|
|
- }
|
|
|
-
|
|
|
- function fitMapToResults() {
|
|
|
- bounds = clusters.getBounds();
|
|
|
- if (bounds.isValid()) {
|
|
|
- map.fitBounds(bounds);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // #### Load structures data and refresh
|
|
|
- var structures;
|
|
|
-
|
|
|
- populatePracticeSelect();
|
|
|
-
|
|
|
- function loadStructures() {
|
|
|
- structures = []
|
|
|
-
|
|
|
- $.ajax({
|
|
|
- type: 'GET',
|
|
|
- url: apiGetAllUrl,
|
|
|
- dataType: "json",
|
|
|
- contentType: "application/json; charset=utf-8",
|
|
|
- timeout : 12000,
|
|
|
- })
|
|
|
- .done(function(res) {
|
|
|
-
|
|
|
- res.forEach(function(item) {
|
|
|
- structure = item;
|
|
|
- structure.n1Id = parseInt(structure.n1Id);
|
|
|
- structure.n2Id = parseInt(structure.n2Id);
|
|
|
- structure.n3Id = parseInt(structure.n3Id);
|
|
|
- structure.n4Id = parseInt(structure.n4Id);
|
|
|
- structure.n5Id = parseInt(structure.n5Id);
|
|
|
- structure.practices = structure.practices !== null ? structure.practices.split(",") : [];
|
|
|
- structures.push(structure);
|
|
|
- })
|
|
|
-
|
|
|
- populateFederationsSelect();
|
|
|
- refresh();
|
|
|
- })
|
|
|
- .fail(function(xhr, textStatus, errorThrown) {
|
|
|
- pleaseWaitSpan.hide();
|
|
|
- errorMsgSpan.show();
|
|
|
- throw 'Error while fetching the API data: ' + textStatus + ' - ' + errorThrown;
|
|
|
- });
|
|
|
- }
|
|
|
- loadStructures();
|
|
|
-
|
|
|
-
|
|
|
- // #### Events
|
|
|
-
|
|
|
- // Update query
|
|
|
- form.on('submit', function(e) {
|
|
|
- e.preventDefault();
|
|
|
- updateQuery();
|
|
|
- area = null;
|
|
|
- currentPage = 1;
|
|
|
- refresh();
|
|
|
- if (Object.values(query).some((k) => k)) {
|
|
|
- // if it's not an empty query, fit to results
|
|
|
- fitMapToResults();
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- submitButton.on('click', function() {
|
|
|
- form.submit();
|
|
|
- });
|
|
|
-
|
|
|
- $('.filters select', form).on('change', function() {
|
|
|
- form.submit();
|
|
|
- });
|
|
|
-
|
|
|
- // Reset search fields
|
|
|
- resetButton.on('click', function (e) {
|
|
|
- e.preventDefault();
|
|
|
- let form = $(this).closest('form');
|
|
|
- form.find('input').each(function () {
|
|
|
- $(this).val('');
|
|
|
- });
|
|
|
- form.find('select').each(function () {
|
|
|
- $(this).val('');
|
|
|
- });
|
|
|
- resetMapBounds();
|
|
|
- form.submit();
|
|
|
- });
|
|
|
-
|
|
|
- // Map goto commands
|
|
|
- $('img[data-map-fit]').on('click', function (e) {
|
|
|
- let goto = $(this).data('map-fit');
|
|
|
- let corners = goto.split(";");
|
|
|
- let p1 = corners[0].split(",");
|
|
|
- let p2 = corners[1].split(",");
|
|
|
- let bounds = L.latLngBounds(L.latLng(p1[0], p1[1]), L.latLng(p2[0], p2[1]));
|
|
|
- map.fitBounds(bounds);
|
|
|
- });
|
|
|
-
|
|
|
- // Toggle structures list and map view
|
|
|
- let filtersRow = form.find('.filters').first();
|
|
|
- let buttonsRow = form.find('.search-buttons').first();
|
|
|
-
|
|
|
- $('.activate-map-view').on('click', function (e) {
|
|
|
- e.preventDefault();
|
|
|
- if (structureFrame.hasClass('map-view')) {
|
|
|
- // already in map view
|
|
|
- return;
|
|
|
- }
|
|
|
- listenMapMoves = true;
|
|
|
- structureFrame.removeClass('list-view');
|
|
|
- structureFrame.addClass('map-view');
|
|
|
-
|
|
|
- // move reset and submit buttons
|
|
|
- submitButton.appendTo(buttonsRow);
|
|
|
- resetButton.prependTo(buttonsRow);
|
|
|
- buttonsRow.show();
|
|
|
-
|
|
|
- resizeMaps();
|
|
|
- })
|
|
|
- $('.activate-list-view').on('click', function (e) {
|
|
|
- e.preventDefault();
|
|
|
- if (structureFrame.hasClass('list-view')) {
|
|
|
- // already in list view
|
|
|
- return;
|
|
|
- }
|
|
|
- listenMapMoves = false;
|
|
|
- structureFrame.removeClass('map-view');
|
|
|
- structureFrame.addClass('list-view');
|
|
|
-
|
|
|
- // move reset and submit buttons
|
|
|
- submitButton.appendTo(filtersRow);
|
|
|
- resetButton.prependTo(filtersRow);
|
|
|
- buttonsRow.hide();
|
|
|
-
|
|
|
- resetButton.prependTo()
|
|
|
-
|
|
|
-
|
|
|
- resetMapBounds();
|
|
|
- })
|
|
|
-
|
|
|
- // Filter results on map moves
|
|
|
- map.on('zoomend moveend', function(e) {
|
|
|
- if (listenMapMoves) {
|
|
|
- let bounds = map.getBounds();
|
|
|
- updateArea(bounds.getWest(), bounds.getSouth(), bounds.getEast(), bounds.getNorth())
|
|
|
- refresh(true);
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- // ### Location filter
|
|
|
- let resultDropdownDiv = form.find('.city-search-dropdown').first();
|
|
|
- let inputName = resultDropdownDiv.siblings("input[name='search-city']").first();
|
|
|
- let inputLat = resultDropdownDiv.siblings("input[name='lat']").first();
|
|
|
- let inputLong = resultDropdownDiv.siblings("input[name='long']").first();
|
|
|
- let resultDiv = resultDropdownDiv.find('.city-search-results').first();
|
|
|
- let loadingDiv = resultDropdownDiv.find('.city-search-loading').first();
|
|
|
- let noResultDiv = resultDropdownDiv.find('.city-search-no-result').first();
|
|
|
- let geolocButton = form.find("button[name='search-localize']").first();
|
|
|
-
|
|
|
- function setNewLocation(name, long, lat) {
|
|
|
- inputName.val(name);
|
|
|
- inputLong.val(long);
|
|
|
- inputLat.val(lat);
|
|
|
- inputName.css("cursor", "pointer");
|
|
|
- resultDropdownDiv.hide();
|
|
|
- if (radiusSelect.val() === '') {
|
|
|
- radiusSelect.val('10')
|
|
|
- }
|
|
|
- form.submit();
|
|
|
- }
|
|
|
-
|
|
|
- function hideCityResults() {
|
|
|
- resultDropdownDiv.hide();
|
|
|
- // if no city was selected, clear the input
|
|
|
- if (!inputLat.val()) {
|
|
|
- inputName.val('');
|
|
|
- resultDiv.empty();
|
|
|
- }
|
|
|
- inputName.css("cursor", "inherit");
|
|
|
- inputName.removeClass('loading');
|
|
|
- }
|
|
|
-
|
|
|
- document.click(function() {
|
|
|
- hideCityResults();
|
|
|
- });
|
|
|
-
|
|
|
- $(document).keydown(function(e) {
|
|
|
- if(e.key === "Escape") {
|
|
|
- hideCityResults();
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- inputName.click(function(e) {
|
|
|
- if (resultDiv.children('.city-search-item').length > 0) {
|
|
|
- resultDropdownDiv.show();
|
|
|
- }
|
|
|
- e.stopPropagation();
|
|
|
- });
|
|
|
-
|
|
|
- inputName.keypress(function (e) {
|
|
|
- if (e.key === "Enter") {
|
|
|
-
|
|
|
- let results = resultDiv.children('.city-search-item');
|
|
|
-
|
|
|
- if (inputName.hasClass('loading')) {
|
|
|
- // A request is currently running, enter will select the first result when the request will complete
|
|
|
- inputName.addClass('enter-pressed');
|
|
|
- e.preventDefault();
|
|
|
- } else if (results.length > 0) {
|
|
|
- // If results are displayed and no request is currently running, enter select the first result
|
|
|
- setNewLocation(results[0].text(), results[0].data("x"), results[0].data("y"))
|
|
|
- e.stopPropagation();
|
|
|
- }
|
|
|
- } else {
|
|
|
- inputName.addClass('loading');
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- resultDiv.on('click', '.city-search-item', function (e) {
|
|
|
- setNewLocation($(this).text(), $(this).data("x"), $(this).data("y"))
|
|
|
- e.stopPropagation();
|
|
|
- });
|
|
|
-
|
|
|
- inputName.on('click', function(e) {
|
|
|
- if ($(this).is(":focus")) {
|
|
|
- $(this).val('');
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- // gouv.fr REST geocoding api
|
|
|
- const addressApiUrl = "https://api-adresse.data.gouv.fr/search/?type=municipality&autocomplete=1&limit=5&q=";
|
|
|
-
|
|
|
- function populateCitySearchResults() {
|
|
|
-
|
|
|
- let query = inputName.val();
|
|
|
- let url = addressApiUrl + encodeURI(query);
|
|
|
-
|
|
|
- if (!query) {
|
|
|
- resultDropdownDiv.hide();
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- inputLat.val('');
|
|
|
- inputLong.val('');
|
|
|
- resultDropdownDiv.show();
|
|
|
- if (resultDiv.children('.city-search-item').length === 0) {
|
|
|
- loadingDiv.show()
|
|
|
- }
|
|
|
- noResultDiv.hide();
|
|
|
-
|
|
|
- $.ajax({
|
|
|
- type: 'GET',
|
|
|
- url: url,
|
|
|
- dataType: "json",
|
|
|
- contentType: "application/json; charset=utf-8"
|
|
|
- })
|
|
|
- .done(function(res) {
|
|
|
- console.log(res);
|
|
|
- let features = res.features;
|
|
|
- resultDiv.empty();
|
|
|
-
|
|
|
- if (!features.length > 0) {
|
|
|
- noResultDiv.show();
|
|
|
- resultDiv.hide();
|
|
|
- } else if (inputName.hasClass('enter-pressed')) {
|
|
|
- // the enter key has been pressed before the request terminate
|
|
|
- let f = features[0];
|
|
|
- setNewLocation(
|
|
|
- f.properties.name + ' (' + f.properties.postcode + ')',
|
|
|
- f.geometry.coordinates[0],
|
|
|
- f.geometry.coordinates[1]
|
|
|
- )
|
|
|
- resultDiv.hide();
|
|
|
- } else {
|
|
|
- for (const f of features) {
|
|
|
- let x = f.geometry.coordinates[0];
|
|
|
- let y = f.geometry.coordinates[1];
|
|
|
- let name = f.properties.name;
|
|
|
- let postcode = f.properties.postcode;
|
|
|
- let span = '<div class="city-search-item" data-x="' + x + '" data-y="' + y + '">' + name + ' (' + postcode + ')</div>';
|
|
|
- resultDiv.append(span);
|
|
|
- }
|
|
|
- resultDiv.show();
|
|
|
- }
|
|
|
- inputName.removeClass('loading');
|
|
|
- inputName.removeClass('enter-pressed');
|
|
|
- loadingDiv.hide()
|
|
|
- })
|
|
|
- .fail(function(e) {
|
|
|
- console.error(e);
|
|
|
- loadingDiv.hide();
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- var runningPopulate = null;
|
|
|
-
|
|
|
- inputName.on('input', function(e) {
|
|
|
- if (runningPopulate !== null) {
|
|
|
- window.clearTimeout(runningPopulate)
|
|
|
- }
|
|
|
- runningPopulate = window.setTimeout(populateCitySearchResults, 300);
|
|
|
- });
|
|
|
-
|
|
|
- geolocButton.on('click', function(e) {
|
|
|
- if (navigator.geolocation) {
|
|
|
- navigator.geolocation.getCurrentPosition(
|
|
|
- function (geoloc) {
|
|
|
- setNewLocation(tr['around-me'], geoloc.coords.longitude, geoloc.coords.latitude)
|
|
|
- e.stopPropagation();
|
|
|
- },
|
|
|
- function () {
|
|
|
- alert(tr['geoloc-unavailable']);
|
|
|
- }
|
|
|
- );
|
|
|
- e.stopPropagation();
|
|
|
- } else {
|
|
|
- alert(tr['geoloc-unsupported']);
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- // Structure details
|
|
|
- function formatFrenchPhoneNumber(number) {
|
|
|
- const regexPhoneNumber = /\+33([1-9])(\d{2})(\d{2})(\d{2})(\d{2})$/;
|
|
|
-
|
|
|
- if (number && number.match(regexPhoneNumber)) {
|
|
|
- return number.replace(regexPhoneNumber, '0$1 $2 $3 $4 $5');
|
|
|
- } else {
|
|
|
- return number;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- function populateDetailsView(structure) {
|
|
|
-
|
|
|
- const structureHeader = structureFrameDetails.find('.structure-header').first();
|
|
|
-
|
|
|
- let logo = structureHeader.find('img.logo').first();
|
|
|
- let defaultLogo = structureHeader.find('img.default-logo').first();
|
|
|
- if (structure.logoId) {
|
|
|
- logo.attr('src', 'https://api.opentalent.fr/app.php/_internal/secure/files/' + structure.logoId + '/0x60');
|
|
|
- logo.show();
|
|
|
- defaultLogo.hide();
|
|
|
- } else {
|
|
|
- defaultLogo.show();
|
|
|
- logo.hide();
|
|
|
- }
|
|
|
-
|
|
|
- let title = structureHeader.find('.structure-name').first();
|
|
|
- title.text(structure.name);
|
|
|
-
|
|
|
- let fbLink = structureHeader.find('a.facebook').first();
|
|
|
- if (structure.facebook) {
|
|
|
- fbLink.attr('href', structure.facebook);
|
|
|
- fbLink.show();
|
|
|
- } else {
|
|
|
- fbLink.attr('href', '');
|
|
|
- fbLink.hide();
|
|
|
- }
|
|
|
-
|
|
|
- let twitterLink = structureHeader.find('a.twitter').first();
|
|
|
- if (structure.twitter) {
|
|
|
- twitterLink.attr('href', structure.twitter);
|
|
|
- twitterLink.show();
|
|
|
- } else {
|
|
|
- twitterLink.attr('href', '');
|
|
|
- twitterLink.hide();
|
|
|
- }
|
|
|
-
|
|
|
- let instagramLink = structureHeader.find('a.instagram').first();
|
|
|
- if (structure.instagram) {
|
|
|
- instagramLink.attr('href', structure.instagram);
|
|
|
- instagramLink.show();
|
|
|
- } else {
|
|
|
- instagramLink.attr('href', '');
|
|
|
- instagramLink.hide();
|
|
|
- }
|
|
|
-
|
|
|
- let practiceTagModel = structureFrameDetails.find('.structure-practice-model').first();
|
|
|
- let practiceContainer = practiceTagModel.parent();
|
|
|
- practiceContainer.children('.structure-practice').remove();
|
|
|
-
|
|
|
- if (structure.practices !== null) {
|
|
|
- let i = 1;
|
|
|
- for (const practice of structure.practices) {
|
|
|
- let tag = practiceTagModel.clone();
|
|
|
-
|
|
|
- if (i <= 3) {
|
|
|
- tag.text(practicesFr[practice]);
|
|
|
- } else {
|
|
|
- tag.text('+ ' + (practice.length - 3) + ' ...');
|
|
|
- }
|
|
|
- tag.removeClass('structure-practice-model')
|
|
|
- tag.addClass('structure-practice')
|
|
|
- tag.show();
|
|
|
- practiceContainer.append(tag);
|
|
|
-
|
|
|
- if (i > 3) { break; }
|
|
|
- i++;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- let contact = structureFrameDetails.find('.contact').first();
|
|
|
- contact.find('.address').first().text(
|
|
|
- [structure.streetAddress, structure.postalCode, structure.addressCity].join(" ")
|
|
|
- );
|
|
|
-
|
|
|
- let phoneLink = contact.find('.phone a').first();
|
|
|
- if (structure.telphone) {
|
|
|
- phoneLink.text(formatFrenchPhoneNumber(structure.telphone));
|
|
|
- phoneLink.attr('href', 'tel:' + structure.telphone);
|
|
|
- } else {
|
|
|
- phoneLink.text('');
|
|
|
- phoneLink.attr('href', '');
|
|
|
- }
|
|
|
-
|
|
|
- let mailLink = contact.find('.mail a').first();
|
|
|
- if (structure.email) {
|
|
|
- mailLink.text(structure.email);
|
|
|
- mailLink.attr('href', 'mailto:' + structure.email);
|
|
|
- } else {
|
|
|
- mailLink.text('');
|
|
|
- mailLink.attr('href', '');
|
|
|
- }
|
|
|
-
|
|
|
- let websiteLink = contact.find('.website a').first();
|
|
|
- if (structure.website) {
|
|
|
- websiteLink.text(structure.website);
|
|
|
- websiteLink.attr('href', structure.website);
|
|
|
- } else {
|
|
|
- websiteLink.text('');
|
|
|
- websiteLink.attr('href', '');
|
|
|
- }
|
|
|
-
|
|
|
- // contact.find('.province').first().text('...');
|
|
|
-
|
|
|
- let networkName = contact.find('.network').first();
|
|
|
- if (structure.n1Name) {
|
|
|
- networkName.text(structure.n1Name);
|
|
|
- } else {
|
|
|
- networkName.text('');
|
|
|
- }
|
|
|
-
|
|
|
- if (structure.longitude && structure.latitude) {
|
|
|
- // clear previous markers
|
|
|
- structureMap.eachLayer(function(layer) {
|
|
|
- if (layer instanceof L.MarkerClusterGroup) { map.removeLayer(layer) }
|
|
|
- })
|
|
|
-
|
|
|
- // add structure position
|
|
|
- let marker = L.marker([structure.latitude, structure.longitude]);
|
|
|
- marker.bindPopup(`<b>${structure.name}</b><br/>${structure.postalCode} ${structure.addressCity}<br/><a href="${structure.website}" target="_blank">${structure.website}</a>`);
|
|
|
- marker.addTo(structureMap);
|
|
|
-
|
|
|
- // zoom on the newly created marker
|
|
|
- var latLngs = [ marker.getLatLng() ];
|
|
|
- var markerBounds = L.latLngBounds(latLngs);
|
|
|
- structureMap.fitBounds(markerBounds);
|
|
|
-
|
|
|
- // show map
|
|
|
- structureFrameDetails.find('#structure-details-map').first().show();
|
|
|
- }
|
|
|
-
|
|
|
- // ux fix: don't know why, but the topbar is above the screen without this
|
|
|
- structureFrameDetails.scrollTop(0);
|
|
|
- }
|
|
|
-
|
|
|
- structureFrame.on('click', '.structure-see', function(e) {
|
|
|
- e.preventDefault();
|
|
|
- const organizationId = $(this).data('organization-id');
|
|
|
-
|
|
|
- structureFrame.hide();
|
|
|
- structureFrameDetails.show();
|
|
|
-
|
|
|
- $.ajax({
|
|
|
- type: 'GET',
|
|
|
- url: apiGetByIdUrl + '&organization-id=' + organizationId,
|
|
|
- dataType: "json",
|
|
|
- contentType: "application/json; charset=utf-8",
|
|
|
- timeout : 5000
|
|
|
- })
|
|
|
- .done(function(structure) {
|
|
|
- structure.practices = structure.practices !== null ? structure.practices.split(",") : [];
|
|
|
- populateDetailsView(structure)
|
|
|
-
|
|
|
- structureFrameDetails.find('.please-wait').first().hide();
|
|
|
- structureFrameDetails.find('.content').first().show();
|
|
|
- resizeMaps();
|
|
|
- })
|
|
|
- .fail(function(xhr, textStatus, errorThrown) {
|
|
|
- pleaseWaitSpan.hide();
|
|
|
- errorMsgSpan.show();
|
|
|
- throw 'Error while fetching the API data: ' + textStatus + ' - ' + errorThrown;
|
|
|
- });
|
|
|
- })
|
|
|
-
|
|
|
- structureFrameDetails.on('click', '.go-back', function (e) {
|
|
|
- e.preventDefault();
|
|
|
-
|
|
|
- structureFrameDetails.find('.please-wait').first().show();
|
|
|
- structureFrameDetails.find('.content').first().hide();
|
|
|
- structureFrameDetails.hide();
|
|
|
- structureFrame.show();
|
|
|
- resizeMaps();
|
|
|
- })
|
|
|
-});
|