umap-project 2.4.0b2__py3-none-any.whl → 2.4.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of umap-project might be problematic. Click here for more details.
- umap/__init__.py +1 -1
- umap/locale/en/LC_MESSAGES/django.po +11 -11
- umap/locale/pt/LC_MESSAGES/django.mo +0 -0
- umap/locale/pt/LC_MESSAGES/django.po +87 -37
- umap/static/umap/base.css +19 -5
- umap/static/umap/img/16-white.svg +1 -3
- umap/static/umap/img/source/16-white.svg +2 -4
- umap/static/umap/js/modules/browser.js +5 -5
- umap/static/umap/js/modules/caption.js +1 -1
- umap/static/umap/js/modules/utils.js +3 -3
- umap/static/umap/js/umap.features.js +11 -3
- umap/static/umap/js/umap.js +47 -48
- umap/static/umap/js/umap.layer.js +11 -1
- umap/static/umap/js/umap.popup.js +1 -1
- umap/static/umap/locale/en.js +2 -1
- umap/static/umap/locale/en.json +2 -1
- umap/static/umap/locale/es.js +9 -8
- umap/static/umap/locale/es.json +9 -8
- umap/static/umap/locale/fr.js +2 -1
- umap/static/umap/locale/fr.json +2 -1
- umap/static/umap/locale/pt.js +61 -60
- umap/static/umap/locale/pt.json +61 -60
- umap/static/umap/map.css +14 -13
- umap/static/umap/unittests/utils.js +5 -5
- umap/static/umap/vars.css +2 -1
- umap/static/umap/vendors/dompurify/purify.es.js +59 -5
- umap/static/umap/vendors/dompurify/purify.es.mjs.map +1 -1
- umap/static/umap/vendors/formbuilder/Leaflet.FormBuilder.js +2 -2
- umap/tests/integration/test_browser.py +76 -3
- umap/tests/integration/test_edit_polygon.py +11 -0
- umap/tests/integration/test_map.py +29 -0
- umap/tests/integration/test_view_marker.py +2 -2
- {umap_project-2.4.0b2.dist-info → umap_project-2.4.1.dist-info}/METADATA +2 -2
- {umap_project-2.4.0b2.dist-info → umap_project-2.4.1.dist-info}/RECORD +37 -46
- {umap_project-2.4.0b2.dist-info → umap_project-2.4.1.dist-info}/WHEEL +1 -1
- umap/.DS_Store +0 -0
- umap/static/.DS_Store +0 -0
- umap/static/umap/.DS_Store +0 -0
- umap/static/umap/favicons/.DS_Store +0 -0
- umap/static/umap/fonts/.DS_Store +0 -0
- umap/static/umap/img/.DS_Store +0 -0
- umap/static/umap/img/source/.DS_Store +0 -0
- umap/tests/.DS_Store +0 -0
- umap/tests/integration/.DS_Store +0 -0
- {umap_project-2.4.0b2.dist-info → umap_project-2.4.1.dist-info}/entry_points.txt +0 -0
- {umap_project-2.4.0b2.dist-info → umap_project-2.4.1.dist-info}/licenses/LICENSE +0 -0
umap/static/umap/locale/pt.json
CHANGED
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
"About": "Sobre",
|
|
15
15
|
"Action not allowed :(": "Ação não permitida :(",
|
|
16
16
|
"Activate slideshow mode": "Ativar modo de apresentação",
|
|
17
|
-
"Add a layer": "Adicionar camada",
|
|
17
|
+
"Add a layer": "Adicionar uma camada",
|
|
18
18
|
"Add a line to the current multi": "Adicionar uma linha ao multipolígono atual",
|
|
19
19
|
"Add a new property": "Adicionar uma nova propriedade",
|
|
20
20
|
"Add a polygon to the current multi": "Adicionar um polígono ao multipolígono atual",
|
|
21
|
-
"Add image URL": "Adicionar URL
|
|
21
|
+
"Add image URL": "Adicionar URL de imagem",
|
|
22
22
|
"Add": "Adicionar",
|
|
23
23
|
"Advanced actions": "Ações avançadas",
|
|
24
24
|
"Advanced properties": "Propriedades avançadas",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"by": "por",
|
|
49
49
|
"Cache proxied request": "Pedido cache com proxy",
|
|
50
50
|
"Cancel edits": "Cancelar edições",
|
|
51
|
-
"Caption": "
|
|
51
|
+
"Caption": "Legenda",
|
|
52
52
|
"Center map on your location": "Centrar mapa na sua localização",
|
|
53
53
|
"Change map background": "Mudar fundo do mapa",
|
|
54
54
|
"Change tilelayers": "Alterar camadas de mosaicos",
|
|
@@ -121,12 +121,12 @@
|
|
|
121
121
|
"Display the embed control": "Mostrar o botão de partilha e descarregar",
|
|
122
122
|
"Display the fullscreen control": "Mostrar o botão de ecrã inteiro",
|
|
123
123
|
"Display the locate control": "Mostrar o botão de localização GPS",
|
|
124
|
-
"Display the measure control": "Mostrar o botão de
|
|
124
|
+
"Display the measure control": "Mostrar o botão de medir",
|
|
125
125
|
"Display the search control": "Mostrar o botão de pesquisa",
|
|
126
|
-
"Display the star map button": "
|
|
126
|
+
"Display the star map button": "Mostrar o botão de estrela do mapa",
|
|
127
127
|
"Display the tile layers control": "Mostrar o botão de camadas de mosaicos",
|
|
128
128
|
"Display the zoom control": "Mostrar os botões de aproximar e afastar (zoom)",
|
|
129
|
-
"Do you want to display a caption bar?": "Mostrar uma barra de
|
|
129
|
+
"Do you want to display a caption bar?": "Mostrar uma barra de legenda?",
|
|
130
130
|
"Do you want to display a minimap?": "Mostrar um mini-mapa?",
|
|
131
131
|
"Do you want to display a panel on load?": "Mostrar um painel ao carregar?",
|
|
132
132
|
"Do you want to display caption menus?": "Mostrar menus de legendas?",
|
|
@@ -255,8 +255,8 @@
|
|
|
255
255
|
"No cache": "Sem cache",
|
|
256
256
|
"No licence has been set": "Não foi definida nenhuma licença",
|
|
257
257
|
"No results": "Sem resultados",
|
|
258
|
-
"no": "
|
|
259
|
-
"No.": "
|
|
258
|
+
"no": "não",
|
|
259
|
+
"No.": "Não.",
|
|
260
260
|
"None": "Nenhum",
|
|
261
261
|
"Number of desired classes (default 5)": "Número de classes pretendidas (predefinição 5)",
|
|
262
262
|
"On the bottom": "No fundo",
|
|
@@ -386,7 +386,7 @@
|
|
|
386
386
|
"width": "largura",
|
|
387
387
|
"Will be displayed in the bottom right corner of the map": "Será mostrado no fundo à direita do mapa",
|
|
388
388
|
"Will be permanently visible in the bottom left corner of the map": "Estará permanentemente visível no canto inferior esquerdo do mapa",
|
|
389
|
-
"Will be visible in the caption of the map": "Será visível
|
|
389
|
+
"Will be visible in the caption of the map": "Será visível na legenda do mapa",
|
|
390
390
|
"yes": "sim",
|
|
391
391
|
"Zoom in": "Aproximar",
|
|
392
392
|
"Zoom level for automatic zooms": "Nível de aproximação para aproximações automáticas",
|
|
@@ -431,55 +431,56 @@
|
|
|
431
431
|
"Filter data": "Dados de filtros",
|
|
432
432
|
"Search map features…": "Procurar elementos do mapa…",
|
|
433
433
|
"Reset all": "Repor tudo",
|
|
434
|
-
"Open browser": "
|
|
435
|
-
"Open caption": "
|
|
436
|
-
"Your map has been created with an anonymous account!": "
|
|
437
|
-
"Real-time collaboration": "
|
|
438
|
-
"Cannot parse data": "
|
|
439
|
-
"Start typing...": "
|
|
440
|
-
"No result": "
|
|
441
|
-
"Data browser": "
|
|
442
|
-
"When providing an URL, uMap can copy the remote data in a layer, or add this URL as remote source of the layer. In that case, data will always be fetched from that URL, and thus be up to date, but it will not be possible to edit it inside uMap.": "
|
|
443
|
-
"Overpass supported expressions": "
|
|
444
|
-
"key (eg. building)": "
|
|
445
|
-
"!key (eg. !name)": "!
|
|
446
|
-
"key=value (eg. building=yes)": "
|
|
447
|
-
"key!=value (eg. building!=yes)": "
|
|
448
|
-
"key~value (eg. name~Grisy)": "
|
|
449
|
-
"key=\"value|value2\" (eg. name=\"Paris|Berlin\")": "
|
|
450
|
-
"More info about Overpass syntax": "
|
|
451
|
-
"For more complex needs, see": "
|
|
452
|
-
"Choose data": "
|
|
453
|
-
"Import helpers:": "
|
|
454
|
-
"Choose the format": "
|
|
455
|
-
"Choose the layer": "
|
|
456
|
-
"Layer name": "
|
|
457
|
-
"Choose import mode": "
|
|
458
|
-
"Copy into the layer": "
|
|
459
|
-
"Link to the layer as remote data": "
|
|
460
|
-
"Condition": "
|
|
461
|
-
"key=value or key!=value": "
|
|
462
|
-
"Are you sure you want to delete this rule?": "
|
|
463
|
-
"empty rule": "
|
|
464
|
-
"Conditional style rules": "
|
|
465
|
-
"Add rule": "
|
|
466
|
-
"Browser: data": "
|
|
467
|
-
"Browser: layers": "
|
|
468
|
-
"Browser: filters": "
|
|
469
|
-
"Enable real-time collaboration": "
|
|
470
|
-
"✅ Copied!": "✅
|
|
471
|
-
"Choose a dataset": "
|
|
472
|
-
"Choose this dataset": "
|
|
473
|
-
"GeoDataMine: thematic data from OpenStreetMap": "GeoDataMine:
|
|
474
|
-
"Choose a theme": "
|
|
475
|
-
"Symplify all geometries to points": "
|
|
476
|
-
"Choose this data": "
|
|
477
|
-
"Search admin boundary": "
|
|
478
|
-
"Please choose a theme and a boundary first.": "
|
|
479
|
-
"Expression": "
|
|
480
|
-
"Geometry mode": "
|
|
481
|
-
"Only geometry centers": "
|
|
482
|
-
"Search area": "
|
|
483
|
-
"Type area name, or let empty to load data in current map view": "
|
|
484
|
-
"Please define an expression for the query first": "
|
|
434
|
+
"Open browser": "Abrir navegador",
|
|
435
|
+
"Open caption": "Abrir legenda",
|
|
436
|
+
"Your map has been created with an anonymous account!": "O seu mapa foi criado com uma conta anónima!",
|
|
437
|
+
"Real-time collaboration": "Colaboração em tempo real",
|
|
438
|
+
"Cannot parse data": "Não é possível analisar os dados",
|
|
439
|
+
"Start typing...": "Comece a escrever...",
|
|
440
|
+
"No result": "Nenhum resultado",
|
|
441
|
+
"Data browser": "Navegador de dados",
|
|
442
|
+
"When providing an URL, uMap can copy the remote data in a layer, or add this URL as remote source of the layer. In that case, data will always be fetched from that URL, and thus be up to date, but it will not be possible to edit it inside uMap.": "Ao fornecer um URL, o uMap pode copiar os dados remotos numa camada ou adicionar esse URL como fonte remota da camada. Nesse caso, os dados serão sempre obtidos a partir desse URL e, por conseguinte, estarão atualizados, mas não será possível editá-los no uMap.",
|
|
443
|
+
"Overpass supported expressions": "Expressões suportadas pelo Overpass",
|
|
444
|
+
"key (eg. building)": "chave (por exemplo: edifício)",
|
|
445
|
+
"!key (eg. !name)": "!chave (por exemplo: nome)",
|
|
446
|
+
"key=value (eg. building=yes)": "chave=valor (por exemplo: building=yes)",
|
|
447
|
+
"key!=value (eg. building!=yes)": "chave!=valor (por exemplo: building!=yes)",
|
|
448
|
+
"key~value (eg. name~Grisy)": "chave~valor (por exemplo: name~Grisy)",
|
|
449
|
+
"key=\"value|value2\" (eg. name=\"Paris|Berlin\")": "chave=\"valor|valor2\" (por exemplo: name=\"Paris|Berlim\")",
|
|
450
|
+
"More info about Overpass syntax": "Mais informações sobre a sintaxe de Overpass",
|
|
451
|
+
"For more complex needs, see": "Para necessidades mais complexas, ver",
|
|
452
|
+
"Choose data": "Escolher dados",
|
|
453
|
+
"Import helpers:": "Ajudantes de importação:",
|
|
454
|
+
"Choose the format": "Escolher o formato",
|
|
455
|
+
"Choose the layer": "Escolher a camada",
|
|
456
|
+
"Layer name": "Nome da camada",
|
|
457
|
+
"Choose import mode": "Escolher o modo de importação",
|
|
458
|
+
"Copy into the layer": "Copiar para a camada",
|
|
459
|
+
"Link to the layer as remote data": "Hiperligação à camada como dados remotos",
|
|
460
|
+
"Condition": "Condição",
|
|
461
|
+
"key=value or key!=value": "chave=valor ou chave!=valor",
|
|
462
|
+
"Are you sure you want to delete this rule?": "Tem a certeza de que pretende eliminar esta regra?",
|
|
463
|
+
"empty rule": "regra vazia",
|
|
464
|
+
"Conditional style rules": "Regras de estilo condicionais",
|
|
465
|
+
"Add rule": "Adicionar regra",
|
|
466
|
+
"Browser: data": "Navegador: dados",
|
|
467
|
+
"Browser: layers": "Navegador: camadas",
|
|
468
|
+
"Browser: filters": "Navegador: filtros",
|
|
469
|
+
"Enable real-time collaboration": "Ativar a colaboração em tempo real",
|
|
470
|
+
"✅ Copied!": "✅ Copiado!",
|
|
471
|
+
"Choose a dataset": "Escolher um conjunto de dados",
|
|
472
|
+
"Choose this dataset": "Escolher este conjunto de dados",
|
|
473
|
+
"GeoDataMine: thematic data from OpenStreetMap": "GeoDataMine: dados temáticos do OpenStreetMap",
|
|
474
|
+
"Choose a theme": "Escolher um tema",
|
|
475
|
+
"Symplify all geometries to points": "Simplificar todas as geometrias para pontos",
|
|
476
|
+
"Choose this data": "Selecionar estes dados",
|
|
477
|
+
"Search admin boundary": "Pesquisar limite administrativo",
|
|
478
|
+
"Please choose a theme and a boundary first.": "Escolha primeiro um tema e um limite.",
|
|
479
|
+
"Expression": "Expressão",
|
|
480
|
+
"Geometry mode": "Modo de geometria",
|
|
481
|
+
"Only geometry centers": "Apenas centros de geometria",
|
|
482
|
+
"Search area": "Pesquisar área",
|
|
483
|
+
"Type area name, or let empty to load data in current map view": "Introduza o nome da área ou deixe em branco para carregar os dados na vista de mapa atual",
|
|
484
|
+
"Please define an expression for the query first": "Defina primeiro uma expressão para a consulta",
|
|
485
|
+
"Data successfully imported!": "Dados importados com sucesso!"
|
|
485
486
|
}
|
umap/static/umap/map.css
CHANGED
|
@@ -678,7 +678,9 @@ ul.photon-autocomplete {
|
|
|
678
678
|
font-style: italic;
|
|
679
679
|
}
|
|
680
680
|
.umap-slideshow-toolbox {
|
|
681
|
-
|
|
681
|
+
position: absolute;
|
|
682
|
+
right: 0;
|
|
683
|
+
top: 0;
|
|
682
684
|
display: none;
|
|
683
685
|
}
|
|
684
686
|
.umap-slideshow-enabled .umap-slideshow-toolbox {
|
|
@@ -690,9 +692,9 @@ ul.photon-autocomplete {
|
|
|
690
692
|
font-size: 1.5em;
|
|
691
693
|
background-color: #464646;
|
|
692
694
|
color: #fff;
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
line-height:
|
|
695
|
+
width: calc(var(--footer-height) * 2);
|
|
696
|
+
height: var(--footer-height);
|
|
697
|
+
line-height: var(--footer-height);
|
|
696
698
|
vertical-align: middle;
|
|
697
699
|
text-align: center;
|
|
698
700
|
}
|
|
@@ -704,24 +706,24 @@ ul.photon-autocomplete {
|
|
|
704
706
|
}
|
|
705
707
|
.umap-slideshow-active .umap-slideshow-toolbox .play,
|
|
706
708
|
.umap-slideshow-toolbox .play {
|
|
707
|
-
width:
|
|
709
|
+
width: calc(var(--footer-height) * 3);
|
|
708
710
|
text-align: left;
|
|
709
711
|
padding-left: 20px;
|
|
710
712
|
}
|
|
711
713
|
.umap-slideshow-toolbox .play:after {
|
|
712
|
-
content: '
|
|
714
|
+
content: '⏯︎';
|
|
713
715
|
}
|
|
714
716
|
.umap-slideshow-active .umap-slideshow-toolbox .play:after {
|
|
715
|
-
content: '
|
|
717
|
+
content: '⏸︎';
|
|
716
718
|
}
|
|
717
719
|
.umap-slideshow-toolbox .stop:before {
|
|
718
|
-
content: '
|
|
720
|
+
content: '⏹';
|
|
719
721
|
}
|
|
720
722
|
.umap-slideshow-toolbox .next:before {
|
|
721
|
-
content: '
|
|
723
|
+
content: '⏵︎';
|
|
722
724
|
}
|
|
723
725
|
.umap-slideshow-toolbox .prev:before {
|
|
724
|
-
content: '
|
|
726
|
+
content: '⏴︎';
|
|
725
727
|
}
|
|
726
728
|
.umap-slideshow-toolbox .play div {
|
|
727
729
|
height: 20px;
|
|
@@ -1127,6 +1129,7 @@ a.umap-control-caption,
|
|
|
1127
1129
|
}
|
|
1128
1130
|
|
|
1129
1131
|
.umap-popup-footer {
|
|
1132
|
+
position: relative;
|
|
1130
1133
|
background-color: rgb(68, 68, 68);
|
|
1131
1134
|
color: white;
|
|
1132
1135
|
display: table;
|
|
@@ -1522,7 +1525,7 @@ span.popup-icon {
|
|
|
1522
1525
|
z-index: 1001;
|
|
1523
1526
|
}
|
|
1524
1527
|
.leaflet-popup-content {
|
|
1525
|
-
min-width:
|
|
1528
|
+
min-width: 200px;
|
|
1526
1529
|
line-height: inherit;
|
|
1527
1530
|
}
|
|
1528
1531
|
.leaflet-popup-content-wrapper, .leaflet-popup-tip {
|
|
@@ -1559,8 +1562,6 @@ span.popup-icon {
|
|
|
1559
1562
|
}
|
|
1560
1563
|
.umap-popup-container {
|
|
1561
1564
|
flex-grow: 1;
|
|
1562
|
-
word-break: break-word;
|
|
1563
|
-
white-space: pre-line;
|
|
1564
1565
|
margin-bottom: 10px;
|
|
1565
1566
|
}
|
|
1566
1567
|
.umap-popup-container ul {
|
|
@@ -11,14 +11,14 @@ global.JSDOM = JSDOM
|
|
|
11
11
|
describe('Utils', function () {
|
|
12
12
|
describe('#toHTML()', function () {
|
|
13
13
|
it('should handle title', function () {
|
|
14
|
-
assert.equal(Utils.toHTML('# A title'), '<
|
|
14
|
+
assert.equal(Utils.toHTML('# A title'), '<h4>A title</h4>')
|
|
15
15
|
})
|
|
16
16
|
it('should handle title followed by text', function () {
|
|
17
|
-
assert.equal(Utils.toHTML('# A title\nSome text.'), '<
|
|
17
|
+
assert.equal(Utils.toHTML('# A title\nSome text.'), '<h4>A title</h4>Some text.')
|
|
18
18
|
})
|
|
19
19
|
|
|
20
20
|
it('should handle title in the middle of the content', function () {
|
|
21
|
-
assert.equal(Utils.toHTML('A phrase\n## A title'), 'A phrase\n<
|
|
21
|
+
assert.equal(Utils.toHTML('A phrase\n## A title'), 'A phrase\n<h5>A title</h5>')
|
|
22
22
|
})
|
|
23
23
|
|
|
24
24
|
it('should handle hr', function () {
|
|
@@ -43,7 +43,7 @@ describe('Utils', function () {
|
|
|
43
43
|
it('should handle simple link in title', function () {
|
|
44
44
|
assert.equal(
|
|
45
45
|
Utils.toHTML('# http://osm.org'),
|
|
46
|
-
'<
|
|
46
|
+
'<h4><a href="http://osm.org" target="_blank">http://osm.org</a></h4>'
|
|
47
47
|
)
|
|
48
48
|
})
|
|
49
49
|
|
|
@@ -180,7 +180,7 @@ describe('Utils', function () {
|
|
|
180
180
|
it('title followed by bullet points', function () {
|
|
181
181
|
assert.equal(
|
|
182
182
|
Utils.toHTML('## Some title\n* First *point*\n* Second **point**\n* Last [[https://here.org|point]]'),
|
|
183
|
-
'<
|
|
183
|
+
'<h5>Some title</h5><ul><li>First <em>point</em></li><li>Second <strong>point</strong></li><li>Last <a href="https://here.org" target="_blank">point</a></li></ul>'
|
|
184
184
|
)
|
|
185
185
|
})
|
|
186
186
|
})
|
umap/static/umap/vars.css
CHANGED
|
@@ -29,12 +29,13 @@
|
|
|
29
29
|
--panel-width: 400px;
|
|
30
30
|
--header-height: 46px;
|
|
31
31
|
--current-header-height: 0px;
|
|
32
|
-
--footer-height:
|
|
32
|
+
--footer-height: 32px;
|
|
33
33
|
--current-footer-height: 0px;
|
|
34
34
|
--control-size: 36px;
|
|
35
35
|
--border-radius: 4px;
|
|
36
36
|
--box-padding: 20px;
|
|
37
37
|
--box-margin: 14px;
|
|
38
|
+
--text-margin: 7px;
|
|
38
39
|
}
|
|
39
40
|
.dark {
|
|
40
41
|
--background-color: var(--color-darkGray);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @license DOMPurify 3.1.
|
|
1
|
+
/*! @license DOMPurify 3.1.3 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.3/LICENSE */
|
|
2
2
|
|
|
3
3
|
const {
|
|
4
4
|
entries,
|
|
@@ -48,6 +48,7 @@ const stringTrim = unapply(String.prototype.trim);
|
|
|
48
48
|
const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
|
|
49
49
|
const regExpTest = unapply(RegExp.prototype.test);
|
|
50
50
|
const typeErrorCreate = unconstruct(TypeError);
|
|
51
|
+
const numberIsNaN = unapply(Number.isNaN);
|
|
51
52
|
|
|
52
53
|
/**
|
|
53
54
|
* Creates a new function that calls the given function with a specified thisArg and arguments.
|
|
@@ -196,7 +197,7 @@ const mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mgly
|
|
|
196
197
|
const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
|
|
197
198
|
const text = freeze(['#text']);
|
|
198
199
|
|
|
199
|
-
const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', '
|
|
200
|
+
const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns', 'slot']);
|
|
200
201
|
const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
|
|
201
202
|
const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
|
|
202
203
|
const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
|
|
@@ -300,7 +301,7 @@ function createDOMPurify() {
|
|
|
300
301
|
* Version label, exposed for easier checks
|
|
301
302
|
* if DOMPurify is up to date or not
|
|
302
303
|
*/
|
|
303
|
-
DOMPurify.version = '3.1.
|
|
304
|
+
DOMPurify.version = '3.1.3';
|
|
304
305
|
|
|
305
306
|
/**
|
|
306
307
|
* Array of elements that DOMPurify removed during sanitation.
|
|
@@ -533,6 +534,9 @@ function createDOMPurify() {
|
|
|
533
534
|
/* Keep a reference to config to pass to hooks */
|
|
534
535
|
let CONFIG = null;
|
|
535
536
|
|
|
537
|
+
/* Specify the maximum element nesting depth to prevent mXSS */
|
|
538
|
+
const MAX_NESTING_DEPTH = 255;
|
|
539
|
+
|
|
536
540
|
/* Ideally, do not touch anything below this line */
|
|
537
541
|
/* ______________________________________________ */
|
|
538
542
|
|
|
@@ -943,7 +947,11 @@ function createDOMPurify() {
|
|
|
943
947
|
* @return {Boolean} true if clobbered, false if safe
|
|
944
948
|
*/
|
|
945
949
|
const _isClobbered = function _isClobbered(elm) {
|
|
946
|
-
return elm instanceof HTMLFormElement && (
|
|
950
|
+
return elm instanceof HTMLFormElement && (
|
|
951
|
+
// eslint-disable-next-line unicorn/no-typeof-undefined
|
|
952
|
+
typeof elm.__depth !== 'undefined' && typeof elm.__depth !== 'number' ||
|
|
953
|
+
// eslint-disable-next-line unicorn/no-typeof-undefined
|
|
954
|
+
typeof elm.__removalCount !== 'undefined' && typeof elm.__removalCount !== 'number' || typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string' || typeof elm.insertBefore !== 'function' || typeof elm.hasChildNodes !== 'function');
|
|
947
955
|
};
|
|
948
956
|
|
|
949
957
|
/**
|
|
@@ -1094,7 +1102,7 @@ function createDOMPurify() {
|
|
|
1094
1102
|
// eslint-disable-next-line complexity
|
|
1095
1103
|
const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
|
|
1096
1104
|
/* Make sure attribute cannot clobber */
|
|
1097
|
-
if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
|
|
1105
|
+
if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement || value === '__depth' || value === '__removalCount')) {
|
|
1098
1106
|
return false;
|
|
1099
1107
|
}
|
|
1100
1108
|
|
|
@@ -1285,9 +1293,32 @@ function createDOMPurify() {
|
|
|
1285
1293
|
if (_sanitizeElements(shadowNode)) {
|
|
1286
1294
|
continue;
|
|
1287
1295
|
}
|
|
1296
|
+
const parentNode = getParentNode(shadowNode);
|
|
1297
|
+
|
|
1298
|
+
/* Set the nesting depth of an element */
|
|
1299
|
+
if (shadowNode.nodeType === NODE_TYPE.element) {
|
|
1300
|
+
if (parentNode && parentNode.__depth) {
|
|
1301
|
+
/*
|
|
1302
|
+
We want the depth of the node in the original tree, which can
|
|
1303
|
+
change when it's removed from its parent.
|
|
1304
|
+
*/
|
|
1305
|
+
shadowNode.__depth = (shadowNode.__removalCount || 0) + parentNode.__depth + 1;
|
|
1306
|
+
} else {
|
|
1307
|
+
shadowNode.__depth = 1;
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
/*
|
|
1312
|
+
* Remove an element if nested too deeply to avoid mXSS
|
|
1313
|
+
* or if the __depth might have been tampered with
|
|
1314
|
+
*/
|
|
1315
|
+
if (shadowNode.__depth >= MAX_NESTING_DEPTH || shadowNode.__depth < 0 || numberIsNaN(shadowNode.__depth)) {
|
|
1316
|
+
_forceRemove(shadowNode);
|
|
1317
|
+
}
|
|
1288
1318
|
|
|
1289
1319
|
/* Deep shadow DOM detected */
|
|
1290
1320
|
if (shadowNode.content instanceof DocumentFragment) {
|
|
1321
|
+
shadowNode.content.__depth = shadowNode.__depth;
|
|
1291
1322
|
_sanitizeShadowDOM(shadowNode.content);
|
|
1292
1323
|
}
|
|
1293
1324
|
|
|
@@ -1403,9 +1434,32 @@ function createDOMPurify() {
|
|
|
1403
1434
|
if (_sanitizeElements(currentNode)) {
|
|
1404
1435
|
continue;
|
|
1405
1436
|
}
|
|
1437
|
+
const parentNode = getParentNode(currentNode);
|
|
1438
|
+
|
|
1439
|
+
/* Set the nesting depth of an element */
|
|
1440
|
+
if (currentNode.nodeType === NODE_TYPE.element) {
|
|
1441
|
+
if (parentNode && parentNode.__depth) {
|
|
1442
|
+
/*
|
|
1443
|
+
We want the depth of the node in the original tree, which can
|
|
1444
|
+
change when it's removed from its parent.
|
|
1445
|
+
*/
|
|
1446
|
+
currentNode.__depth = (currentNode.__removalCount || 0) + parentNode.__depth + 1;
|
|
1447
|
+
} else {
|
|
1448
|
+
currentNode.__depth = 1;
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
/*
|
|
1453
|
+
* Remove an element if nested too deeply to avoid mXSS
|
|
1454
|
+
* or if the __depth might have been tampered with
|
|
1455
|
+
*/
|
|
1456
|
+
if (currentNode.__depth >= MAX_NESTING_DEPTH || currentNode.__depth < 0 || numberIsNaN(currentNode.__depth)) {
|
|
1457
|
+
_forceRemove(currentNode);
|
|
1458
|
+
}
|
|
1406
1459
|
|
|
1407
1460
|
/* Shadow DOM detected, sanitize it */
|
|
1408
1461
|
if (currentNode.content instanceof DocumentFragment) {
|
|
1462
|
+
currentNode.content.__depth = currentNode.__depth;
|
|
1409
1463
|
_sanitizeShadowDOM(currentNode.content);
|
|
1410
1464
|
}
|
|
1411
1465
|
|