Make all location champs autocomplete
This commit is contained in:
parent
0ef25ef36c
commit
22aa2d4ee0
19 changed files with 187 additions and 61 deletions
|
@ -242,6 +242,16 @@
|
|||
}
|
||||
}
|
||||
|
||||
.select2-selection--single {
|
||||
min-height: 62px;
|
||||
|
||||
// scss-lint:disable SelectorFormat
|
||||
.select2-selection__arrow {
|
||||
display: none;
|
||||
}
|
||||
// scss-lint:enable
|
||||
}
|
||||
|
||||
// scss-lint:disable SelectorFormat
|
||||
.select2-selection__rendered {
|
||||
padding: $default-padding;
|
||||
|
|
|
@ -63,6 +63,10 @@
|
|||
width: 200px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.select2-container {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -117,6 +117,7 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
def setup_javascript_settings
|
||||
gon.autosave = Rails.application.config.ds_autosave
|
||||
gon.autocomplete = Rails.application.secrets.autocomplete
|
||||
end
|
||||
|
||||
def setup_tracking
|
||||
|
|
|
@ -1,46 +1,158 @@
|
|||
import $ from 'jquery';
|
||||
import 'select2';
|
||||
|
||||
const optionTemplate = email =>
|
||||
const { api_geo_url, api_adresse_url } = gon.autocomplete || {};
|
||||
|
||||
const language = {
|
||||
errorLoading: function() {
|
||||
return 'Les résultats ne peuvent pas être chargés.';
|
||||
},
|
||||
inputTooLong: function(args) {
|
||||
var overChars = args.input.length - args.maximum;
|
||||
|
||||
return 'Supprimez ' + overChars + ' caractère' + (overChars > 1 ? 's' : '');
|
||||
},
|
||||
inputTooShort: function(args) {
|
||||
var remainingChars = args.minimum - args.input.length;
|
||||
|
||||
return (
|
||||
'Saisissez au moins ' +
|
||||
remainingChars +
|
||||
' caractère' +
|
||||
(remainingChars > 1 ? 's' : '')
|
||||
);
|
||||
},
|
||||
loadingMore: function() {
|
||||
return 'Chargement de résultats supplémentaires…';
|
||||
},
|
||||
maximumSelected: function(args) {
|
||||
return (
|
||||
'Vous pouvez seulement sélectionner ' +
|
||||
args.maximum +
|
||||
' élément' +
|
||||
(args.maximum > 1 ? 's' : '')
|
||||
);
|
||||
},
|
||||
noResults: function() {
|
||||
return 'Aucun résultat trouvé';
|
||||
},
|
||||
searching: function() {
|
||||
return 'Recherche en cours…';
|
||||
},
|
||||
removeAllItems: function() {
|
||||
return 'Supprimer tous les éléments';
|
||||
}
|
||||
};
|
||||
|
||||
const baseOptions = {
|
||||
language,
|
||||
width: '100%'
|
||||
};
|
||||
|
||||
const baseAjaxOptions = {
|
||||
delay: 250,
|
||||
cache: true,
|
||||
data({ term: nom }) {
|
||||
return {
|
||||
nom,
|
||||
fields: 'nom,code'
|
||||
};
|
||||
},
|
||||
processResults(data) {
|
||||
return {
|
||||
results: data.map(({ nom }) => ({ id: nom, text: nom }))
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const regionsOptions = {
|
||||
...baseOptions,
|
||||
minimumInputLength: 2,
|
||||
ajax: { url: `${api_geo_url}/regions`, ...baseAjaxOptions }
|
||||
};
|
||||
|
||||
const communesOptions = {
|
||||
...baseOptions,
|
||||
minimumInputLength: 2,
|
||||
ajax: { url: `${api_geo_url}/communes`, ...baseAjaxOptions }
|
||||
};
|
||||
|
||||
const etranger99 = { id: '99 - Étranger', text: '99 - Étranger' };
|
||||
const departementsOptions = {
|
||||
...baseOptions,
|
||||
minimumInputLength: 2,
|
||||
ajax: {
|
||||
...baseAjaxOptions,
|
||||
url: `${api_geo_url}/departements`,
|
||||
processResults(data) {
|
||||
return {
|
||||
results: data
|
||||
.map(({ nom, code }) => ({
|
||||
id: `${code} - ${nom}`,
|
||||
text: `${code} - ${nom}`
|
||||
}))
|
||||
.concat([etranger99])
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const adresseOptions = {
|
||||
...baseOptions,
|
||||
minimumInputLength: 2,
|
||||
ajax: {
|
||||
...baseAjaxOptions,
|
||||
url: `${api_adresse_url}/search`,
|
||||
data({ term: q }) {
|
||||
return {
|
||||
q,
|
||||
limit: 5
|
||||
};
|
||||
},
|
||||
processResults(data) {
|
||||
return {
|
||||
results: data.features.map(({ properties: { label }, geometry }) => ({
|
||||
id: label,
|
||||
text: label,
|
||||
geometry
|
||||
}))
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const templateOption = ({ text }) =>
|
||||
$(
|
||||
'<span class="custom-select2-option"><span class="icon person"></span>' +
|
||||
email.text +
|
||||
'</span>'
|
||||
`<span class="custom-select2-option"><span class="icon person"></span>${text}</span>`
|
||||
);
|
||||
|
||||
addEventListener('ds:page:update', () => {
|
||||
$('select.select2').select2({
|
||||
language: 'fr',
|
||||
width: '100%'
|
||||
});
|
||||
$('select.select2').select2(baseOptions);
|
||||
$('select.select2.departements').select2(departementsOptions);
|
||||
$('select.select2.regions').select2(regionsOptions);
|
||||
$('select.select2.communes').select2(communesOptions);
|
||||
$('select.select2.adresse').select2(adresseOptions);
|
||||
|
||||
$('.columns-form select.select2-limited').select2({
|
||||
language: 'fr',
|
||||
width: '300px',
|
||||
placeholder: 'Sélectionnez des colonnes',
|
||||
maximumSelectionLength: '5',
|
||||
width: '300px'
|
||||
maximumSelectionLength: '5'
|
||||
});
|
||||
|
||||
$('.recipients-form select.select2-limited').select2({
|
||||
language: 'fr',
|
||||
language,
|
||||
width: '300px',
|
||||
placeholder: 'Sélectionnez des instructeurs',
|
||||
maximumSelectionLength: '30',
|
||||
width: '300px'
|
||||
maximumSelectionLength: '30'
|
||||
});
|
||||
|
||||
$('select.select2-limited.select-instructeurs').select2({
|
||||
language: 'fr',
|
||||
language,
|
||||
dropdownParent: $('.instructeur-wrapper'),
|
||||
placeholder: 'Saisir l’adresse email de l’instructeur',
|
||||
tags: true,
|
||||
tokenSeparators: [',', ' '],
|
||||
templateResult: optionTemplate,
|
||||
templateSelection: function(email) {
|
||||
return $(
|
||||
'<span class="custom-select2-option"><span class="icon person"></span>' +
|
||||
email.text +
|
||||
'</span>'
|
||||
);
|
||||
}
|
||||
templateResult: templateOption,
|
||||
templateSelection: templateOption
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,7 +8,6 @@ import '../shared/page-update-event';
|
|||
import '../shared/activestorage/ujs';
|
||||
import '../shared/rails-ujs-fix';
|
||||
import '../shared/safari-11-file-xhr-workaround';
|
||||
import '../shared/autocomplete';
|
||||
import '../shared/remote-input';
|
||||
import '../shared/franceconnect';
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ import '../shared/activestorage/ujs';
|
|||
import '../shared/activestorage/attachment-checker';
|
||||
import '../shared/rails-ujs-fix';
|
||||
import '../shared/safari-11-file-xhr-workaround';
|
||||
import '../shared/autocomplete';
|
||||
import '../shared/remote-input';
|
||||
import '../shared/franceconnect';
|
||||
import '../shared/toggle-target';
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* globals FreeDraw L */
|
||||
import { fire, getJSON, delegate } from '@utils';
|
||||
import { fire, delegate } from '@utils';
|
||||
import $ from 'jquery';
|
||||
|
||||
import polygonArea from './polygon_area';
|
||||
|
||||
|
@ -113,14 +114,6 @@ function drawParcellesAgricoles(map, { parcellesAgricoles }, editable = false) {
|
|||
);
|
||||
}
|
||||
|
||||
function geocodeAddress(map, query) {
|
||||
getJSON('/address/geocode', { request: query }).then(data => {
|
||||
if (data.lat !== null) {
|
||||
map.setView(new L.LatLng(data.lat, data.lon), data.zoom);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getCurrentMap(element) {
|
||||
if (!element.matches('.carte')) {
|
||||
const closestCarteElement = element.closest('.carte');
|
||||
|
@ -246,10 +239,12 @@ delegate('click', '.toolbar .new-area', event => {
|
|||
}
|
||||
});
|
||||
|
||||
delegate('autocomplete:select', '.toolbar [data-address]', event => {
|
||||
$(document).on('select2:select', 'select[data-address]', event => {
|
||||
const map = getCurrentMap(event.target);
|
||||
const { geometry } = event.params.data;
|
||||
|
||||
if (map) {
|
||||
geocodeAddress(map, event.detail.label);
|
||||
if (map && geometry && geometry.type === 'Point') {
|
||||
const [lon, lat] = geometry.coordinates;
|
||||
map.setView(new L.LatLng(lat, lon), 14);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,5 +1,2 @@
|
|||
class Champs::DepartementChamp < Champs::TextChamp
|
||||
def self.departements
|
||||
ApiGeo::API.departements.map { |liste| "#{liste[:code]} - #{liste[:nom]}" }.push('99 - Étranger')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
class Champs::PaysChamp < Champs::TextChamp
|
||||
PAYS = JSON.parse(Rails.root.join('app', 'lib', 'api_geo', 'pays.json').read, symbolize_names: true)
|
||||
|
||||
def self.pays
|
||||
ApiGeo::API.pays.pluck(:nom)
|
||||
PAYS.pluck(:nom)
|
||||
end
|
||||
|
||||
def self.disabled_options
|
||||
|
|
|
@ -1,5 +1,2 @@
|
|||
class Champs::RegionChamp < Champs::TextChamp
|
||||
def self.regions
|
||||
ApiGeo::API.regions.sort_by { |e| e[:nom] }.pluck(:nom)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
= form.text_field :value,
|
||||
data: { address: true, autocomplete: 'address' },
|
||||
placeholder: champ.libelle,
|
||||
required: champ.mandatory?
|
||||
= form.select :value, [champ.value].compact,
|
||||
{ include_blank: true },
|
||||
required: champ.mandatory?,
|
||||
class: 'select2 adresse'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.toolbar
|
||||
%button.button.primary.new-area Ajouter une zone
|
||||
%input.address{ data: { address: true, autocomplete: 'address' }, placeholder: 'Saisissez une adresse ou positionner la carte' }
|
||||
%select.select2.adresse{ data: { address: true }, placeholder: 'Saisissez une adresse ou positionner la carte' }
|
||||
|
||||
.carte.edit{ data: { geo: geo_data(champ) }, class: "carte-#{form.index}" }
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
= form.select :value,
|
||||
Champs::DepartementChamp.departements,
|
||||
include_blank: true,
|
||||
required: champ.mandatory?
|
||||
= form.select :value, [champ.value].compact,
|
||||
{ include_blank: true },
|
||||
required: champ.mandatory?,
|
||||
class: 'select2 departements'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
= form.select :value,
|
||||
Champs::PaysChamp.pays,
|
||||
disabled: Champs::PaysChamp.disabled_options,
|
||||
include_blank: true,
|
||||
required: champ.mandatory?
|
||||
{ disabled: Champs::PaysChamp.disabled_options, include_blank: true },
|
||||
required: champ.mandatory?,
|
||||
class: 'select2 pays'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
= form.select :value,
|
||||
Champs::RegionChamp.regions,
|
||||
include_blank: true,
|
||||
required: champ.mandatory?
|
||||
= form.select :value, [champ.value].compact,
|
||||
{ include_blank: true },
|
||||
required: champ.mandatory?,
|
||||
class: 'select2 regions'
|
||||
|
|
|
@ -105,3 +105,7 @@ LOGRAGE_ENABLED="disabled"
|
|||
# Service externe d'horodatage des changements de statut des dossiers (effectué quotidiennement)
|
||||
UNIVERSIGN_API_URL=""
|
||||
UNIVERSIGN_USERPWD=""
|
||||
|
||||
# API Geo / Adresse
|
||||
API_ADRESSE_URL="https://api-adresse.data.gouv.fr"
|
||||
API_GEO_URL="https://geo.api.gouv.fr"
|
||||
|
|
|
@ -5,6 +5,7 @@ Rails.application.config.assets.version = '1.0'
|
|||
|
||||
# Add additional assets to the asset load path
|
||||
Rails.application.config.assets.paths << Rails.root.join('node_modules', 'trix', 'dist')
|
||||
Rails.application.config.assets.paths << Rails.root.join('node_modules', 'select2', 'dist', 'css')
|
||||
|
||||
# Precompile additional assets.
|
||||
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
|
||||
|
|
|
@ -13,7 +13,7 @@ Rails.application.config.content_security_policy do |policy|
|
|||
# c'est trop compliqué pour être rectifié immédiatement (et sans valeur ajoutée:
|
||||
# c'est hardcodé dans les vues, donc pas injectable).
|
||||
policy.style_src :self, "*.crisp.chat", "crisp.chat", :unsafe_inline
|
||||
policy.connect_src :self, "wss://*.crisp.chat", "*.crisp.chat", "*.demarches-simplifiees.fr", "in-automate.sendinblue.com", "app.franceconnect.gouv.fr", "sentry.io"
|
||||
policy.connect_src :self, "wss://*.crisp.chat", "*.crisp.chat", "*.demarches-simplifiees.fr", "in-automate.sendinblue.com", "app.franceconnect.gouv.fr", "sentry.io", "geo.api.gouv.fr", "api-adresse.data.gouv.fr"
|
||||
# Pour tout le reste, par défaut on accepte uniquement ce qui vient de chez nous
|
||||
# et dans la notification on inclue la source de l'erreur
|
||||
policy.default_src :self, :data, :report_sample, "fonts.gstatic.com", "in-automate.sendinblue.com", "player.vimeo.com", "app.franceconnect.gouv.fr", "sentry.io", "static.demarches-simplifiees.fr", "*.crisp.chat", "crisp.chat", "*.crisp.help", "*.sibautomation.com", "sibautomation.com", "data"
|
||||
|
|
|
@ -68,6 +68,9 @@ defaults: &defaults
|
|||
client_key: <%= ENV['CRISP_CLIENT_KEY'] %>
|
||||
universign:
|
||||
userpwd: <%= ENV['UNIVERSIGN_USERPWD'] %>
|
||||
autocomplete:
|
||||
api_geo_url: <%= ENV['API_GEO_URL'] %>
|
||||
api_adresse_url: <%= ENV['API_ADRESSE_URL'] %>
|
||||
|
||||
|
||||
|
||||
|
@ -94,6 +97,8 @@ test:
|
|||
logout_endpoint: https://bidon.com/endpoint
|
||||
universign:
|
||||
userpwd: 'fake:fake'
|
||||
autocomplete:
|
||||
api_geo_url: /test/api_geo
|
||||
|
||||
# Do not keep production secrets in the repository,
|
||||
# instead read values from the environment.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue