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.

Files changed (46) hide show
  1. umap/__init__.py +1 -1
  2. umap/locale/en/LC_MESSAGES/django.po +11 -11
  3. umap/locale/pt/LC_MESSAGES/django.mo +0 -0
  4. umap/locale/pt/LC_MESSAGES/django.po +87 -37
  5. umap/static/umap/base.css +19 -5
  6. umap/static/umap/img/16-white.svg +1 -3
  7. umap/static/umap/img/source/16-white.svg +2 -4
  8. umap/static/umap/js/modules/browser.js +5 -5
  9. umap/static/umap/js/modules/caption.js +1 -1
  10. umap/static/umap/js/modules/utils.js +3 -3
  11. umap/static/umap/js/umap.features.js +11 -3
  12. umap/static/umap/js/umap.js +47 -48
  13. umap/static/umap/js/umap.layer.js +11 -1
  14. umap/static/umap/js/umap.popup.js +1 -1
  15. umap/static/umap/locale/en.js +2 -1
  16. umap/static/umap/locale/en.json +2 -1
  17. umap/static/umap/locale/es.js +9 -8
  18. umap/static/umap/locale/es.json +9 -8
  19. umap/static/umap/locale/fr.js +2 -1
  20. umap/static/umap/locale/fr.json +2 -1
  21. umap/static/umap/locale/pt.js +61 -60
  22. umap/static/umap/locale/pt.json +61 -60
  23. umap/static/umap/map.css +14 -13
  24. umap/static/umap/unittests/utils.js +5 -5
  25. umap/static/umap/vars.css +2 -1
  26. umap/static/umap/vendors/dompurify/purify.es.js +59 -5
  27. umap/static/umap/vendors/dompurify/purify.es.mjs.map +1 -1
  28. umap/static/umap/vendors/formbuilder/Leaflet.FormBuilder.js +2 -2
  29. umap/tests/integration/test_browser.py +76 -3
  30. umap/tests/integration/test_edit_polygon.py +11 -0
  31. umap/tests/integration/test_map.py +29 -0
  32. umap/tests/integration/test_view_marker.py +2 -2
  33. {umap_project-2.4.0b2.dist-info → umap_project-2.4.1.dist-info}/METADATA +2 -2
  34. {umap_project-2.4.0b2.dist-info → umap_project-2.4.1.dist-info}/RECORD +37 -46
  35. {umap_project-2.4.0b2.dist-info → umap_project-2.4.1.dist-info}/WHEEL +1 -1
  36. umap/.DS_Store +0 -0
  37. umap/static/.DS_Store +0 -0
  38. umap/static/umap/.DS_Store +0 -0
  39. umap/static/umap/favicons/.DS_Store +0 -0
  40. umap/static/umap/fonts/.DS_Store +0 -0
  41. umap/static/umap/img/.DS_Store +0 -0
  42. umap/static/umap/img/source/.DS_Store +0 -0
  43. umap/tests/.DS_Store +0 -0
  44. umap/tests/integration/.DS_Store +0 -0
  45. {umap_project-2.4.0b2.dist-info → umap_project-2.4.1.dist-info}/entry_points.txt +0 -0
  46. {umap_project-2.4.0b2.dist-info → umap_project-2.4.1.dist-info}/licenses/LICENSE +0 -0
@@ -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 da imagem",
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": "Cabeçalho",
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 medição",
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": "Apresentar o botão de estrela do mapa",
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 cabeçalho?",
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": "no",
259
- "No.": "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 no cabeçalho do mapa",
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": "Open browser",
435
- "Open caption": "Open caption",
436
- "Your map has been created with an anonymous account!": "Your map has been created with an anonymous account!",
437
- "Real-time collaboration": "Real-time collaboration",
438
- "Cannot parse data": "Cannot parse data",
439
- "Start typing...": "Start typing...",
440
- "No result": "No result",
441
- "Data browser": "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.": "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": "Overpass supported expressions",
444
- "key (eg. building)": "key (eg. building)",
445
- "!key (eg. !name)": "!key (eg. !name)",
446
- "key=value (eg. building=yes)": "key=value (eg. building=yes)",
447
- "key!=value (eg. building!=yes)": "key!=value (eg. building!=yes)",
448
- "key~value (eg. name~Grisy)": "key~value (eg. name~Grisy)",
449
- "key=\"value|value2\" (eg. name=\"Paris|Berlin\")": "key=\"value|value2\" (eg. name=\"Paris|Berlin\")",
450
- "More info about Overpass syntax": "More info about Overpass syntax",
451
- "For more complex needs, see": "For more complex needs, see",
452
- "Choose data": "Choose data",
453
- "Import helpers:": "Import helpers:",
454
- "Choose the format": "Choose the format",
455
- "Choose the layer": "Choose the layer",
456
- "Layer name": "Layer name",
457
- "Choose import mode": "Choose import mode",
458
- "Copy into the layer": "Copy into the layer",
459
- "Link to the layer as remote data": "Link to the layer as remote data",
460
- "Condition": "Condition",
461
- "key=value or key!=value": "key=value or key!=value",
462
- "Are you sure you want to delete this rule?": "Are you sure you want to delete this rule?",
463
- "empty rule": "empty rule",
464
- "Conditional style rules": "Conditional style rules",
465
- "Add rule": "Add rule",
466
- "Browser: data": "Browser: data",
467
- "Browser: layers": "Browser: layers",
468
- "Browser: filters": "Browser: filters",
469
- "Enable real-time collaboration": "Enable real-time collaboration",
470
- "✅ Copied!": "✅ Copied!",
471
- "Choose a dataset": "Choose a dataset",
472
- "Choose this dataset": "Choose this dataset",
473
- "GeoDataMine: thematic data from OpenStreetMap": "GeoDataMine: thematic data from OpenStreetMap",
474
- "Choose a theme": "Choose a theme",
475
- "Symplify all geometries to points": "Symplify all geometries to points",
476
- "Choose this data": "Choose this data",
477
- "Search admin boundary": "Search admin boundary",
478
- "Please choose a theme and a boundary first.": "Please choose a theme and a boundary first.",
479
- "Expression": "Expression",
480
- "Geometry mode": "Geometry mode",
481
- "Only geometry centers": "Only geometry centers",
482
- "Search area": "Search area",
483
- "Type area name, or let empty to load data in current map view": "Type area name, or let empty to load data in current map view",
484
- "Please define an expression for the query first": "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
- float: right;
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
- height: 46px;
694
- width: 70px;
695
- line-height: 46px;
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: 100px;
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: 100px;
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'), '<h3>A title</h3>')
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.'), '<h3>A title</h3>Some 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<h4>A title</h4>')
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
- '<h3><a href="http://osm.org" target="_blank">http://osm.org</a></h3>'
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
- '<h4>Some title</h4><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>'
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: 28px;
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.5 | (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.5/LICENSE */
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', 'popover', 'popovertarget', 'popovertargetaction', '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
+ 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.5';
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 && (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');
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