mirror of
https://github.com/umap-project/umap.git
synced 2025-05-05 14:01:50 +02:00
Compare commits
18 commits
4031dfbf4f
...
2e52ce8ba0
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2e52ce8ba0 | ||
![]() |
be83eddbd0 | ||
![]() |
4df201107e | ||
![]() |
60f16cbc76 | ||
![]() |
2fa88c36f8 | ||
![]() |
47c5c0a2f0 | ||
![]() |
e548ec60f1 | ||
![]() |
190acbfaf0 | ||
![]() |
1370b1a0e8 | ||
![]() |
aa75b323c8 | ||
![]() |
1c00545095 | ||
![]() |
54a3aae912 | ||
![]() |
9d4069d9ae | ||
![]() |
167bab70c5 | ||
![]() |
d3ed46356d | ||
![]() |
103cedf0bf | ||
![]() |
4cbb2e1491 | ||
![]() |
c53eae5878 |
21 changed files with 169 additions and 1817 deletions
|
@ -1,6 +1,7 @@
|
|||
!!! abstract "Ce que nous allons apprendre"
|
||||
|
||||
- Importer le contour d’une commune
|
||||
- Importer le cadastre [sur l'instance uMap pour les agents publics](https://umap.incubateur.anct.gouv.fr/fr/)
|
||||
- Importer les contours des départements ou des régions
|
||||
- Importer un point d’intérêt (bibliothèques, parkings, …) qui est enregistré sur OpenStreetMap
|
||||
|
||||
|
@ -15,12 +16,20 @@ Voilà les deux actions à effectuer une fois une carte préexistante, ou une no
|
|||
|
||||
uMap permet d’utiliser des données produites par de nombreux services et placées en open data sous différents formats. Nous verrons ultérieurement (niveau intermédiaire) où rechercher ces sources. D’ores et déjà, vous pouvez utiliser l’assistant d’importation pour récupérer en un clic des contours administratifs et des points d’intérêt.
|
||||
|
||||
### Ressources disponibles (20/09/2024)
|
||||
### Ressources disponibles (05/11/2024)
|
||||
|
||||
Au 20 septembre 2024, les imports suivants sont disponibles :
|
||||
Au 5 novembre 2024, les imports suivants sont disponibles :
|
||||
|
||||
- contour d’une commune
|
||||
- contours des départements et des régions
|
||||
- contour d’une commune : limites communales jointives, issues du Référentiel à Grande Échelle (RGE), mises à jour par l'IGN ;
|
||||
- cadastre, sur l'instance uMap pour les agents publics :
|
||||
- Parcelles
|
||||
- Bâtiments
|
||||
- Communes (attention ce périmètre est moins précis, privilégier celui issu du RGE ci-dessus)
|
||||
- Feuilles
|
||||
- Lieux-dits
|
||||
- Préfixes des sections
|
||||
- Subdivisions fiscales.
|
||||
- contours des départements et des régions ;
|
||||
- données issues d’OpenStreetMap placées dans [GeoDataMine](https://geodatamine.fr/). Comme son nom l’indique, GeoDataMine est une véritable mine de données très utiles pour les services publics :
|
||||
- Aire de jeux
|
||||
- Aménagements cyclables
|
||||
|
@ -43,7 +52,7 @@ Au 20 septembre 2024, les imports suivants sont disponibles :
|
|||
|
||||
Voici un bref passage en revu des différents imports proposés et pour finir l’import de la localisation des bibliothèques de Clermont- Ferrand :
|
||||
|
||||

|
||||

|
||||
|
||||
## 1. Importer le contour d’une commune
|
||||
|
||||
|
@ -58,30 +67,53 @@ Cliquez sur « Communes France » et sélectionnez la commune souhaitée dans
|
|||
Le code affiché n’est pas le code postal mais le code INSEE de la commune.
|
||||
|
||||
Voici le résultat avec la commune d’Arles (la plus vaste de France métropolitaine, un gain certain si on fait l’économie de dessiner son contour !)
|
||||

|
||||
|
||||

|
||||
|
||||
|
||||
Une fois cet import réalisé, tout est réglable : couleur de contour, de fond, affichage oui non d’une étiquette.
|
||||
|
||||
## 2. Importer les contours des départements ou des régions
|
||||
## 2. Importer le cadastre
|
||||
|
||||
Cliquez sur l’outil d’importation en bas de la barre de droite, puis descendez jusqu’au cadre « Assistants d’import ».
|
||||
|
||||
Cliquez sur « Cadastre », choisir l'objet du cadastre à importer, par défaut, les parcelles sont proposées. Sélectionner une commune, choisir le type de calque et cliquez sur "Importer".
|
||||
|
||||

|
||||
|
||||
Pour régler l'épaisseur du trait et l'opacité du fond, cliquer dans la barre de droite sur "Gérer les calques", puis sur le petit stylo ("Editer") et enfin dans les "propriétés de la forme" :
|
||||
|
||||

|
||||
|
||||
On obtient une couche d'information moins chargée, ce qui permet d'ajouter d'autres données :
|
||||
|
||||

|
||||
|
||||
Sur cet exemple, l'identifiant s'affiche au survol d'une parcelle avec la souris. Pour obtenir cet affichage, cliquer sur les "Propriétés avancées" du calque, juste en dessous des "Propriétés de la forme", puis dans "Clé pour le libellé", indiquer id. C'est en effet le nom donné dans le tableau de données à la colonne qui accueille l'identifiant des parcelles.
|
||||
|
||||
!!! note
|
||||
Il est tout à fait possible d'utiliser le cadastre comme fond de carte. Dans ce cas, la méthode est différente, voir la fiche tuto [Où trouver des données](https://discover.umap-project.org/fr/tutorials/4-find-data/)
|
||||
|
||||
## 3. Importer les contours des départements ou des régions
|
||||
|
||||
Cliquez sur l’outil d’importation en bas de la barre de droite, puis cliquez sur le lien « Assistants d’import ».
|
||||
|
||||
Cliquez sur « Contours nationaux » puis soit départements, soit régions et enfin le type de calque (voir supra l’explication). Tous les départements sont importés :
|
||||
|
||||

|
||||

|
||||
|
||||
## 3. Importer un point d’intérêt issu de GeoDataMine
|
||||
## 4. Importer un point d’intérêt issu de GeoDataMine
|
||||
|
||||
Cliquez sur l’outil d’importation en bas de la barre de droite, puis cliquez sur le lien « Assistants d’import ».
|
||||
|
||||
Cliquez sur « GeoDataMine (thèmes OSM) » et sélectionnez les informations souhaitées, routes, bâtiments, commerces, services publics, …
|
||||
Par exemple, en sélectionnant les points d’eau potable de la CA du Grand Avignon, puis « Copier dans un calque »
|
||||
Par exemple, en sélectionnant les points d’eau potable de la CA du Grand Avignon, puis « Copier dans un calque » ou « Associer comme données distantes » (dans ce dernier cas, la carte se mettra automatiquement à jour lorsque le jeu de données changera).
|
||||
|
||||

|
||||

|
||||
|
||||
Voici une réelle économie de temps plutôt que de placer pointeur après pointeur tous les points d’eau.
|
||||
|
||||
## 4. La carte combinée
|
||||
## 5. La carte combinée
|
||||
|
||||
Bien entendu, on peut tout à fait combiner les différentes couches d’information et présenter par exemple la carte des Points d’eau potable dans la CA du Grand Avignon, avec les contours des communes qui composent l’EPCI, du département et de la région :
|
||||
|
||||
|
@ -89,7 +121,7 @@ Bien entendu, on peut tout à fait combiner les différentes couches d’informa
|
|||
|
||||

|
||||
|
||||
[Voir la carte en plein écran](https://umap.openstreetmap.fr/fr/map/points-deau-potable-grand-avignon_1116739?scaleControl=false&miniMap=false&scrollWheelZoom=true&zoomControl=true&editMode=disabled&moreControl=true&searchControl=null&tilelayersControl=null&embedControl=null&datalayersControl=true&onLoadPanel=none&captionBar=false&captionMenus=true#11/43.9889/4.7962){ .md-button }
|
||||
[Voir la carte en plein écran](https://umap.incubateur.anct.gouv.fr/fr/map/points-deau-potable-grand-avignon_672)
|
||||
|
||||
Il faudra dans ce cas supprimer toutes les informations inutiles dans le tableau de données qui est accessible dans la barre de gauche pour chaque calque.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Force rtfd to use a recent version of mkdocs
|
||||
mkdocs==1.6.1
|
||||
pymdown-extensions==10.14.3
|
||||
mkdocs-material==9.6.7
|
||||
mkdocs-material==9.6.9
|
||||
mkdocs-static-i18n==1.3.0
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Force rtfd to use a recent version of mkdocs
|
||||
mkdocs==1.6.1
|
||||
pymdown-extensions==10.14.3
|
||||
mkdocs-material==9.6.7
|
||||
mkdocs-material==9.6.9
|
||||
mkdocs-static-i18n==1.3.0
|
||||
|
|
|
@ -33,7 +33,7 @@ dependencies = [
|
|||
"django-environ==0.12.0",
|
||||
"django-probes==1.7.0",
|
||||
"Pillow==11.1.0",
|
||||
"psycopg==3.2.5",
|
||||
"psycopg==3.2.6",
|
||||
"requests==2.32.3",
|
||||
"rcssmin==1.2.1",
|
||||
"rjsmin==1.2.4",
|
||||
|
@ -44,10 +44,10 @@ dependencies = [
|
|||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"hatch==1.14.0",
|
||||
"ruff==0.9.10",
|
||||
"ruff==0.11.2",
|
||||
"djlint==1.36.4",
|
||||
"mkdocs==1.6.1",
|
||||
"mkdocs-material==9.6.7",
|
||||
"mkdocs-material==9.6.9",
|
||||
"mkdocs-static-i18n==1.3.0",
|
||||
"vermin==1.6.0",
|
||||
"pymdown-extensions==10.14.3",
|
||||
|
|
|
@ -202,3 +202,15 @@ dt {
|
|||
height: 100vh;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.table-scrollable {
|
||||
background-image: linear-gradient(to right, var(--background-color), var(--background-color)),
|
||||
linear-gradient(to right, var(--background-color), var(--background-color)),
|
||||
linear-gradient(to right, rgba(0, 0, 20, .50), rgba(255, 255, 255, 0)),
|
||||
linear-gradient(to left, rgba(0, 0, 20, .50), rgba(255, 255, 255, 0));
|
||||
background-position: left center, right center, left center, right center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 20px 100%, 20px 100%, 10px 100%, 10px 100%;
|
||||
background-attachment: local, local, scroll, scroll;
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
z-index: var(--zindex-dialog);
|
||||
margin: auto;
|
||||
margin-top: 100px;
|
||||
width: 40vw;
|
||||
width: var(--dialog-width);
|
||||
max-width: 100vw;
|
||||
max-height: 50vh;
|
||||
padding: 20px;
|
||||
|
|
|
@ -55,3 +55,10 @@
|
|||
.importers ul .datasets:before {
|
||||
background-image: url(../img/importers/datasets.svg);
|
||||
}
|
||||
.importer.banfr h3:before,
|
||||
.importers ul .banfr:before {
|
||||
background-image: url(../img/importers/banfr.svg);
|
||||
}
|
||||
.importer table {
|
||||
width: calc(var(--dialog-width) - 2 * var(--box-margin));
|
||||
}
|
||||
|
|
1
umap/static/umap/img/importers/banfr.svg
Normal file
1
umap/static/umap/img/importers/banfr.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" fill="none"><path fill="#bebebe" d="M40 0H10C4.477 0 0 4.477 0 10v30c0 5.523 4.477 10 10 10h30c5.523 0 10-4.477 10-10V10c0-5.523-4.477-10-10-10z" style="stroke-width:1"/><path fill="#bfbfbf" fill-opacity=".9" fill-rule="evenodd" d="M29.023 20.012v6.053a1.226 1.226 0 0 0 2.451 0v-6.053a1.226 1.226 0 0 0-2.451 0z" clip-rule="evenodd" style="fill:#323737;fill-opacity:1;stroke-width:1"/><path fill="#E1000F" fill-opacity=".9" fill-rule="evenodd" d="m24.393 18.047 5.242 3.027a1.226 1.226 0 0 0 1.225-2.123l-5.241-3.027a1.226 1.226 0 0 0-1.226 2.123z" clip-rule="evenodd" style="fill:#323737;fill-opacity:1;stroke-width:1"/><path fill="#000091" fill-opacity=".9" fill-rule="evenodd" d="m29.635 25.004-5.242 3.026a1.226 1.226 0 0 0 1.226 2.123l5.241-3.027a1.226 1.226 0 0 0-1.225-2.122z" clip-rule="evenodd" style="fill:#323737;fill-opacity:1;stroke-width:1"/><path fill="#bfbfbf" fill-opacity=".9" fill-rule="evenodd" d="M20.99 26.065v-6.053a1.226 1.226 0 0 0-2.451 0v6.053a1.226 1.226 0 0 0 2.451 0z" clip-rule="evenodd" style="fill:#323737;fill-opacity:1;stroke-width:1"/><path fill="#000091" fill-opacity=".9" fill-rule="evenodd" d="m20.377 21.074 5.242-3.027a1.226 1.226 0 0 0-1.226-2.123l-5.241 3.027a1.226 1.226 0 0 0 1.225 2.123z" clip-rule="evenodd" style="fill:#323737;fill-opacity:1;stroke-width:1"/><path fill="#E1000F" fill-opacity=".9" fill-rule="evenodd" d="m14.934 27.326 4.84-.035a1.226 1.226 0 0 0-.018-2.452l-4.84.035a1.226 1.226 0 0 0 .018 2.452z" clip-rule="evenodd" style="fill:#323737;fill-opacity:1;stroke-width:1"/><path fill="#bfbfbf" fill-opacity=".9" fill-rule="evenodd" d="M18.62 14.22A9.977 9.977 0 0 1 25 11.924c2.424 0 4.648.864 6.38 2.298a1.226 1.226 0 0 0 1.564-1.888A12.417 12.417 0 0 0 25 9.471a12.417 12.417 0 0 0-7.944 2.862 1.226 1.226 0 0 0 1.564 1.888z" clip-rule="evenodd" style="fill:#323737;fill-opacity:1;stroke-width:1"/><path fill="#000091" fill-opacity=".9" fill-rule="evenodd" d="M16.022 25.565c-.622-1.309-1.035-2.553-1.035-3.628a9.998 9.998 0 0 1 3.632-7.716 1.225 1.225 0 1 0-1.563-1.888 12.443 12.443 0 0 0-4.52 9.604c0 1.385.473 2.997 1.271 4.679a1.226 1.226 0 0 0 2.215-1.051z" clip-rule="evenodd" style="fill:#323737;fill-opacity:1;stroke-width:1"/><path fill="#E1000F" fill-opacity=".9" fill-rule="evenodd" d="M31.38 14.221a9.997 9.997 0 0 1 3.633 7.716c0 1.682-.967 3.75-2.248 5.846-3.235 5.298-8.629 10.652-8.629 10.652a1.224 1.224 0 1 0 1.728 1.737s5.62-5.586 8.993-11.11c1.551-2.541 2.607-5.087 2.607-7.125 0-3.861-1.759-7.318-4.52-9.604a1.226 1.226 0 0 0-1.564 1.888z" clip-rule="evenodd" style="fill:#323737;fill-opacity:1;stroke-width:1"/><path fill="#000091" fill-opacity=".9" fill-rule="evenodd" d="M25.864 38.435s-3.874-3.85-7.03-8.252a1.227 1.227 0 0 0-1.992 1.427c3.275 4.57 7.294 8.562 7.294 8.562.48.478 1.257.475 1.734-.006a1.224 1.224 0 0 0-.006-1.731z" clip-rule="evenodd" style="fill:#323737;fill-opacity:1;stroke-width:1"/></svg>
|
After Width: | Height: | Size: 2.9 KiB |
|
@ -94,6 +94,9 @@ export default class Importer extends Utils.WithTemplate {
|
|||
case 'datasets':
|
||||
import('./importers/datasets.js').then(register)
|
||||
break
|
||||
case 'banfr':
|
||||
import('./importers/banfr.js').then(register)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -173,7 +176,7 @@ export default class Importer extends Utils.WithTemplate {
|
|||
showImporters() {
|
||||
if (!this.IMPORTERS.length) return
|
||||
const [element, { grid }] = Utils.loadTemplateWithRefs(GRID_TEMPLATE)
|
||||
for (const plugin of this.IMPORTERS.sort((a, b) => (a.id > b.id ? 1 : -1))) {
|
||||
for (const plugin of this.IMPORTERS.sort((a, b) => (a.name > b.name ? 1 : -1))) {
|
||||
const button = Utils.loadTemplate(
|
||||
`<li><button type="button" class="${plugin.id}">${plugin.name}</button></li>`
|
||||
)
|
||||
|
|
93
umap/static/umap/js/modules/importers/banfr.js
Normal file
93
umap/static/umap/js/modules/importers/banfr.js
Normal file
|
@ -0,0 +1,93 @@
|
|||
import { DomUtil } from '../../../vendors/leaflet/leaflet-src.esm.js'
|
||||
import { BaseAjax, SingleMixin } from '../autocomplete.js'
|
||||
import * as Utils from '../utils.js'
|
||||
import { AutocompleteCommunes } from './communesfr.js'
|
||||
import { translate } from '../i18n.js'
|
||||
import { uMapAlert as Alert } from '../../components/alerts/alert.js'
|
||||
|
||||
const TEMPLATE = `
|
||||
<div>
|
||||
<h3>Géocodage d’adresses en France</h3>
|
||||
<p>Géocoder un fichier CSV avec la base adresse nationale.</p>
|
||||
<fieldset class="formbox">
|
||||
<legend>Choisir un fichier CSV (encodé en UTF-8)</legend>
|
||||
<input type=file name=file data-ref=csvFile accept=".csv" />
|
||||
</fieldset>
|
||||
<fieldset class="formbox">
|
||||
<legend>Aperçu des données</legend>
|
||||
<table class="table-scrollable" data-ref=table></table>
|
||||
</fieldset>
|
||||
<fieldset class="formbox">
|
||||
<legend>Sélectionner les colonnes à utiliser</legend>
|
||||
<span data-ref="columns"></span>
|
||||
</fieldset>
|
||||
</div>
|
||||
`
|
||||
|
||||
export class Importer {
|
||||
constructor(umap, options) {
|
||||
this._umap = umap
|
||||
this.name = options.name || 'Géocodage FR'
|
||||
this.id = 'banfr'
|
||||
}
|
||||
|
||||
async open(importer) {
|
||||
let data
|
||||
const [container, { table, columns, csvFile }] =
|
||||
Utils.loadTemplateWithRefs(TEMPLATE)
|
||||
csvFile.addEventListener('change', () => {
|
||||
const reader = new FileReader()
|
||||
reader.onload = (evt) => {
|
||||
data = evt.target.result
|
||||
const rows = csv2geojson.auto(data).slice(0, 5)
|
||||
const cols = Object.keys(rows[0])
|
||||
table.innerHTML = ''
|
||||
columns.innerHTML = ''
|
||||
const tr = document.createElement('tr')
|
||||
for (const column of cols) {
|
||||
tr.appendChild(Utils.loadTemplate(`<th>${column}</th>`))
|
||||
columns.appendChild(
|
||||
Utils.loadTemplate(
|
||||
`<label><input type="checkbox" value="${column}" /> ${column}</label>`
|
||||
)
|
||||
)
|
||||
}
|
||||
table.appendChild(tr)
|
||||
for (const row of rows) {
|
||||
const tr = document.createElement('tr')
|
||||
for (const column of cols) {
|
||||
tr.appendChild(Utils.loadTemplate(`<td>${row[column]}</td>`))
|
||||
}
|
||||
table.appendChild(tr)
|
||||
}
|
||||
}
|
||||
reader.readAsText(csvFile.files[0])
|
||||
})
|
||||
|
||||
const confirm = async (form) => {
|
||||
const formData = new FormData()
|
||||
formData.append('data', csvFile.files[0])
|
||||
for (const option of columns.querySelectorAll('input:checked')) {
|
||||
formData.append('columns', option.value)
|
||||
}
|
||||
const response = await this._umap.request.post(
|
||||
'https://api-adresse.data.gouv.fr/search/csv/',
|
||||
{},
|
||||
formData
|
||||
)
|
||||
if (response?.ok) {
|
||||
importer.raw = await response.text()
|
||||
importer.format = 'csv'
|
||||
}
|
||||
}
|
||||
|
||||
importer.dialog
|
||||
.open({
|
||||
template: container,
|
||||
className: `${this.id} importer dark`,
|
||||
cancel: false,
|
||||
accept: translate('Geocode'),
|
||||
})
|
||||
.then(confirm)
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
"globals": {
|
||||
"describe": true,
|
||||
"happen": true,
|
||||
"assert": true,
|
||||
"before": true,
|
||||
"after": true,
|
||||
"it": true,
|
||||
"sinon": true,
|
||||
"enableEdit": true,
|
||||
"disableEdit": true,
|
||||
"changeInputValue": true,
|
||||
"resetMap": true,
|
||||
"initMap": true,
|
||||
"clickCancel": true,
|
||||
"map": true,
|
||||
"qs": true,
|
||||
"qsa": true,
|
||||
"qst": true
|
||||
}
|
||||
}
|
|
@ -1,463 +0,0 @@
|
|||
describe('U.DataLayer', () => {
|
||||
let path = '/map/99/datalayer/update/62/',
|
||||
map,
|
||||
datalayer
|
||||
|
||||
before(async () => {
|
||||
fetchMock.mock(/\/datalayer\/62\/\?.*/, JSON.stringify(RESPONSES.datalayer62_GET))
|
||||
fetchMock.sticky('/map/99/update/settings/', { id: 99 })
|
||||
this.options = {
|
||||
umap_id: 99,
|
||||
}
|
||||
MAP = map = initMap({ umap_id: 99 })
|
||||
const datalayer_options = defaultDatalayerData()
|
||||
await map.initDataLayers([datalayer_options])
|
||||
datalayer = map.getDataLayerByUmapId(62)
|
||||
enableEdit()
|
||||
})
|
||||
after(() => {
|
||||
fetchMock.restore()
|
||||
resetMap()
|
||||
})
|
||||
|
||||
describe('#init()', () => {
|
||||
it('should be added in datalayers index', () => {
|
||||
assert.notEqual(map.datalayers_index.indexOf(datalayer), -1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#edit()', () => {
|
||||
var editButton, form, input, forceButton
|
||||
|
||||
it('row in control should be active', () => {
|
||||
assert.notOk(
|
||||
qs('.leaflet-control-browse #browse_data_toggle_' + L.stamp(datalayer) + '.off')
|
||||
)
|
||||
})
|
||||
|
||||
it('should have edit button', () => {
|
||||
editButton = qs('#browse_data_toggle_' + L.stamp(datalayer) + ' .layer-edit')
|
||||
assert.ok(editButton)
|
||||
})
|
||||
|
||||
it('should have toggle visibility element', () => {
|
||||
assert.ok(qs('.leaflet-control-browse i.layer-toggle'))
|
||||
})
|
||||
|
||||
it('should exist only one datalayer', () => {
|
||||
assert.equal(qsa('.leaflet-control-browse i.layer-toggle').length, 1)
|
||||
})
|
||||
|
||||
it('should build a form on edit button click', () => {
|
||||
happen.click(editButton)
|
||||
form = qs('form.umap-form')
|
||||
input = qs('form.umap-form input[name="name"]')
|
||||
assert.ok(form)
|
||||
assert.ok(input)
|
||||
})
|
||||
|
||||
it('should update name on input change', () => {
|
||||
var new_name = 'This is a new name'
|
||||
input.value = new_name
|
||||
happen.once(input, { type: 'input' })
|
||||
assert.equal(datalayer.options.name, new_name)
|
||||
})
|
||||
|
||||
it('should have made datalayer dirty', () => {
|
||||
assert.ok(datalayer.isDirty)
|
||||
assert.notEqual(map.dirty_datalayers.indexOf(datalayer), -1)
|
||||
})
|
||||
|
||||
it('should have made Map dirty', () => {
|
||||
assert.ok(map.isDirty)
|
||||
})
|
||||
|
||||
it('should call datalayer.save on save button click', (done) => {
|
||||
const postDatalayer = fetchMock.post(path, () => {
|
||||
return defaultDatalayerData()
|
||||
})
|
||||
clickSave()
|
||||
window.setTimeout(() => {
|
||||
assert(fetchMock.called(path))
|
||||
done()
|
||||
}, 500)
|
||||
})
|
||||
|
||||
it('should show alert if server respond 412', (done) => {
|
||||
cleanAlert()
|
||||
fetchMock.restore()
|
||||
fetchMock.post(path, 412)
|
||||
happen.click(editButton)
|
||||
input = qs('form.umap-form input[name="name"]')
|
||||
input.value = 'a new name'
|
||||
happen.once(input, { type: 'input' })
|
||||
clickSave()
|
||||
window.setTimeout(() => {
|
||||
assert(L.DomUtil.hasClass(map._container, 'umap-alert'))
|
||||
assert.notEqual(map.dirty_datalayers.indexOf(datalayer), -1)
|
||||
const forceButton = qs('#umap-alert-container .umap-action')
|
||||
assert.ok(forceButton)
|
||||
done()
|
||||
}, 500)
|
||||
})
|
||||
|
||||
it('should save anyway on force save button click', (done) => {
|
||||
const forceButton = qs('#umap-alert-container .umap-action')
|
||||
fetchMock.restore()
|
||||
fetchMock.post(path, defaultDatalayerData)
|
||||
happen.click(forceButton)
|
||||
window.setTimeout(() => {
|
||||
assert.notOk(qs('#umap-alert-container .umap-action'))
|
||||
assert(fetchMock.called(path))
|
||||
assert.equal(map.dirty_datalayers.indexOf(datalayer), -1)
|
||||
done()
|
||||
}, 500)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#save() new', () => {
|
||||
let newLayerButton, form, input, newDatalayer, editButton, manageButton
|
||||
|
||||
it('should have a manage datalayers action', () => {
|
||||
enableEdit()
|
||||
manageButton = qs('.manage-datalayers')
|
||||
assert.ok(manageButton)
|
||||
happen.click(manageButton)
|
||||
})
|
||||
|
||||
it('should have a new layer button', () => {
|
||||
newLayerButton = qs('.panel.right.on .add-datalayer')
|
||||
assert.ok(newLayerButton)
|
||||
})
|
||||
|
||||
it('should build a form on new layer button click', () => {
|
||||
happen.click(newLayerButton)
|
||||
form = qs('form.umap-form')
|
||||
input = qs('form.umap-form input[name="name"]')
|
||||
assert.ok(form)
|
||||
assert.ok(input)
|
||||
})
|
||||
|
||||
it('should have an empty name', () => {
|
||||
assert.notOk(input.value)
|
||||
})
|
||||
|
||||
it('should have created a new datalayer', () => {
|
||||
assert.equal(map.datalayers_index.length, 2)
|
||||
newDatalayer = map.datalayers_index[1]
|
||||
})
|
||||
|
||||
it('should have made Map dirty', () => {
|
||||
assert.ok(map.isDirty)
|
||||
})
|
||||
|
||||
it('should update name on input change', () => {
|
||||
var new_name = 'This is a new name'
|
||||
input.value = new_name
|
||||
happen.once(input, { type: 'input' })
|
||||
assert.equal(newDatalayer.options.name, new_name)
|
||||
})
|
||||
|
||||
it('should set umap_id on save callback', async () => {
|
||||
assert.notOk(newDatalayer.umap_id)
|
||||
fetchMock.post('/map/99/datalayer/create/', defaultDatalayerData({ id: 63 }))
|
||||
clickSave()
|
||||
return new Promise((resolve) => {
|
||||
window.setTimeout(() => {
|
||||
assert.equal(newDatalayer.umap_id, 63)
|
||||
resolve()
|
||||
}, 1000)
|
||||
})
|
||||
})
|
||||
|
||||
it('should have unset map dirty', () => {
|
||||
assert.notOk(map.isDirty)
|
||||
})
|
||||
|
||||
it('should have edit button', () => {
|
||||
editButton = qs('#browse_data_toggle_' + L.stamp(newDatalayer) + ' .layer-edit')
|
||||
assert.ok(editButton)
|
||||
})
|
||||
|
||||
it('should call update if we edit again', async () => {
|
||||
happen.click(editButton)
|
||||
assert.notOk(map.isDirty)
|
||||
input = qs('form.umap-form input[name="name"]')
|
||||
input.value = "a new name again but we don't care which"
|
||||
happen.once(input, { type: 'input' })
|
||||
assert.ok(map.isDirty)
|
||||
var response = () => {
|
||||
return defaultDatalayerData({ pk: 63 })
|
||||
}
|
||||
var spy = sinon.spy(response)
|
||||
fetchMock.post('/map/99/datalayer/update/63/', spy)
|
||||
return new Promise((resolve) => {
|
||||
clickSave()
|
||||
window.setTimeout(() => {
|
||||
assert.ok(spy.calledOnce)
|
||||
resolve()
|
||||
}, 1000)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('#iconClassChange()', () => {
|
||||
it('should change icon class', () => {
|
||||
happen.click(qs('[data-id="' + datalayer._leaflet_id + '"] .layer-edit'))
|
||||
changeSelectValue(
|
||||
qs('form#datalayer-advanced-properties select[name=iconClass]'),
|
||||
'Circle'
|
||||
)
|
||||
assert.notOk(qs('div.umap-div-icon'))
|
||||
assert.ok(qs('div.umap-circle-icon'))
|
||||
happen.click(
|
||||
qs('form#datalayer-advanced-properties .umap-field-iconClass .undefine')
|
||||
)
|
||||
assert.notOk(qs('div.umap-circle-icon'))
|
||||
assert.ok(qs('div.umap-div-icon'))
|
||||
clickCancel()
|
||||
})
|
||||
})
|
||||
|
||||
describe('#show/hide', () => {
|
||||
it('should hide features on hide', () => {
|
||||
assert.ok(qs('div.umap-div-icon'))
|
||||
assert.ok(qs('path[fill="none"]'))
|
||||
datalayer.hide()
|
||||
assert.notOk(qs('div.umap-div-icon'))
|
||||
assert.notOk(qs('path[fill="none"]'))
|
||||
})
|
||||
|
||||
it('should show features on show', () => {
|
||||
assert.notOk(qs('div.umap-div-icon'))
|
||||
assert.notOk(qs('path[fill="none"]'))
|
||||
datalayer.show()
|
||||
assert.ok(qs('div.umap-div-icon'))
|
||||
assert.ok(qs('path[fill="none"]'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('#clone()', () => {
|
||||
it('should clone everything but the id and the name', () => {
|
||||
enableEdit()
|
||||
var clone = datalayer.clone()
|
||||
assert.notOk(clone.umap_id)
|
||||
assert.notEqual(clone.options.name, datalayer.name)
|
||||
assert.ok(clone.options.name)
|
||||
assert.equal(clone.options.color, datalayer.options.color)
|
||||
assert.equal(clone.options.stroke, datalayer.options.stroke)
|
||||
clone._delete()
|
||||
clickSave()
|
||||
})
|
||||
})
|
||||
|
||||
describe('#restore()', () => {
|
||||
var oldConfirm,
|
||||
newConfirm = () => {
|
||||
return true
|
||||
}
|
||||
|
||||
before(() => {
|
||||
oldConfirm = window.confirm
|
||||
window.confirm = newConfirm
|
||||
})
|
||||
after(() => {
|
||||
window.confirm = oldConfirm
|
||||
})
|
||||
|
||||
it('should restore everything', (done) => {
|
||||
enableEdit()
|
||||
var geojson = L.Util.CopyJSON(RESPONSES.datalayer62_GET)
|
||||
geojson.features.push({
|
||||
geometry: {
|
||||
type: 'Point',
|
||||
coordinates: [-1.274658203125, 50.57634993749885],
|
||||
},
|
||||
type: 'Feature',
|
||||
id: 1807,
|
||||
properties: { _umap_options: {}, name: 'new point from restore' },
|
||||
})
|
||||
geojson._umap_options.color = 'Chocolate'
|
||||
fetchMock.get('/datalayer/62/olderversion.geojson', geojson)
|
||||
sinon.spy(window, 'confirm')
|
||||
datalayer.restore('olderversion.geojson')
|
||||
window.setTimeout(() => {
|
||||
assert(window.confirm.calledOnce)
|
||||
window.confirm.restore()
|
||||
assert.equal(datalayer.umap_id, 62)
|
||||
assert.ok(datalayer.isDirty)
|
||||
assert.equal(datalayer._index.length, 4)
|
||||
assert.ok(qs('path[fill="Chocolate"]'))
|
||||
done()
|
||||
}, 1000)
|
||||
})
|
||||
|
||||
it('should revert anything on cancel click', () => {
|
||||
clickCancel()
|
||||
assert.equal(datalayer._index.length, 3)
|
||||
assert.notOk(qs('path[fill="Chocolate"]'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('#smart-options()', () => {
|
||||
let poly, marker
|
||||
before(() => {
|
||||
datalayer.eachLayer(function (layer) {
|
||||
if (!poly && layer instanceof L.Polygon) {
|
||||
poly = layer
|
||||
}
|
||||
if (!marker && layer instanceof L.Marker) {
|
||||
marker = layer
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('should parse color variable', () => {
|
||||
let icon = qs('div.umap-div-icon .icon_container')
|
||||
poly.properties.mycolor = 'DarkGoldenRod'
|
||||
marker.properties.mycolor = 'DarkRed'
|
||||
marker.properties._umap_options.color = undefined
|
||||
assert.notOk(qs('path[fill="DarkGoldenRod"]'))
|
||||
assert.equal(icon.style.backgroundColor, 'olivedrab')
|
||||
datalayer.options.color = '{mycolor}'
|
||||
datalayer.options.fillColor = '{mycolor}'
|
||||
datalayer.indexProperties(poly)
|
||||
datalayer.indexProperties(marker)
|
||||
datalayer.redraw()
|
||||
icon = qs('div.umap-div-icon .icon_container')
|
||||
assert.equal(icon.style.backgroundColor, 'darkred')
|
||||
assert.ok(qs('path[fill="DarkGoldenRod"]'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('#facet-search()', () => {
|
||||
before(async () => {
|
||||
fetchMock.get(/\/datalayer\/63\/\?.*/, RESPONSES.datalayer63_GET)
|
||||
map.options.facetKey = 'name'
|
||||
await map.initDataLayers([RESPONSES.datalayer63_GET._umap_options])
|
||||
})
|
||||
it('should not impact non browsable layer', () => {
|
||||
assert.ok(qs('path[fill="SteelBlue"]'))
|
||||
})
|
||||
it('should allow advanced filter', () => {
|
||||
map.openFacet()
|
||||
assert.ok(qs('div.umap-facet-search'))
|
||||
// This one if from the normal datalayer
|
||||
// it's name is "test", so it should be hidden
|
||||
// by the filter
|
||||
assert.ok(qs('path[fill="none"]'))
|
||||
happen.click(qs('input[data-value="name poly"]'))
|
||||
assert.notOk(qs('path[fill="none"]'))
|
||||
// This one comes from a non browsable layer
|
||||
// so it should not be affected by the filter
|
||||
assert.ok(qs('path[fill="SteelBlue"]'))
|
||||
happen.click(qs('input[data-value="name poly"]')) // Undo
|
||||
})
|
||||
it('should allow to control facet label', () => {
|
||||
map.options.facetKey = 'name|Nom'
|
||||
map.openFacet()
|
||||
assert.ok(qs('div.umap-facet-search h5'))
|
||||
assert.equal(qs('div.umap-facet-search h5').textContent, 'Nom')
|
||||
})
|
||||
})
|
||||
describe('#zoomEnd', () => {
|
||||
it('should honour the fromZoom option', () => {
|
||||
map.setZoom(6, { animate: false })
|
||||
assert.ok(qs('path[fill="none"]'))
|
||||
datalayer.options.fromZoom = 6
|
||||
map.setZoom(5, { animate: false })
|
||||
assert.notOk(qs('path[fill="none"]'))
|
||||
map.setZoom(6, { animate: false })
|
||||
assert.ok(qs('path[fill="none"]'))
|
||||
})
|
||||
|
||||
it('should honour the toZoom option', () => {
|
||||
map.setZoom(6, { animate: false })
|
||||
assert.ok(qs('path[fill="none"]'))
|
||||
datalayer.options.toZoom = 6
|
||||
map.setZoom(7, { animate: false })
|
||||
assert.notOk(qs('path[fill="none"]'))
|
||||
map.setZoom(6, { animate: false })
|
||||
assert.ok(qs('path[fill="none"]'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('#displayOnLoad', () => {
|
||||
before(() => {
|
||||
fetchMock.get(/\/datalayer\/64\/\?.*/, RESPONSES.datalayer64_GET)
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
await map.initDataLayers([RESPONSES.datalayer64_GET._umap_options])
|
||||
datalayer = map.getDataLayerByUmapId(64)
|
||||
map.setZoom(10, { animate: false })
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
datalayer._delete()
|
||||
})
|
||||
|
||||
it('should not display layer at load', () => {
|
||||
assert.notOk(qs('path[fill="AliceBlue"]'))
|
||||
})
|
||||
|
||||
it('should display on click', (done) => {
|
||||
happen.click(qs(`[data-id='${L.stamp(datalayer)}'] .layer-toggle`))
|
||||
window.setTimeout(() => {
|
||||
assert.ok(qs('path[fill="AliceBlue"]'))
|
||||
done()
|
||||
}, 500)
|
||||
})
|
||||
|
||||
it('should not display on zoom', (done) => {
|
||||
map.setZoom(9, { animate: false })
|
||||
window.setTimeout(() => {
|
||||
assert.notOk(qs('path[fill="AliceBlue"]'))
|
||||
done()
|
||||
}, 500)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#delete()', () => {
|
||||
let deleteLink,
|
||||
deletePath = '/map/99/datalayer/delete/62/'
|
||||
before(() => {
|
||||
datalayer = map.getDataLayerByUmapId(62)
|
||||
})
|
||||
|
||||
it('should have a delete link in update form', () => {
|
||||
enableEdit()
|
||||
happen.click(qs('#browse_data_toggle_' + L.stamp(datalayer) + ' .layer-edit'))
|
||||
deleteLink = qs('button.delete_datalayer_button')
|
||||
assert.ok(deleteLink)
|
||||
})
|
||||
|
||||
it('should delete features on datalayer delete', () => {
|
||||
happen.click(deleteLink)
|
||||
assert.notOk(qs('div.icon_container'))
|
||||
})
|
||||
|
||||
it('should have set map dirty', () => {
|
||||
assert.ok(map.isDirty)
|
||||
})
|
||||
|
||||
it('should delete layer control row on delete', () => {
|
||||
assert.notOk(
|
||||
qs('.leaflet-control-browse #browse_data_toggle_' + L.stamp(datalayer))
|
||||
)
|
||||
})
|
||||
|
||||
it('should be removed from map.datalayers_index', () => {
|
||||
assert.equal(map.datalayers_index.indexOf(datalayer), -1)
|
||||
})
|
||||
|
||||
it('should be removed from map.datalayers', () => {
|
||||
assert.notOk(map.datalayers[L.stamp(datalayer)])
|
||||
})
|
||||
|
||||
it('should be visible again on edit cancel', () => {
|
||||
clickCancel()
|
||||
assert.ok(qs('div.icon_container'))
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,131 +0,0 @@
|
|||
describe('U.FeatureMixin', function () {
|
||||
let map, datalayer
|
||||
before(async () => {
|
||||
await fetchMock.mock(
|
||||
/\/datalayer\/62\/\?.*/,
|
||||
JSON.stringify(RESPONSES.datalayer62_GET)
|
||||
)
|
||||
this.options = {
|
||||
umap_id: 99,
|
||||
}
|
||||
MAP = map = initMap({ umap_id: 99 })
|
||||
const datalayer_options = defaultDatalayerData()
|
||||
await map.initDataLayers([datalayer_options])
|
||||
datalayer = map.getDataLayerByUmapId(62)
|
||||
})
|
||||
after(function () {
|
||||
fetchMock.restore()
|
||||
resetMap()
|
||||
})
|
||||
|
||||
describe('#utils()', function () {
|
||||
var poly, marker
|
||||
function setFeatures(datalayer) {
|
||||
datalayer.eachLayer(function (layer) {
|
||||
if (!poly && layer instanceof L.Polygon) {
|
||||
poly = layer
|
||||
}
|
||||
if (!marker && layer instanceof L.Marker) {
|
||||
marker = layer
|
||||
}
|
||||
})
|
||||
}
|
||||
it('should generate a valid geojson', function () {
|
||||
setFeatures(datalayer)
|
||||
assert.ok(poly)
|
||||
assert.deepEqual(poly.toGeoJSON().geometry, {
|
||||
type: 'Polygon',
|
||||
coordinates: [
|
||||
[
|
||||
[11.25, 53.585984],
|
||||
[10.151367, 52.975108],
|
||||
[12.689209, 52.167194],
|
||||
[14.084473, 53.199452],
|
||||
[12.634277, 53.618579],
|
||||
[11.25, 53.585984],
|
||||
[11.25, 53.585984],
|
||||
],
|
||||
],
|
||||
})
|
||||
// Ensure original latlngs has not been modified
|
||||
assert.equal(poly.getLatLngs()[0].length, 6)
|
||||
})
|
||||
|
||||
it('should remove empty _umap_options from exported geojson', function () {
|
||||
setFeatures(datalayer)
|
||||
assert.ok(poly)
|
||||
assert.deepEqual(poly.toGeoJSON().properties, { name: 'name poly' })
|
||||
assert.ok(marker)
|
||||
assert.deepEqual(marker.toGeoJSON().properties, {
|
||||
_umap_options: { color: 'OliveDrab' },
|
||||
name: 'test',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('#properties()', function () {
|
||||
it('should rename property', function () {
|
||||
var poly = datalayer._lineToLayer({}, [
|
||||
[0, 0],
|
||||
[0, 1],
|
||||
[0, 2],
|
||||
])
|
||||
poly.properties.prop1 = 'xxx'
|
||||
poly.renameProperty('prop1', 'prop2')
|
||||
assert.equal(poly.properties.prop2, 'xxx')
|
||||
assert.ok(typeof poly.properties.prop1 === 'undefined')
|
||||
})
|
||||
|
||||
it('should not create property when renaming', function () {
|
||||
var poly = datalayer._lineToLayer({}, [
|
||||
[0, 0],
|
||||
[0, 1],
|
||||
[0, 2],
|
||||
])
|
||||
delete poly.properties.prop2 // Make sure it doesn't exist
|
||||
poly.renameProperty('prop1', 'prop2')
|
||||
assert.ok(typeof poly.properties.prop2 === 'undefined')
|
||||
})
|
||||
|
||||
it('should delete property', function () {
|
||||
var poly = datalayer._lineToLayer({}, [
|
||||
[0, 0],
|
||||
[0, 1],
|
||||
[0, 2],
|
||||
])
|
||||
poly.properties.prop = 'xxx'
|
||||
assert.equal(poly.properties.prop, 'xxx')
|
||||
poly.deleteProperty('prop')
|
||||
assert.ok(typeof poly.properties.prop === 'undefined')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#matchFilter()', function () {
|
||||
var poly
|
||||
|
||||
it('should filter on properties', function () {
|
||||
poly = datalayer._lineToLayer({}, [
|
||||
[0, 0],
|
||||
[0, 1],
|
||||
[0, 2],
|
||||
])
|
||||
poly.properties.name = 'mooring'
|
||||
assert.ok(poly.matchFilter('moo', ['name']))
|
||||
assert.notOk(poly.matchFilter('foo', ['name']))
|
||||
})
|
||||
|
||||
it('should be case unsensitive', function () {
|
||||
assert.ok(poly.matchFilter('Moo', ['name']))
|
||||
})
|
||||
|
||||
it('should match also in the middle of a string', function () {
|
||||
assert.ok(poly.matchFilter('oor', ['name']))
|
||||
})
|
||||
|
||||
it('should handle multiproperties', function () {
|
||||
poly.properties.city = 'Teulada'
|
||||
assert.ok(poly.matchFilter('eul', ['name', 'city', 'foo']))
|
||||
})
|
||||
})
|
||||
|
||||
})
|
|
@ -1,37 +0,0 @@
|
|||
describe('U.Map', () => {
|
||||
let map, datalayer
|
||||
before(async () => {
|
||||
await fetchMock.mock(
|
||||
/\/datalayer\/62\/\?.*/,
|
||||
JSON.stringify(RESPONSES.datalayer62_GET)
|
||||
)
|
||||
this.options = {
|
||||
umap_id: 99,
|
||||
}
|
||||
map = initMap({ umap_id: 99 })
|
||||
const datalayer_options = defaultDatalayerData()
|
||||
await map.initDataLayers([datalayer_options])
|
||||
datalayer = map.getDataLayerByUmapId(62)
|
||||
})
|
||||
after(() => {
|
||||
fetchMock.restore()
|
||||
clickCancel()
|
||||
resetMap()
|
||||
})
|
||||
|
||||
describe('#localizeUrl()', function () {
|
||||
it('should replace known variables', function () {
|
||||
assert.equal(
|
||||
map.localizeUrl('http://example.org/{zoom}'),
|
||||
'http://example.org/' + map.getZoom()
|
||||
)
|
||||
})
|
||||
|
||||
it('should keep unknown variables', function () {
|
||||
assert.equal(
|
||||
map.localizeUrl('http://example.org/{unkown}'),
|
||||
'http://example.org/{unkown}'
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,126 +0,0 @@
|
|||
describe('U.Marker', () => {
|
||||
let map, datalayer
|
||||
before(async () => {
|
||||
const datalayer_response = JSON.parse(JSON.stringify(RESPONSES.datalayer62_GET)) // Copy.
|
||||
datalayer_response._umap_options.iconClass = 'Drop'
|
||||
await fetchMock.mock(/\/datalayer\/62\/\?.*/, datalayer_response)
|
||||
this.options = {
|
||||
umap_id: 99,
|
||||
}
|
||||
MAP = map = initMap({ umap_id: 99 })
|
||||
const datalayer_options = defaultDatalayerData()
|
||||
await map.initDataLayers([datalayer_options])
|
||||
datalayer = map.getDataLayerByUmapId(62)
|
||||
})
|
||||
after(() => {
|
||||
fetchMock.restore()
|
||||
resetMap()
|
||||
})
|
||||
|
||||
describe('#iconClassChange()', () => {
|
||||
it('should change icon class', () => {
|
||||
enableEdit()
|
||||
happen.click(qs('div.umap-drop-icon'))
|
||||
happen.click(qs('ul.leaflet-inplace-toolbar a.umap-toggle-edit'))
|
||||
changeSelectValue(
|
||||
qs(
|
||||
'form#umap-feature-shape-properties .umap-field-iconClass select[name=iconClass]'
|
||||
),
|
||||
'Circle'
|
||||
)
|
||||
assert.notOk(qs('div.umap-drop-icon'))
|
||||
assert.ok(qs('div.umap-circle-icon'))
|
||||
happen.click(
|
||||
qs('form#umap-feature-shape-properties .umap-field-iconClass .undefine')
|
||||
)
|
||||
assert.notOk(qs('div.umap-circle-icon'))
|
||||
assert.ok(qs('div.umap-drop-icon'))
|
||||
clickCancel()
|
||||
})
|
||||
})
|
||||
|
||||
describe('#iconSymbolChange()', () => {
|
||||
it('should change icon symbol', () => {
|
||||
enableEdit()
|
||||
happen.click(qs('div.umap-drop-icon'))
|
||||
happen.click(qs('ul.leaflet-inplace-toolbar a.umap-toggle-edit'))
|
||||
changeInputValue(
|
||||
qs(
|
||||
'form#umap-feature-shape-properties .umap-field-iconUrl input[name=iconUrl]'
|
||||
),
|
||||
'1'
|
||||
)
|
||||
assert.equal(qs('div.umap-drop-icon span').textContent, '1')
|
||||
changeInputValue(
|
||||
qs(
|
||||
'form#umap-feature-shape-properties .umap-field-iconUrl input[name=iconUrl]'
|
||||
),
|
||||
'{name}'
|
||||
)
|
||||
assert.equal(qs('div.umap-drop-icon span').textContent, 'test')
|
||||
clickCancel()
|
||||
})
|
||||
})
|
||||
|
||||
describe('#iconClassChange()', () => {
|
||||
it('should change icon class', () => {
|
||||
enableEdit()
|
||||
happen.click(qs('div.umap-drop-icon'))
|
||||
happen.click(qs('ul.leaflet-inplace-toolbar a.umap-toggle-edit'))
|
||||
changeSelectValue(
|
||||
qs(
|
||||
'form#umap-feature-shape-properties .umap-field-iconClass select[name=iconClass]'
|
||||
),
|
||||
'Circle'
|
||||
)
|
||||
assert.notOk(qs('div.umap-drop-icon'))
|
||||
assert.ok(qs('div.umap-circle-icon'))
|
||||
happen.click(
|
||||
qs('form#umap-feature-shape-properties .umap-field-iconClass .undefine')
|
||||
)
|
||||
assert.notOk(qs('div.umap-circle-icon'))
|
||||
assert.ok(qs('div.umap-drop-icon'))
|
||||
clickCancel()
|
||||
})
|
||||
})
|
||||
|
||||
describe('#clone', () => {
|
||||
it('should clone marker', () => {
|
||||
var layer = new U.Marker(map, [10, 20], {
|
||||
datalayer: datalayer,
|
||||
}).addTo(datalayer)
|
||||
assert.equal(datalayer._index.length, 4)
|
||||
other = layer.clone()
|
||||
assert.ok(map.hasLayer(other))
|
||||
assert.equal(datalayer._index.length, 5)
|
||||
// Must not be the same reference
|
||||
assert.notEqual(layer._latlng, other._latlng)
|
||||
assert.equal(L.Util.formatNum(layer._latlng.lat), other._latlng.lat)
|
||||
assert.equal(L.Util.formatNum(layer._latlng.lng), other._latlng.lng)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#edit()', function (done) {
|
||||
it('should allow changing coordinates manually', () => {
|
||||
var layer = new U.Marker(map, [10, 20], {
|
||||
datalayer: datalayer,
|
||||
}).addTo(datalayer)
|
||||
enableEdit()
|
||||
layer.edit()
|
||||
changeInputValue(qs('form.umap-form input[name="lat"]'), '54.43')
|
||||
assert.equal(layer._latlng.lat, 54.43)
|
||||
})
|
||||
|
||||
it('should not allow invalid latitude nor longitude', () => {
|
||||
var layer = new U.Marker(map, [10, 20], {
|
||||
datalayer: datalayer,
|
||||
}).addTo(datalayer)
|
||||
enableEdit()
|
||||
layer.edit()
|
||||
changeInputValue(qs('form.umap-form input[name="lat"]'), '5443')
|
||||
assert.equal(layer._latlng.lat, 10)
|
||||
changeInputValue(qs('form.umap-form input[name="lng"]'), '5443')
|
||||
assert.equal(layer._latlng.lng, 20)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,111 +0,0 @@
|
|||
describe('U.Polygon', function () {
|
||||
var p2ll, map, datalayer
|
||||
|
||||
before(function () {
|
||||
map = initMap({ umap_id: 99 })
|
||||
enableEdit()
|
||||
p2ll = function (x, y) {
|
||||
return map.containerPointToLatLng([x, y])
|
||||
}
|
||||
datalayer = map.createDataLayer()
|
||||
datalayer.connectToMap()
|
||||
})
|
||||
|
||||
after(function () {
|
||||
clickCancel()
|
||||
resetMap()
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
datalayer.empty()
|
||||
})
|
||||
|
||||
describe('#isMulti()', function () {
|
||||
it('should return false for basic Polygon', function () {
|
||||
var layer = new U.Polygon(
|
||||
map,
|
||||
[
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
[5, 6],
|
||||
],
|
||||
{ datalayer: datalayer }
|
||||
)
|
||||
assert.notOk(layer.isMulti())
|
||||
})
|
||||
|
||||
it('should return false for nested basic Polygon', function () {
|
||||
var latlngs = [[[p2ll(100, 150), p2ll(150, 200), p2ll(200, 100)]]],
|
||||
layer = new U.Polygon(map, latlngs, { datalayer: datalayer })
|
||||
assert.notOk(layer.isMulti())
|
||||
})
|
||||
|
||||
it('should return false for simple Polygon with hole', function () {
|
||||
var layer = new U.Polygon(
|
||||
map,
|
||||
[
|
||||
[
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
[5, 6],
|
||||
],
|
||||
[
|
||||
[7, 8],
|
||||
[9, 10],
|
||||
[11, 12],
|
||||
],
|
||||
],
|
||||
{ datalayer: datalayer }
|
||||
)
|
||||
assert.notOk(layer.isMulti())
|
||||
})
|
||||
|
||||
it('should return true for multi Polygon', function () {
|
||||
var latLngs = [
|
||||
[
|
||||
[
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
[5, 6],
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
[7, 8],
|
||||
[9, 10],
|
||||
[11, 12],
|
||||
],
|
||||
],
|
||||
]
|
||||
var layer = new U.Polygon(map, latLngs, { datalayer: datalayer })
|
||||
assert.ok(layer.isMulti())
|
||||
})
|
||||
|
||||
it('should return true for multi Polygon with hole', function () {
|
||||
var latLngs = [
|
||||
[
|
||||
[
|
||||
[10, 20],
|
||||
[30, 40],
|
||||
[50, 60],
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
[0, 10],
|
||||
[10, 10],
|
||||
[10, 0],
|
||||
],
|
||||
[
|
||||
[2, 3],
|
||||
[2, 4],
|
||||
[3, 4],
|
||||
],
|
||||
],
|
||||
]
|
||||
var layer = new U.Polygon(map, latLngs, { datalayer: datalayer })
|
||||
assert.ok(layer.isMulti())
|
||||
})
|
||||
})
|
||||
|
||||
})
|
|
@ -1,286 +0,0 @@
|
|||
describe('U.Polyline', function () {
|
||||
var p2ll, map
|
||||
|
||||
before(function () {
|
||||
this.map = map = initMap({ umap_id: 99 })
|
||||
enableEdit()
|
||||
p2ll = function (x, y) {
|
||||
return map.containerPointToLatLng([x, y])
|
||||
}
|
||||
this.datalayer = this.map.createDataLayer()
|
||||
this.datalayer.connectToMap()
|
||||
})
|
||||
|
||||
after(function () {
|
||||
clickCancel()
|
||||
resetMap()
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
this.datalayer.empty()
|
||||
})
|
||||
|
||||
describe('#isMulti()', function () {
|
||||
it('should return false for basic Polyline', function () {
|
||||
var layer = new U.Polyline(
|
||||
this.map,
|
||||
[
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
[5, 6],
|
||||
],
|
||||
{ datalayer: this.datalayer }
|
||||
)
|
||||
assert.notOk(layer.isMulti())
|
||||
})
|
||||
|
||||
it('should return false for nested basic Polyline', function () {
|
||||
var layer = new U.Polyline(
|
||||
this.map,
|
||||
[
|
||||
[
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
[5, 6],
|
||||
],
|
||||
],
|
||||
{ datalayer: this.datalayer }
|
||||
)
|
||||
assert.notOk(layer.isMulti())
|
||||
})
|
||||
|
||||
it('should return true for multi Polyline', function () {
|
||||
var latLngs = [
|
||||
[
|
||||
[
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
[5, 6],
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
[7, 8],
|
||||
[9, 10],
|
||||
[11, 12],
|
||||
],
|
||||
],
|
||||
]
|
||||
var layer = new U.Polyline(this.map, latLngs, { datalayer: this.datalayer })
|
||||
assert.ok(layer.isMulti())
|
||||
})
|
||||
})
|
||||
|
||||
describe('#contextmenu', function () {
|
||||
afterEach(function () {
|
||||
// Make sure contextmenu is hidden.
|
||||
happen.once(document, { type: 'keydown', keyCode: 27 })
|
||||
})
|
||||
|
||||
describe('#in edit mode', function () {
|
||||
it('should allow to remove shape when multi', function () {
|
||||
var latlngs = [
|
||||
[p2ll(100, 100), p2ll(100, 200)],
|
||||
[p2ll(300, 350), p2ll(350, 400), p2ll(400, 300)],
|
||||
],
|
||||
layer = new U.Polyline(this.map, latlngs, {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
happen.once(layer._path, { type: 'contextmenu' })
|
||||
assert.equal(qst('Remove shape from the multi'), 1)
|
||||
})
|
||||
|
||||
it('should not allow to remove shape when not multi', function () {
|
||||
var latlngs = [[p2ll(100, 100), p2ll(100, 200)]],
|
||||
layer = new U.Polyline(this.map, latlngs, {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
happen.once(layer._path, { type: 'contextmenu' })
|
||||
assert.notOk(qst('Remove shape from the multi'))
|
||||
})
|
||||
|
||||
it('should not allow to isolate shape when not multi', function () {
|
||||
var latlngs = [[p2ll(100, 100), p2ll(100, 200)]],
|
||||
layer = new U.Polyline(this.map, latlngs, {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
happen.once(layer._path, { type: 'contextmenu' })
|
||||
assert.notOk(qst('Extract shape to separate feature'))
|
||||
})
|
||||
|
||||
it('should allow to isolate shape when multi', function () {
|
||||
var latlngs = [
|
||||
[p2ll(100, 150), p2ll(100, 200)],
|
||||
[p2ll(300, 350), p2ll(350, 400), p2ll(400, 300)],
|
||||
],
|
||||
layer = new U.Polyline(this.map, latlngs, {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
happen.once(layer._path, { type: 'contextmenu' })
|
||||
assert.ok(qst('Extract shape to separate feature'))
|
||||
})
|
||||
|
||||
it('should not allow to transform to polygon when multi', function () {
|
||||
var latlngs = [
|
||||
[p2ll(100, 150), p2ll(100, 200)],
|
||||
[p2ll(300, 350), p2ll(350, 400), p2ll(400, 300)],
|
||||
],
|
||||
layer = new U.Polyline(this.map, latlngs, {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
happen.once(layer._path, { type: 'contextmenu' })
|
||||
assert.notOk(qst('Transform to polygon'))
|
||||
})
|
||||
|
||||
it('should allow to transform to polygon when not multi', function () {
|
||||
var latlngs = [p2ll(100, 150), p2ll(100, 200), p2ll(200, 100)],
|
||||
layer = new U.Polyline(this.map, latlngs, {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
happen.once(layer._path, { type: 'contextmenu' })
|
||||
assert.equal(qst('Transform to polygon'), 1)
|
||||
})
|
||||
|
||||
it('should not allow to transfer shape when not editedFeature', function () {
|
||||
var layer = new U.Polyline(this.map, [p2ll(100, 150), p2ll(100, 200)], {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
happen.once(layer._path, { type: 'contextmenu' })
|
||||
assert.notOk(qst('Transfer shape to edited feature'))
|
||||
})
|
||||
|
||||
it('should not allow to transfer shape when editedFeature is not a line', function () {
|
||||
var layer = new U.Polyline(this.map, [p2ll(100, 150), p2ll(100, 200)], {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer),
|
||||
other = new U.Polygon(
|
||||
this.map,
|
||||
[p2ll(200, 300), p2ll(300, 200), p2ll(200, 100)],
|
||||
{ datalayer: this.datalayer }
|
||||
).addTo(this.datalayer)
|
||||
other.edit()
|
||||
happen.once(layer._path, { type: 'contextmenu' })
|
||||
assert.notOk(qst('Transfer shape to edited feature'))
|
||||
})
|
||||
|
||||
it('should allow to transfer shape when another line is edited', function () {
|
||||
var layer = new U.Polyline(
|
||||
this.map,
|
||||
[p2ll(100, 150), p2ll(100, 200), p2ll(200, 100)],
|
||||
{ datalayer: this.datalayer }
|
||||
).addTo(this.datalayer),
|
||||
other = new U.Polyline(this.map, [p2ll(200, 300), p2ll(300, 200)], {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
other.edit()
|
||||
happen.once(layer._path, { type: 'contextmenu' })
|
||||
assert.equal(qst('Transfer shape to edited feature'), 1)
|
||||
other.remove()
|
||||
layer.remove()
|
||||
})
|
||||
|
||||
it('should allow to merge lines when multi', function () {
|
||||
var latlngs = [
|
||||
[p2ll(100, 100), p2ll(100, 200)],
|
||||
[p2ll(300, 350), p2ll(350, 400), p2ll(400, 300)],
|
||||
],
|
||||
layer = new U.Polyline(this.map, latlngs, {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
happen.once(layer._path, { type: 'contextmenu' })
|
||||
assert.equal(qst('Merge lines'), 1)
|
||||
})
|
||||
|
||||
it('should not allow to merge lines when not multi', function () {
|
||||
var latlngs = [[p2ll(100, 100), p2ll(100, 200)]],
|
||||
layer = new U.Polyline(this.map, latlngs, {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
happen.once(layer._path, { type: 'contextmenu' })
|
||||
assert.notOk(qst('Merge lines'))
|
||||
})
|
||||
|
||||
it('should allow to split lines when clicking on vertex', function () {
|
||||
var latlngs = [[p2ll(300, 350), p2ll(350, 400), p2ll(400, 300)]],
|
||||
layer = new U.Polyline(this.map, latlngs, {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
layer.enableEdit()
|
||||
happen.at('contextmenu', 350, 400)
|
||||
assert.equal(qst('Split line'), 1)
|
||||
})
|
||||
|
||||
it('should not allow to split lines when clicking on first vertex', function () {
|
||||
var latlngs = [[p2ll(300, 350), p2ll(350, 400), p2ll(400, 300)]],
|
||||
layer = new U.Polyline(this.map, latlngs, {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
layer.enableEdit()
|
||||
happen.at('contextmenu', 300, 350)
|
||||
assert.equal(qst('Delete this feature'), 1) // Make sure we have clicked on the vertex.
|
||||
assert.notOk(qst('Split line'))
|
||||
})
|
||||
|
||||
it('should not allow to split lines when clicking on last vertex', function () {
|
||||
var latlngs = [[p2ll(300, 350), p2ll(350, 400), p2ll(400, 300)]],
|
||||
layer = new U.Polyline(this.map, latlngs, {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
layer.enableEdit()
|
||||
happen.at('contextmenu', 400, 300)
|
||||
assert.equal(qst('Delete this feature'), 1) // Make sure we have clicked on the vertex.
|
||||
assert.notOk(qst('Split line'))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('#mergeShapes', function () {
|
||||
it('should remove duplicated join point when merging', function () {
|
||||
var latlngs = [
|
||||
[
|
||||
[0, 0],
|
||||
[0, 1],
|
||||
],
|
||||
[
|
||||
[0, 1],
|
||||
[0, 2],
|
||||
],
|
||||
],
|
||||
layer = new U.Polyline(this.map, latlngs, {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
layer.mergeShapes()
|
||||
layer.disableEdit() // Remove vertex from latlngs to compare them.
|
||||
assert.deepEqual(layer.getLatLngs(), [
|
||||
L.latLng([0, 0]),
|
||||
L.latLng([0, 1]),
|
||||
L.latLng([0, 2]),
|
||||
])
|
||||
assert(this.map.isDirty)
|
||||
})
|
||||
|
||||
it('should revert candidate if first point is closer', function () {
|
||||
var latlngs = [
|
||||
[
|
||||
[0, 0],
|
||||
[0, 1],
|
||||
],
|
||||
[
|
||||
[0, 2],
|
||||
[0, 1],
|
||||
],
|
||||
],
|
||||
layer = new U.Polyline(this.map, latlngs, {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
layer.mergeShapes()
|
||||
layer.disableEdit()
|
||||
assert.deepEqual(layer.getLatLngs(), [
|
||||
L.latLng([0, 0]),
|
||||
L.latLng([0, 1]),
|
||||
L.latLng([0, 2]),
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
})
|
|
@ -1,28 +0,0 @@
|
|||
describe('L.Util', function () {
|
||||
describe('#TextColorFromBackgroundColor', function () {
|
||||
it('should output white for black', function () {
|
||||
document.body.style.backgroundColor = 'black'
|
||||
assert.equal(L.DomUtil.TextColorFromBackgroundColor(document.body), '#ffffff')
|
||||
})
|
||||
|
||||
it('should output white for brown', function () {
|
||||
document.body.style.backgroundColor = 'brown'
|
||||
assert.equal(L.DomUtil.TextColorFromBackgroundColor(document.body), '#ffffff')
|
||||
})
|
||||
|
||||
it('should output black for white', function () {
|
||||
document.body.style.backgroundColor = 'white'
|
||||
assert.equal(L.DomUtil.TextColorFromBackgroundColor(document.body), '#000000')
|
||||
})
|
||||
|
||||
it('should output black for tan', function () {
|
||||
document.body.style.backgroundColor = 'tan'
|
||||
assert.equal(L.DomUtil.TextColorFromBackgroundColor(document.body), '#000000')
|
||||
})
|
||||
|
||||
it('should output black by default', function () {
|
||||
document.body.style.backgroundColor = 'transparent'
|
||||
assert.equal(L.DomUtil.TextColorFromBackgroundColor(document.body), '#000000')
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,455 +0,0 @@
|
|||
window.assert = chai.assert
|
||||
window.expect = chai.expect
|
||||
|
||||
var qs = function (selector, element) {
|
||||
return (element || document).querySelector(selector)
|
||||
}
|
||||
var qsa = function (selector) {
|
||||
return document.querySelectorAll(selector)
|
||||
}
|
||||
var qst = function (text, parent) {
|
||||
// find element by its text content
|
||||
var r = document.evaluate(
|
||||
"descendant::*[contains(text(),'" + text + "')]",
|
||||
parent || qs('#map'),
|
||||
null,
|
||||
XPathResult.UNORDERED_NODE_ITERATOR_TYPE,
|
||||
null
|
||||
),
|
||||
count = 0
|
||||
while (r.iterateNext()) console.log(++count)
|
||||
return count
|
||||
}
|
||||
happen.at = function (what, x, y, props) {
|
||||
this.once(
|
||||
document.elementFromPoint(x, y),
|
||||
L.Util.extend(
|
||||
{
|
||||
type: what,
|
||||
clientX: x,
|
||||
clientY: y,
|
||||
screenX: x,
|
||||
screenY: y,
|
||||
which: 1,
|
||||
button: 0,
|
||||
},
|
||||
props || {}
|
||||
)
|
||||
)
|
||||
}
|
||||
var resetMap = function () {
|
||||
var mapElement = qs('#map')
|
||||
mapElement.innerHTML = 'Done'
|
||||
delete mapElement._leaflet_id
|
||||
document.body.className = ''
|
||||
}
|
||||
var enableEdit = function () {
|
||||
happen.click(qs('div.leaflet-control-edit-enable button'))
|
||||
}
|
||||
var disableEdit = function () {
|
||||
happen.click(qs('.leaflet-control-edit-disable'))
|
||||
}
|
||||
var clickSave = function () {
|
||||
happen.click(qs('.leaflet-control-edit-save'))
|
||||
}
|
||||
var clickCancel = function () {
|
||||
var _confirm = window.confirm
|
||||
window.confirm = function (text) {
|
||||
return true
|
||||
}
|
||||
happen.click(qs('button.leaflet-control-edit-cancel'))
|
||||
happen.once(document.body, { type: 'keypress', keyCode: 13 })
|
||||
window.confirm = _confirm
|
||||
}
|
||||
var changeInputValue = function (input, value) {
|
||||
input.value = value
|
||||
happen.once(input, { type: 'input' })
|
||||
happen.once(input, { type: 'blur' })
|
||||
}
|
||||
var changeSelectValue = function (path_or_select, value) {
|
||||
if (typeof path_or_select === 'string') path_or_select = qs(path_or_select)
|
||||
var found = false
|
||||
for (var i = 0; i < path_or_select.length; i++) {
|
||||
if (path_or_select.options[i].value === value) {
|
||||
path_or_select.options[i].selected = true
|
||||
found = true
|
||||
}
|
||||
}
|
||||
happen.once(path_or_select, { type: 'change' })
|
||||
if (!found)
|
||||
throw new Error('Value ' + value + 'not found in select ' + path_or_select)
|
||||
return path_or_select
|
||||
}
|
||||
var cleanAlert = function () {
|
||||
L.DomUtil.removeClass(qs('#map'), 'umap-alert')
|
||||
L.DomUtil.get('umap-alert-container').innerHTML = ''
|
||||
UI_ALERT_ID = null // Prevent setTimeout to be called
|
||||
}
|
||||
var defaultDatalayerData = function (custom) {
|
||||
var _default = {
|
||||
iconClass: 'Default',
|
||||
name: 'Elephants',
|
||||
displayOnLoad: true,
|
||||
id: 62,
|
||||
pictogram_url: null,
|
||||
weight: null,
|
||||
fillColor: '',
|
||||
color: '',
|
||||
stroke: true,
|
||||
smoothFactor: null,
|
||||
dashArray: '',
|
||||
fill: true,
|
||||
}
|
||||
return L.extend({}, _default, custom)
|
||||
}
|
||||
|
||||
function initMap(options) {
|
||||
default_options = {
|
||||
type: 'Feature',
|
||||
properties: {
|
||||
umap_id: 42,
|
||||
datalayers: [],
|
||||
urls: {
|
||||
map: '/map/{slug}_{pk}',
|
||||
datalayer_view: '/datalayer/{pk}/',
|
||||
map_update: '/map/{map_id}/update/settings/',
|
||||
map_old_url: '/map/{username}/{slug}/',
|
||||
map_clone: '/map/{map_id}/update/clone/',
|
||||
map_short_url: '/m/{pk}/',
|
||||
map_anonymous_edit_url: '/map/anonymous-edit/{signature}',
|
||||
map_new: '/map/new/',
|
||||
datalayer_update: '/map/{map_id}/datalayer/update/{pk}/',
|
||||
map_delete: '/map/{map_id}/update/delete/',
|
||||
map_create: '/map/create/',
|
||||
logout: '/logout/',
|
||||
datalayer_create: '/map/{map_id}/datalayer/create/',
|
||||
login_popup_end: '/login/popupd/',
|
||||
login: '/login/',
|
||||
datalayer_delete: '/map/{map_id}/datalayer/delete/{pk}/',
|
||||
datalayer_versions: '/map/{map_id}/datalayer/{pk}/versions/',
|
||||
datalayer_version: '/datalayer/{pk}/{name}',
|
||||
pictogram_list_json: '/pictogram/json/',
|
||||
map_update_permissions: '/map/{map_id}/update/permissions/',
|
||||
map_download: '/map/{map_id}/download/',
|
||||
},
|
||||
default_iconUrl: '../src/img/marker.svg',
|
||||
zoom: 6,
|
||||
share_statuses: [
|
||||
[1, 'Tout le monde (public)'],
|
||||
[2, 'Quiconque a le lien'],
|
||||
[3, 'Éditeurs uniquement'],
|
||||
],
|
||||
tilelayers: [
|
||||
{
|
||||
attribution: '\u00a9 OSM Contributors',
|
||||
name: 'OpenStreetMap',
|
||||
url_template: 'http://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png',
|
||||
minZoom: 0,
|
||||
maxZoom: 18,
|
||||
id: 1,
|
||||
selected: true,
|
||||
},
|
||||
{
|
||||
attribution: 'HOT and friends',
|
||||
name: 'HOT OSM-fr server',
|
||||
url_template: 'http://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png',
|
||||
rank: 99,
|
||||
minZoom: 0,
|
||||
maxZoom: 20,
|
||||
id: 2,
|
||||
},
|
||||
],
|
||||
tilelayer: {
|
||||
attribution: 'HOT and friends',
|
||||
name: 'HOT OSM-fr server',
|
||||
url_template: 'http://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png',
|
||||
rank: 99,
|
||||
minZoom: 0,
|
||||
maxZoom: 20,
|
||||
id: 2,
|
||||
},
|
||||
licences: {
|
||||
'No licence set': {
|
||||
url: '',
|
||||
name: 'No licence set',
|
||||
},
|
||||
'Licence ouverte/Open Licence': {
|
||||
url: 'http://www.data.gouv.fr/Licence-Ouverte-Open-Licence',
|
||||
name: 'Licence ouverte/Open Licence',
|
||||
},
|
||||
'WTFPL': {
|
||||
url: 'http://www.wtfpl.net/',
|
||||
name: 'WTFPL',
|
||||
},
|
||||
'ODbl': {
|
||||
url: 'http://opendatacommons.org/licenses/odbl/',
|
||||
name: 'ODbl',
|
||||
},
|
||||
},
|
||||
name: 'name of the map',
|
||||
description: 'The description of the map',
|
||||
locale: 'en',
|
||||
editMode: 'advanced',
|
||||
moreControl: true,
|
||||
scaleControl: true,
|
||||
miniMap: false,
|
||||
datalayersControl: true,
|
||||
displayCaptionOnLoad: false,
|
||||
displayPopupFooter: false,
|
||||
displayDataBrowserOnLoad: false,
|
||||
permissions: {
|
||||
share_status: 1,
|
||||
owner: {
|
||||
id: 1,
|
||||
name: 'ybon',
|
||||
url: '/en/user/ybon/',
|
||||
},
|
||||
editors: [],
|
||||
},
|
||||
user: {
|
||||
id: 1,
|
||||
name: 'foofoo',
|
||||
url: '/en/me',
|
||||
},
|
||||
},
|
||||
}
|
||||
options = options || {}
|
||||
options.properties = L.extend({}, default_options.properties, options)
|
||||
options.geometry = {
|
||||
type: 'Point',
|
||||
coordinates: [5.0592041015625, 52.05924589011585],
|
||||
}
|
||||
return new U.Map('map', options)
|
||||
}
|
||||
|
||||
var RESPONSES = {
|
||||
datalayer62_GET: {
|
||||
crs: null,
|
||||
type: 'FeatureCollection',
|
||||
_umap_options: defaultDatalayerData(),
|
||||
features: [
|
||||
{
|
||||
geometry: {
|
||||
type: 'Point',
|
||||
coordinates: [-0.274658203125, 52.57634993749885],
|
||||
},
|
||||
type: 'Feature',
|
||||
id: 1807,
|
||||
properties: { _umap_options: { color: 'OliveDrab' }, name: 'test' },
|
||||
},
|
||||
{
|
||||
geometry: {
|
||||
type: 'LineString',
|
||||
coordinates: [
|
||||
[-0.5712890625, 54.47642158429295],
|
||||
[0.439453125, 54.610254981579146],
|
||||
[1.724853515625, 53.44880683542759],
|
||||
[4.163818359375, 53.98839506479995],
|
||||
[5.306396484375, 53.533778184257805],
|
||||
[6.591796875, 53.70971358510174],
|
||||
[7.042236328124999, 53.35055131839989],
|
||||
],
|
||||
},
|
||||
type: 'Feature',
|
||||
id: 20,
|
||||
properties: { _umap_options: { fill: false, opacity: 0.6 }, name: 'test' },
|
||||
},
|
||||
{
|
||||
geometry: {
|
||||
type: 'Polygon',
|
||||
coordinates: [
|
||||
[
|
||||
[11.25, 53.585983654559804],
|
||||
[10.1513671875, 52.9751081817353],
|
||||
[12.689208984375, 52.16719363541221],
|
||||
[14.084472656249998, 53.199451902831555],
|
||||
[12.63427734375, 53.61857936489517],
|
||||
[11.25, 53.585983654559804],
|
||||
[11.25, 53.585983654559804],
|
||||
],
|
||||
],
|
||||
},
|
||||
type: 'Feature',
|
||||
id: 76,
|
||||
properties: { name: 'name poly' },
|
||||
},
|
||||
],
|
||||
},
|
||||
// This one is non browsable
|
||||
datalayer63_GET: {
|
||||
crs: null,
|
||||
type: 'FeatureCollection',
|
||||
_umap_options: defaultDatalayerData({ id: 63, browsable: false }),
|
||||
features: [
|
||||
{
|
||||
geometry: {
|
||||
type: 'Polygon',
|
||||
coordinates: [
|
||||
[
|
||||
[5.545478, 45.068383],
|
||||
[5.545907, 45.067277],
|
||||
[5.548439, 45.067565],
|
||||
[5.552516, 45.06752],
|
||||
[5.553288, 45.068217],
|
||||
[5.549405, 45.069247],
|
||||
[5.548224, 45.071005],
|
||||
[5.545907, 45.071096],
|
||||
[5.545478, 45.068383],
|
||||
],
|
||||
],
|
||||
},
|
||||
type: 'Feature',
|
||||
id: 76,
|
||||
properties: { name: 'non browsable 1' },
|
||||
},
|
||||
{
|
||||
type: 'Feature',
|
||||
properties: {
|
||||
_umap_options: {
|
||||
color: 'SteelBlue',
|
||||
},
|
||||
name: 'non browsable 2',
|
||||
},
|
||||
geometry: {
|
||||
type: 'Polygon',
|
||||
coordinates: [
|
||||
[
|
||||
[5.550542, 45.071717],
|
||||
[5.548182, 45.071051],
|
||||
[5.549426, 45.069232],
|
||||
[5.553331, 45.068171],
|
||||
[5.554812, 45.070869],
|
||||
[5.553396, 45.072384],
|
||||
[5.550542, 45.071717],
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
// This one is not shown at load
|
||||
datalayer64_GET: {
|
||||
crs: null,
|
||||
type: 'FeatureCollection',
|
||||
_umap_options: defaultDatalayerData({
|
||||
name: 'hidden',
|
||||
id: 64,
|
||||
displayOnLoad: false,
|
||||
}),
|
||||
features: [
|
||||
{
|
||||
geometry: {
|
||||
type: 'Polygon',
|
||||
coordinates: [
|
||||
[
|
||||
[5.545478, 45.068383],
|
||||
[5.545907, 45.067277],
|
||||
[5.548439, 45.067565],
|
||||
[5.552516, 45.06752],
|
||||
[5.553288, 45.068217],
|
||||
[5.549405, 45.069247],
|
||||
[5.548224, 45.071005],
|
||||
[5.545907, 45.071096],
|
||||
[5.545478, 45.068383],
|
||||
],
|
||||
],
|
||||
},
|
||||
type: 'Feature',
|
||||
id: 76,
|
||||
properties: { name: 'not shown at load 1' },
|
||||
},
|
||||
{
|
||||
type: 'Feature',
|
||||
properties: {
|
||||
_umap_options: {
|
||||
color: 'AliceBlue',
|
||||
},
|
||||
name: 'not shown at load 2',
|
||||
},
|
||||
geometry: {
|
||||
type: 'Polygon',
|
||||
coordinates: [
|
||||
[
|
||||
[5.550542, 45.071717],
|
||||
[5.548182, 45.071051],
|
||||
[5.549426, 45.069232],
|
||||
[5.553331, 45.068171],
|
||||
[5.554812, 45.070869],
|
||||
[5.553396, 45.072384],
|
||||
[5.550542, 45.071717],
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
var kml_example =
|
||||
'<?xml version="1.0" encoding="UTF-8"?>' +
|
||||
'<kml xmlns="http://www.opengis.net/kml/2.2">' +
|
||||
'<Placemark>' +
|
||||
'<name>Simple point</name>' +
|
||||
'<description>Here is a simple description.</description>' +
|
||||
'<Point>' +
|
||||
'<coordinates>-122.0822035425683,37.42228990140251,0</coordinates>' +
|
||||
'</Point>' +
|
||||
'</Placemark>' +
|
||||
'<Placemark>' +
|
||||
'<name>Simple path</name>' +
|
||||
'<description>Simple description</description>' +
|
||||
'<LineString>' +
|
||||
'<coordinates>-112.2550785337791,36.07954952145647,2357 -112.2549277039738,36.08117083492122,2357 -112.2552505069063,36.08260761307279,2357</coordinates>' +
|
||||
'</LineString>' +
|
||||
'</Placemark>' +
|
||||
'<Placemark>' +
|
||||
'<name>Simple polygon</name>' +
|
||||
'<description>A description.</description>' +
|
||||
'<Polygon>' +
|
||||
'<outerBoundaryIs>' +
|
||||
'<LinearRing>' +
|
||||
'<coordinates>' +
|
||||
' -77.05788457660967,38.87253259892824,100 ' +
|
||||
' -77.05465973756702,38.87291016281703,100 ' +
|
||||
' -77.05315536854791,38.87053267794386,100 ' +
|
||||
' -77.05788457660967,38.87253259892824,100 ' +
|
||||
'</coordinates>' +
|
||||
'</LinearRing>' +
|
||||
'</outerBoundaryIs>' +
|
||||
'</Polygon>' +
|
||||
'</Placemark>' +
|
||||
'</kml>'
|
||||
|
||||
var gpx_example =
|
||||
'<gpx' +
|
||||
' version="1.1"' +
|
||||
' creator="GPSBabel - http://www.gpsbabel.org"' +
|
||||
' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' +
|
||||
' xmlns="http://www.topografix.com/GPX/1/1"' +
|
||||
' xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">' +
|
||||
' <wpt lat="45.44283" lon="-121.72904"><ele>1374</ele><name>Simple Point</name><desc>Simple description</desc></wpt>' +
|
||||
' <trk>' +
|
||||
' <name>Simple path</name>' +
|
||||
' <desc>Simple description</desc>' +
|
||||
' <trkseg>' +
|
||||
' <trkpt lat="45.4431641" lon="-121.7295456"></trkpt>' +
|
||||
' <trkpt lat="45.4428615" lon="-121.7290800"></trkpt>' +
|
||||
' <trkpt lat="45.4425697" lon="-121.7279085"></trkpt>' +
|
||||
' </trkseg>' +
|
||||
' </trk>' +
|
||||
'</gpx>'
|
||||
|
||||
var csv_example =
|
||||
'Foo,Latitude,Longitude,title,description\n' +
|
||||
'bar,41.34,122.86,a point somewhere,the description of this point'
|
||||
|
||||
// Make Sinon log readable
|
||||
sinon.format = function (what) {
|
||||
if (typeof what === 'object') {
|
||||
return JSON.stringify(what, null, 4)
|
||||
} else if (typeof what === 'undefined') {
|
||||
return ''
|
||||
} else {
|
||||
return what.toString()
|
||||
}
|
||||
}
|
|
@ -1,139 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Umap front Tests</title>
|
||||
<meta charset="utf-8" />
|
||||
<script type="module" src="../js/modules/leaflet-configure.js" defer></script>
|
||||
<script type="module" src="../js/modules/global.js" defer></script>
|
||||
|
||||
<script src="../vendors/editable/Path.Drag.js" defer></script>
|
||||
<script src="../vendors/editable/Leaflet.Editable.js" defer></script>
|
||||
<script src="../vendors/hash/leaflet-hash.js" defer></script>
|
||||
<script src="../vendors/editinosm/Leaflet.EditInOSM.js" defer></script>
|
||||
<script src="../vendors/minimap/Control.MiniMap.min.js" defer></script>
|
||||
<script src="../vendors/csv2geojson/csv2geojson.js" defer></script>
|
||||
<script src="../vendors/togeojson/togeojson.umd.js" defer></script>
|
||||
<script src="../vendors/osmtogeojson/osmtogeojson.js" defer></script>
|
||||
<script src="../vendors/loading/Control.Loading.js" defer></script>
|
||||
<script src="../vendors/markercluster/leaflet.markercluster.js" defer></script>
|
||||
<script src="../vendors/contextmenu/leaflet.contextmenu.min.js" defer></script>
|
||||
<script src="../vendors/photon/leaflet.photon.js" defer></script>
|
||||
<script src="../vendors/georsstogeojson/GeoRSSToGeoJSON.js" defer></script>
|
||||
<script src="../vendors/heat/leaflet-heat.js" defer></script>
|
||||
<script src="../vendors/fullscreen/Leaflet.fullscreen.min.js" defer></script>
|
||||
<script src="../vendors/toolbar/leaflet.toolbar.js" defer></script>
|
||||
<script src="../vendors/formbuilder/Leaflet.FormBuilder.js" defer></script>
|
||||
<script src="../vendors/measurable/Leaflet.Measurable.js" defer></script>
|
||||
<script src="../vendors/togpx/togpx.js" defer></script>
|
||||
<script src="../vendors/iconlayers/iconLayers.js" defer></script>
|
||||
<script src="../vendors/tokml/tokml.js" defer></script>
|
||||
<script src="../vendors/locatecontrol/L.Control.Locate.min.js" defer></script>
|
||||
<script src="../vendors/colorbrewer/colorbrewer.js" defer></script>
|
||||
<script src="../vendors/simple-statistics/simple-statistics.min.js" defer></script>
|
||||
|
||||
<script src="../js/umap.core.js" defer></script>
|
||||
<script src="../js/umap.autocomplete.js" defer></script>
|
||||
<script src="../js/umap.popup.js" defer></script>
|
||||
<script src="../js/umap.forms.js" defer></script>
|
||||
<script src="../js/umap.icon.js" defer></script>
|
||||
<script src="../js/umap.features.js" defer></script>
|
||||
<script src="../js/umap.permissions.js" defer></script>
|
||||
<script src="../js/umap.datalayer.permissions.js" defer></script>
|
||||
<script src="../js/umap.layer.js" defer></script>
|
||||
<script src="../js/umap.controls.js" defer></script>
|
||||
<script src="../js/umap.slideshow.js" defer></script>
|
||||
<script src="../js/umap.tableeditor.js" defer></script>
|
||||
<script src="../js/umap.importer.js" defer></script>
|
||||
<script src="../js/umap.share.js" defer></script>
|
||||
<script src="../js/umap.js" defer></script>
|
||||
<script src="../js/umap.ui.js" defer></script>
|
||||
<script src="../js/components/fragment.js" defer></script>
|
||||
|
||||
<link rel="stylesheet" href="../vendors/leaflet/leaflet.css" />
|
||||
<link rel="stylesheet" href="../vendors/markercluster/MarkerCluster.css" />
|
||||
<link rel="stylesheet" href="../vendors/markercluster/MarkerCluster.Default.css" />
|
||||
<link rel="stylesheet" href="../vendors/editinosm/Leaflet.EditInOSM.css" />
|
||||
<link rel="stylesheet" href="../vendors/minimap/Control.MiniMap.min.css" />
|
||||
<link rel="stylesheet" href="../vendors/contextmenu/leaflet.contextmenu.min.css" />
|
||||
<link rel="stylesheet" href="../vendors/toolbar/leaflet.toolbar.css" />
|
||||
<link rel="stylesheet" href="../vendors/measurable/Leaflet.Measurable.css" />
|
||||
<link rel="stylesheet" href="../vendors/fullscreen/leaflet.fullscreen.css" />
|
||||
<link rel="stylesheet" href="../vendors/locatecontrol/L.Control.Locate.min.css" />
|
||||
<link rel="stylesheet" href="../vendors/iconlayers/iconLayers.css" />
|
||||
|
||||
<link rel="stylesheet" href="../../umap/vars.css" />
|
||||
<link rel="stylesheet" href="../../umap/font.css" />
|
||||
<link rel="stylesheet" href="../../umap/base.css" />
|
||||
<link rel="stylesheet" href="../../umap/content.css" />
|
||||
<link rel="stylesheet" href="../../umap/nav.css" />
|
||||
<link rel="stylesheet" href="../../umap/map.css" />
|
||||
<link rel="stylesheet" href="../../umap/theme.css" />
|
||||
|
||||
<script src="../../../../node_modules/sinon/pkg/sinon.js"></script>
|
||||
<script src="../../../../node_modules/mocha/mocha.js"></script>
|
||||
<script src="../../../../node_modules/chai/chai.js"></script>
|
||||
<script src="../../../../node_modules/happen/happen.js"></script>
|
||||
<link rel="stylesheet" href="../../../../node_modules/mocha/mocha.css" />
|
||||
<script type="module">
|
||||
import fetchMock from '../../../../node_modules/fetch-mock/esm/client.js';
|
||||
window.fetchMock = fetchMock
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
mocha.setup({
|
||||
ui: 'bdd',
|
||||
bail: window.location.search.indexOf('failfast') !== -1,
|
||||
ignoreLeaks: true,
|
||||
})
|
||||
chai.config.includeStack = true
|
||||
</script>
|
||||
<script src="./_pre.js" defer></script>
|
||||
<script src="./Map.js" defer></script>
|
||||
<script src="./Feature.js" defer></script>
|
||||
<script src="./Marker.js" defer></script>
|
||||
<script src="./Polyline.js" defer></script>
|
||||
<script src="./Polygon.js" defer></script>
|
||||
<script src="./Util.js" defer></script>
|
||||
<script type="module" src="./URLs.js" defer></script>
|
||||
<style type="text/css">
|
||||
#mocha {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 10000;
|
||||
background-color: white;
|
||||
box-shadow: 0px 0px 8px 0px black;
|
||||
overflow-y: auto;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#mocha-stats {
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="mocha"></div>
|
||||
<div id="map"></div>
|
||||
<script>
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
var runner = (window.mochaPhantomJS || window.mocha).run(function (failures) {
|
||||
if (window.location.search.indexOf('debug') === -1)
|
||||
qs('#mocha').style.display = 'block'
|
||||
console.log(failures)
|
||||
})
|
||||
if (window.location.search.indexOf('debug') !== -1) {
|
||||
runner.on('fail', function (test, err) {
|
||||
console.log(test.title, test.err)
|
||||
console.log(test.err.expected, test.err.actual)
|
||||
console.log(test.err.stack)
|
||||
})
|
||||
sinon.log = function (message) {
|
||||
console.log(message)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -44,6 +44,7 @@
|
|||
--small-box-padding: 4px;
|
||||
--box-margin: 14px;
|
||||
--text-margin: 7px;
|
||||
--dialog-width: 40vw;
|
||||
|
||||
/* z-indexes (leaflet CSS sets the map at 400 by default) */
|
||||
--zindex-alert: 500;
|
||||
|
|
Loading…
Reference in a new issue