umap-project 2.2.1__py3-none-any.whl → 2.3.0__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 (144) hide show
  1. umap/__init__.py +1 -1
  2. umap/static/umap/base.css +83 -44
  3. umap/static/umap/css/icon.css +6 -0
  4. umap/static/umap/css/panel.css +9 -4
  5. umap/static/umap/img/16.svg +2 -2
  6. umap/static/umap/img/source/16.svg +3 -3
  7. umap/static/umap/js/modules/browser.js +63 -22
  8. umap/static/umap/js/modules/facets.js +14 -39
  9. umap/static/umap/js/modules/orderable.js +1 -1
  10. umap/static/umap/js/modules/schema.js +4 -4
  11. umap/static/umap/js/modules/urls.js +1 -1
  12. umap/static/umap/js/modules/utils.js +9 -1
  13. umap/static/umap/js/umap.controls.js +15 -11
  14. umap/static/umap/js/umap.core.js +17 -15
  15. umap/static/umap/js/umap.features.js +8 -2
  16. umap/static/umap/js/umap.forms.js +92 -33
  17. umap/static/umap/js/umap.js +19 -24
  18. umap/static/umap/js/umap.layer.js +3 -6
  19. umap/static/umap/locale/am_ET.js +11 -12
  20. umap/static/umap/locale/am_ET.json +11 -12
  21. umap/static/umap/locale/ar.js +11 -12
  22. umap/static/umap/locale/ar.json +11 -12
  23. umap/static/umap/locale/ast.js +11 -12
  24. umap/static/umap/locale/ast.json +11 -12
  25. umap/static/umap/locale/bg.js +11 -12
  26. umap/static/umap/locale/bg.json +11 -12
  27. umap/static/umap/locale/br.js +11 -12
  28. umap/static/umap/locale/br.json +11 -12
  29. umap/static/umap/locale/ca.js +11 -12
  30. umap/static/umap/locale/ca.json +11 -12
  31. umap/static/umap/locale/cs_CZ.js +11 -12
  32. umap/static/umap/locale/cs_CZ.json +11 -12
  33. umap/static/umap/locale/da.js +11 -12
  34. umap/static/umap/locale/da.json +11 -12
  35. umap/static/umap/locale/de.js +11 -12
  36. umap/static/umap/locale/de.json +11 -12
  37. umap/static/umap/locale/el.js +11 -12
  38. umap/static/umap/locale/el.json +11 -12
  39. umap/static/umap/locale/en.js +11 -12
  40. umap/static/umap/locale/en.json +11 -12
  41. umap/static/umap/locale/en_US.json +11 -12
  42. umap/static/umap/locale/es.js +11 -12
  43. umap/static/umap/locale/es.json +11 -12
  44. umap/static/umap/locale/et.js +11 -12
  45. umap/static/umap/locale/et.json +11 -12
  46. umap/static/umap/locale/eu.js +27 -16
  47. umap/static/umap/locale/eu.json +27 -16
  48. umap/static/umap/locale/fa_IR.js +11 -12
  49. umap/static/umap/locale/fa_IR.json +11 -12
  50. umap/static/umap/locale/fi.js +11 -12
  51. umap/static/umap/locale/fi.json +11 -12
  52. umap/static/umap/locale/fr.js +11 -12
  53. umap/static/umap/locale/fr.json +11 -12
  54. umap/static/umap/locale/gl.js +11 -12
  55. umap/static/umap/locale/gl.json +11 -12
  56. umap/static/umap/locale/he.js +11 -12
  57. umap/static/umap/locale/he.json +11 -12
  58. umap/static/umap/locale/hr.js +11 -12
  59. umap/static/umap/locale/hr.json +11 -12
  60. umap/static/umap/locale/hu.js +29 -30
  61. umap/static/umap/locale/hu.json +29 -30
  62. umap/static/umap/locale/id.js +11 -12
  63. umap/static/umap/locale/id.json +11 -12
  64. umap/static/umap/locale/is.js +11 -12
  65. umap/static/umap/locale/is.json +11 -12
  66. umap/static/umap/locale/it.js +11 -12
  67. umap/static/umap/locale/it.json +11 -12
  68. umap/static/umap/locale/ja.js +11 -12
  69. umap/static/umap/locale/ja.json +11 -12
  70. umap/static/umap/locale/ko.js +11 -12
  71. umap/static/umap/locale/ko.json +11 -12
  72. umap/static/umap/locale/lt.js +11 -12
  73. umap/static/umap/locale/lt.json +11 -12
  74. umap/static/umap/locale/ms.js +20 -21
  75. umap/static/umap/locale/ms.json +20 -21
  76. umap/static/umap/locale/nl.js +11 -12
  77. umap/static/umap/locale/nl.json +11 -12
  78. umap/static/umap/locale/no.js +11 -12
  79. umap/static/umap/locale/no.json +11 -12
  80. umap/static/umap/locale/pl.js +11 -12
  81. umap/static/umap/locale/pl.json +11 -12
  82. umap/static/umap/locale/pl_PL.json +11 -12
  83. umap/static/umap/locale/pt.js +11 -12
  84. umap/static/umap/locale/pt.json +11 -12
  85. umap/static/umap/locale/pt_BR.js +11 -12
  86. umap/static/umap/locale/pt_BR.json +11 -12
  87. umap/static/umap/locale/pt_PT.js +11 -12
  88. umap/static/umap/locale/pt_PT.json +11 -12
  89. umap/static/umap/locale/ro.js +11 -12
  90. umap/static/umap/locale/ro.json +11 -12
  91. umap/static/umap/locale/ru.js +11 -12
  92. umap/static/umap/locale/ru.json +11 -12
  93. umap/static/umap/locale/si.js +240 -227
  94. umap/static/umap/locale/si.json +240 -227
  95. umap/static/umap/locale/sk_SK.js +11 -12
  96. umap/static/umap/locale/sk_SK.json +11 -12
  97. umap/static/umap/locale/sl.js +11 -12
  98. umap/static/umap/locale/sl.json +11 -12
  99. umap/static/umap/locale/sr.js +11 -12
  100. umap/static/umap/locale/sr.json +11 -12
  101. umap/static/umap/locale/sv.js +11 -12
  102. umap/static/umap/locale/sv.json +11 -12
  103. umap/static/umap/locale/th_TH.js +11 -12
  104. umap/static/umap/locale/th_TH.json +11 -12
  105. umap/static/umap/locale/tr.js +11 -12
  106. umap/static/umap/locale/tr.json +11 -12
  107. umap/static/umap/locale/uk_UA.js +11 -12
  108. umap/static/umap/locale/uk_UA.json +11 -12
  109. umap/static/umap/locale/vi.js +11 -12
  110. umap/static/umap/locale/vi.json +11 -12
  111. umap/static/umap/locale/vi_VN.json +11 -12
  112. umap/static/umap/locale/zh.js +11 -12
  113. umap/static/umap/locale/zh.json +11 -12
  114. umap/static/umap/locale/zh_CN.json +11 -12
  115. umap/static/umap/locale/zh_TW.Big5.json +11 -12
  116. umap/static/umap/locale/zh_TW.js +11 -12
  117. umap/static/umap/locale/zh_TW.json +11 -12
  118. umap/static/umap/map.css +17 -2
  119. umap/static/umap/unittests/utils.js +7 -0
  120. umap/static/umap/vars.css +10 -0
  121. umap/static/umap/vendors/dompurify/purify.es.js +54 -5
  122. umap/static/umap/vendors/dompurify/purify.es.mjs.map +1 -0
  123. umap/tests/integration/conftest.py +5 -4
  124. umap/tests/integration/test_browser.py +7 -0
  125. umap/tests/integration/test_choropleth.py +1 -1
  126. umap/tests/integration/test_draw_polygon.py +6 -0
  127. umap/tests/integration/test_draw_polyline.py +6 -0
  128. umap/tests/integration/test_edit_datalayer.py +5 -5
  129. umap/tests/integration/test_edit_map.py +4 -4
  130. umap/tests/integration/test_edit_marker.py +6 -6
  131. umap/tests/integration/test_edit_polygon.py +6 -6
  132. umap/tests/integration/test_facets_browser.py +82 -13
  133. {umap_project-2.2.1.dist-info → umap_project-2.3.0.dist-info}/METADATA +8 -7
  134. {umap_project-2.2.1.dist-info → umap_project-2.3.0.dist-info}/RECORD +137 -143
  135. {umap_project-2.2.1.dist-info → umap_project-2.3.0.dist-info}/WHEEL +1 -1
  136. umap/.DS_Store +0 -0
  137. umap/static/.DS_Store +0 -0
  138. umap/static/umap/.DS_Store +0 -0
  139. umap/static/umap/favicons/.DS_Store +0 -0
  140. umap/static/umap/fonts/.DS_Store +0 -0
  141. umap/tests/.DS_Store +0 -0
  142. umap/tests/integration/.DS_Store +0 -0
  143. {umap_project-2.2.1.dist-info → umap_project-2.3.0.dist-info}/entry_points.txt +0 -0
  144. {umap_project-2.2.1.dist-info → umap_project-2.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -83,7 +83,6 @@ const locale = {
83
83
  "color": "色彩",
84
84
  "Comma separated list of numbers, including min and max values.": "用逗號分隔數字,包括最小與最大值。",
85
85
  "Comma separated list of properties to use for sorting features. To reverse the sort, put a minus sign (-) before. Eg. mykey,-otherkey.": "用逗號分隔屬性清單來排序圖徵。要保存排序,在槊面加上減號 (-1),例如 mykey,-otherkey。",
86
- "Comma separated list of properties to use when filtering features": "以逗號分開列出篩選時要使用的屬性",
87
86
  "Comma, tab or semi-colon separated values. SRS WGS84 is implied. Only Point geometries are imported. The import will look at the column headers for any mention of «lat» and «lon» at the begining of the header, case insensitive. All other column are imported as properties.": "使用逗號、定位鍵或是分號分隔的地理數據。預設座標系為 SRS WGS84。只會匯入地理座標點。匯入時抓取 «lat» 與 «lon» 開頭的欄位資料,不分大小寫。其他欄位則歸入屬性資料。",
88
87
  "Congratulations, your map has been created!": "恭喜您的地圖已經新增完成",
89
88
  "Continue line": "連續線段",
@@ -96,7 +95,6 @@ const locale = {
96
95
  "Custom background": "自訂背景",
97
96
  "Custom overlay": "客制套疊",
98
97
  "dash array": "虛線排列",
99
- "Data browser": "資料檢視器",
100
98
  "Data is browsable": "資料是可檢視的",
101
99
  "Datalayers": "資料圖層",
102
100
  "Default interaction options": "預設互動選項",
@@ -165,16 +163,12 @@ const locale = {
165
163
  "Exit Fullscreen": "結束全螢幕模式",
166
164
  "expanded": "展開",
167
165
  "Extract shape to separate feature": "由外形分離出圖徵",
168
- "Facet keys": "方面鍵",
169
- "Facet search": "方面搜尋",
170
166
  "Feature identifier key": "Feature identifier key",
171
167
  "Feature properties": "圖徵屬性",
172
168
  "Fetch data each time map view changes.": "每次地圖檢視改變時截取資料。",
173
169
  "fill color": "填入色彩",
174
170
  "fill opacity": "填入不透明度",
175
171
  "fill": "填入",
176
- "Filter keys": "篩選鍵",
177
- "Filter": "篩選器",
178
172
  "Fit all data": "檢視所有資料",
179
173
  "Format": "格式",
180
174
  "From zoom": "由縮放大小",
@@ -267,7 +261,6 @@ const locale = {
267
261
  "NM": "NM",
268
262
  "No cache": "沒有快取内容",
269
263
  "No licence has been set": "尚未設定授權條例",
270
- "No results for these facets": "各方面沒有結果",
271
264
  "No results": "沒有結果",
272
265
  "no": "否",
273
266
  "No.": "無。",
@@ -332,7 +325,6 @@ const locale = {
332
325
  "See layers": "See layers",
333
326
  "See full screen": "觀看全螢幕",
334
327
  "See on OpenStreetMap": "在開放街圖檢視",
335
- "Select data": "Select data",
336
328
  "Send me the link": "寄送連結給我",
337
329
  "Set it to false to hide this layer from the slideshow, the data browser, the popup navigation…": "設定為假時,在幻燈片時、資料檢視器和彈出式導航中可將此圖層隱藏...",
338
330
  "settings": "設定",
@@ -434,9 +426,7 @@ const locale = {
434
426
  "Edit map details": "Edit map details",
435
427
  "Back to browser": "Back to browser",
436
428
  "Toggle size": "Toggle size",
437
- "Layers": "Layers",
438
429
  "Display the caption control": "Display the caption control",
439
- "Comma separated list of properties to use for facet search (eg.: mykey,otherkey). To control label, add it after a | (eg.: mykey|My Key,otherkey|Other Key). To control input field type, add it after another | (eg.: mykey|My Key|checkbox,otherkey|Other Key|datetime). Allowed values for the input field type are checkbox (default), radio, number, date and datetime.": "Comma separated list of properties to use for facet search (eg.: mykey,otherkey). To control label, add it after a | (eg.: mykey|My Key,otherkey|Other Key). To control input field type, add it after another | (eg.: mykey|My Key|checkbox,otherkey|Other Key|datetime). Allowed values for the input field type are checkbox (default), radio, number, date and datetime.",
440
430
  "<empty value>": "<empty value>",
441
431
  "Min": "Min",
442
432
  "Max": "Max",
@@ -446,8 +436,17 @@ const locale = {
446
436
  "Edit in OpenStreetMap": "Edit in OpenStreetMap",
447
437
  "Cannot determine latitude and longitude columns.": "Cannot determine latitude and longitude columns.",
448
438
  "Back to layers": "Back to layers",
449
- "Data": "Data",
450
- "Filters": "Filters"
439
+ "Filters": "Filters",
440
+ "Comma separated list of properties to use when filtering features by text input": "Comma separated list of properties to use when filtering features by text input",
441
+ "Comma separated list of properties to use for filters (eg.: mykey,otherkey). To control label, add it after a | (eg.: mykey|My Key,otherkey|Other Key). To control input field type, add it after another | (eg.: mykey|My Key|checkbox,otherkey|Other Key|datetime). Allowed values for the input field type are checkbox (default), radio, number, date and datetime.": "Comma separated list of properties to use for filters (eg.: mykey,otherkey). To control label, add it after a | (eg.: mykey|My Key,otherkey|Other Key). To control input field type, add it after another | (eg.: mykey|My Key|checkbox,otherkey|Other Key|datetime). Allowed values for the input field type are checkbox (default), radio, number, date and datetime.",
442
+ "Search keys": "Search keys",
443
+ "Filters keys": "Filters keys",
444
+ "Filter data": "Filter data",
445
+ "Search map features…": "Search map features…",
446
+ "Reset all": "Reset all",
447
+ "Browser in data mode": "Browser in data mode",
448
+ "Browser in layers mode": "Browser in layers mode",
449
+ "Browser in filters mode": "Browser in filters mode"
451
450
  }
452
451
  L.registerLocale("zh_TW", locale)
453
452
  L.setLocale("zh_TW")
@@ -83,7 +83,6 @@
83
83
  "color": "色彩",
84
84
  "Comma separated list of numbers, including min and max values.": "用逗號分隔數字,包括最小與最大值。",
85
85
  "Comma separated list of properties to use for sorting features. To reverse the sort, put a minus sign (-) before. Eg. mykey,-otherkey.": "用逗號分隔屬性清單來排序圖徵。要保存排序,在槊面加上減號 (-1),例如 mykey,-otherkey。",
86
- "Comma separated list of properties to use when filtering features": "以逗號分開列出篩選時要使用的屬性",
87
86
  "Comma, tab or semi-colon separated values. SRS WGS84 is implied. Only Point geometries are imported. The import will look at the column headers for any mention of «lat» and «lon» at the begining of the header, case insensitive. All other column are imported as properties.": "使用逗號、定位鍵或是分號分隔的地理數據。預設座標系為 SRS WGS84。只會匯入地理座標點。匯入時抓取 «lat» 與 «lon» 開頭的欄位資料,不分大小寫。其他欄位則歸入屬性資料。",
88
87
  "Congratulations, your map has been created!": "恭喜您的地圖已經新增完成",
89
88
  "Continue line": "連續線段",
@@ -96,7 +95,6 @@
96
95
  "Custom background": "自訂背景",
97
96
  "Custom overlay": "客制套疊",
98
97
  "dash array": "虛線排列",
99
- "Data browser": "資料檢視器",
100
98
  "Data is browsable": "資料是可檢視的",
101
99
  "Datalayers": "資料圖層",
102
100
  "Default interaction options": "預設互動選項",
@@ -165,16 +163,12 @@
165
163
  "Exit Fullscreen": "結束全螢幕模式",
166
164
  "expanded": "展開",
167
165
  "Extract shape to separate feature": "由外形分離出圖徵",
168
- "Facet keys": "方面鍵",
169
- "Facet search": "方面搜尋",
170
166
  "Feature identifier key": "Feature identifier key",
171
167
  "Feature properties": "圖徵屬性",
172
168
  "Fetch data each time map view changes.": "每次地圖檢視改變時截取資料。",
173
169
  "fill color": "填入色彩",
174
170
  "fill opacity": "填入不透明度",
175
171
  "fill": "填入",
176
- "Filter keys": "篩選鍵",
177
- "Filter": "篩選器",
178
172
  "Fit all data": "檢視所有資料",
179
173
  "Format": "格式",
180
174
  "From zoom": "由縮放大小",
@@ -267,7 +261,6 @@
267
261
  "NM": "NM",
268
262
  "No cache": "沒有快取内容",
269
263
  "No licence has been set": "尚未設定授權條例",
270
- "No results for these facets": "各方面沒有結果",
271
264
  "No results": "沒有結果",
272
265
  "no": "否",
273
266
  "No.": "無。",
@@ -332,7 +325,6 @@
332
325
  "See layers": "See layers",
333
326
  "See full screen": "觀看全螢幕",
334
327
  "See on OpenStreetMap": "在開放街圖檢視",
335
- "Select data": "Select data",
336
328
  "Send me the link": "寄送連結給我",
337
329
  "Set it to false to hide this layer from the slideshow, the data browser, the popup navigation…": "設定為假時,在幻燈片時、資料檢視器和彈出式導航中可將此圖層隱藏...",
338
330
  "settings": "設定",
@@ -434,9 +426,7 @@
434
426
  "Edit map details": "Edit map details",
435
427
  "Back to browser": "Back to browser",
436
428
  "Toggle size": "Toggle size",
437
- "Layers": "Layers",
438
429
  "Display the caption control": "Display the caption control",
439
- "Comma separated list of properties to use for facet search (eg.: mykey,otherkey). To control label, add it after a | (eg.: mykey|My Key,otherkey|Other Key). To control input field type, add it after another | (eg.: mykey|My Key|checkbox,otherkey|Other Key|datetime). Allowed values for the input field type are checkbox (default), radio, number, date and datetime.": "Comma separated list of properties to use for facet search (eg.: mykey,otherkey). To control label, add it after a | (eg.: mykey|My Key,otherkey|Other Key). To control input field type, add it after another | (eg.: mykey|My Key|checkbox,otherkey|Other Key|datetime). Allowed values for the input field type are checkbox (default), radio, number, date and datetime.",
440
430
  "<empty value>": "<empty value>",
441
431
  "Min": "Min",
442
432
  "Max": "Max",
@@ -446,6 +436,15 @@
446
436
  "Edit in OpenStreetMap": "Edit in OpenStreetMap",
447
437
  "Cannot determine latitude and longitude columns.": "Cannot determine latitude and longitude columns.",
448
438
  "Back to layers": "Back to layers",
449
- "Data": "Data",
450
- "Filters": "Filters"
439
+ "Filters": "Filters",
440
+ "Comma separated list of properties to use when filtering features by text input": "Comma separated list of properties to use when filtering features by text input",
441
+ "Comma separated list of properties to use for filters (eg.: mykey,otherkey). To control label, add it after a | (eg.: mykey|My Key,otherkey|Other Key). To control input field type, add it after another | (eg.: mykey|My Key|checkbox,otherkey|Other Key|datetime). Allowed values for the input field type are checkbox (default), radio, number, date and datetime.": "Comma separated list of properties to use for filters (eg.: mykey,otherkey). To control label, add it after a | (eg.: mykey|My Key,otherkey|Other Key). To control input field type, add it after another | (eg.: mykey|My Key|checkbox,otherkey|Other Key|datetime). Allowed values for the input field type are checkbox (default), radio, number, date and datetime.",
442
+ "Search keys": "Search keys",
443
+ "Filters keys": "Filters keys",
444
+ "Filter data": "Filter data",
445
+ "Search map features…": "Search map features…",
446
+ "Reset all": "Reset all",
447
+ "Browser in data mode": "Browser in data mode",
448
+ "Browser in layers mode": "Browser in layers mode",
449
+ "Browser in filters mode": "Browser in filters mode"
451
450
  }
umap/static/umap/map.css CHANGED
@@ -888,10 +888,10 @@ a.umap-control-caption,
888
888
  .umap-browser .datalayer i {
889
889
  cursor: pointer;
890
890
  }
891
- .umap-browser ul {
891
+ .umap-browser .datalayer ul {
892
892
  display: none;
893
893
  }
894
- .show-list ul {
894
+ .umap-browser .show-list ul {
895
895
  display: block;
896
896
  }
897
897
 
@@ -982,6 +982,21 @@ a.umap-control-caption,
982
982
  .umap-browser .show-list .datalayer-toggle-list {
983
983
  background-position: -145px -45px;
984
984
  }
985
+ .umap-browser .filters summary {
986
+ background: none;
987
+ border: 1px solid var(--color-lightGray);
988
+ width: fit-content;
989
+ padding: 0 10px;
990
+ margin-bottom: var(--block-margin);
991
+ }
992
+ .umap-browser .filters summary {
993
+ list-style: none;
994
+ display: inline-block;
995
+ }
996
+ .umap-browser details[open].filters summary {
997
+ margin-bottom: -1px;
998
+ border-bottom: 1px solid var(--background-color);
999
+ }
985
1000
  .datalayer-name {
986
1001
  cursor: pointer;
987
1002
  }
@@ -185,6 +185,13 @@ describe('Utils', function () {
185
185
  assert.equal(Utils.escapeHTML('<a href="geo:1,2"></a>'), '<a href="geo:1,2"></a>')
186
186
  })
187
187
 
188
+ it('should not escape dir and title attributes', function () {
189
+ assert.equal(
190
+ Utils.escapeHTML('<a title="Title" dir="rtl"></a>'),
191
+ '<a dir="rtl" title="Title"></a>'
192
+ )
193
+ })
194
+
188
195
  it('should not fail with int value', function () {
189
196
  assert.equal(Utils.escapeHTML(25), '25')
190
197
  })
umap/static/umap/vars.css CHANGED
@@ -4,6 +4,13 @@
4
4
  --color-darkBlue: #263B58;
5
5
  --color-lightGray: #ddd;
6
6
  --color-darkGray: #323737;
7
+ --color-light: white;
8
+ --color-limeGreen: #b9f5d2;
9
+ --color-brightCyan: #46ece6;
10
+ --color-lightCyan: #d4fbf9;
11
+
12
+ --background-color: var(--color-light);
13
+ --color-accent: var(--color-brightCyan);
7
14
 
8
15
  /* Buttons. */
9
16
  --button-primary-background: var(--color-waterMint);
@@ -20,3 +27,6 @@
20
27
  --footer-height: 46px;
21
28
  --control-size: 36px;
22
29
  }
30
+ .dark {
31
+ --background-color: var(--color-darkGray);
32
+ }
@@ -1,4 +1,4 @@
1
- /*! @license DOMPurify 3.1.0 | (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.0/LICENSE */
1
+ /*! @license DOMPurify 3.1.2 | (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.2/LICENSE */
2
2
 
3
3
  const {
4
4
  entries,
@@ -282,7 +282,7 @@ function createDOMPurify() {
282
282
  * Version label, exposed for easier checks
283
283
  * if DOMPurify is up to date or not
284
284
  */
285
- DOMPurify.version = '3.1.0';
285
+ DOMPurify.version = '3.1.2';
286
286
 
287
287
  /**
288
288
  * Array of elements that DOMPurify removed during sanitation.
@@ -515,6 +515,9 @@ function createDOMPurify() {
515
515
  /* Keep a reference to config to pass to hooks */
516
516
  let CONFIG = null;
517
517
 
518
+ /* Specify the maximum element nesting depth to prevent mXSS */
519
+ const MAX_NESTING_DEPTH = 255;
520
+
518
521
  /* Ideally, do not touch anything below this line */
519
522
  /* ______________________________________________ */
520
523
 
@@ -701,7 +704,7 @@ function createDOMPurify() {
701
704
  CONFIG = cfg;
702
705
  };
703
706
  const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
704
- const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'desc', 'title', 'annotation-xml']);
707
+ const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'annotation-xml']);
705
708
 
706
709
  // Certain elements are allowed in both SVG and HTML
707
710
  // namespace. We need to specify them explicitly
@@ -925,7 +928,11 @@ function createDOMPurify() {
925
928
  * @return {Boolean} true if clobbered, false if safe
926
929
  */
927
930
  const _isClobbered = function _isClobbered(elm) {
928
- 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');
931
+ return elm instanceof HTMLFormElement && (
932
+ // eslint-disable-next-line unicorn/no-typeof-undefined
933
+ typeof elm.__depth !== 'undefined' && typeof elm.__depth !== 'number' ||
934
+ // eslint-disable-next-line unicorn/no-typeof-undefined
935
+ 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');
929
936
  };
930
937
 
931
938
  /**
@@ -1023,7 +1030,9 @@ function createDOMPurify() {
1023
1030
  if (childNodes && parentNode) {
1024
1031
  const childCount = childNodes.length;
1025
1032
  for (let i = childCount - 1; i >= 0; --i) {
1026
- parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
1033
+ const childClone = cloneNode(childNodes[i], true);
1034
+ childClone.__removalCount = (currentNode.__removalCount || 0) + 1;
1035
+ parentNode.insertBefore(childClone, getNextSibling(currentNode));
1027
1036
  }
1028
1037
  }
1029
1038
  }
@@ -1255,9 +1264,29 @@ function createDOMPurify() {
1255
1264
  if (_sanitizeElements(shadowNode)) {
1256
1265
  continue;
1257
1266
  }
1267
+ const parentNode = getParentNode(shadowNode);
1268
+
1269
+ /* Set the nesting depth of an element */
1270
+ if (shadowNode.nodeType === 1) {
1271
+ if (parentNode && parentNode.__depth) {
1272
+ /*
1273
+ We want the depth of the node in the original tree, which can
1274
+ change when it's removed from its parent.
1275
+ */
1276
+ shadowNode.__depth = (shadowNode.__removalCount || 0) + parentNode.__depth + 1;
1277
+ } else {
1278
+ shadowNode.__depth = 1;
1279
+ }
1280
+ }
1281
+
1282
+ /* Remove an element if nested too deeply to avoid mXSS */
1283
+ if (shadowNode.__depth >= MAX_NESTING_DEPTH) {
1284
+ _forceRemove(shadowNode);
1285
+ }
1258
1286
 
1259
1287
  /* Deep shadow DOM detected */
1260
1288
  if (shadowNode.content instanceof DocumentFragment) {
1289
+ shadowNode.content.__depth = shadowNode.__depth;
1261
1290
  _sanitizeShadowDOM(shadowNode.content);
1262
1291
  }
1263
1292
 
@@ -1373,9 +1402,29 @@ function createDOMPurify() {
1373
1402
  if (_sanitizeElements(currentNode)) {
1374
1403
  continue;
1375
1404
  }
1405
+ const parentNode = getParentNode(currentNode);
1406
+
1407
+ /* Set the nesting depth of an element */
1408
+ if (currentNode.nodeType === 1) {
1409
+ if (parentNode && parentNode.__depth) {
1410
+ /*
1411
+ We want the depth of the node in the original tree, which can
1412
+ change when it's removed from its parent.
1413
+ */
1414
+ currentNode.__depth = (currentNode.__removalCount || 0) + parentNode.__depth + 1;
1415
+ } else {
1416
+ currentNode.__depth = 1;
1417
+ }
1418
+ }
1419
+
1420
+ /* Remove an element if nested too deeply to avoid mXSS */
1421
+ if (currentNode.__depth >= MAX_NESTING_DEPTH) {
1422
+ _forceRemove(currentNode);
1423
+ }
1376
1424
 
1377
1425
  /* Shadow DOM detected, sanitize it */
1378
1426
  if (currentNode.content instanceof DocumentFragment) {
1427
+ currentNode.content.__depth = currentNode.__depth;
1379
1428
  _sanitizeShadowDOM(currentNode.content);
1380
1429
  }
1381
1430