umap-project 2.2.2__py3-none-any.whl → 2.3.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 (156) hide show
  1. umap/__init__.py +1 -1
  2. umap/locale/pl/LC_MESSAGES/django.mo +0 -0
  3. umap/locale/pl/LC_MESSAGES/django.po +83 -78
  4. umap/locale/pt/LC_MESSAGES/django.mo +0 -0
  5. umap/locale/pt/LC_MESSAGES/django.po +129 -123
  6. umap/static/umap/base.css +85 -44
  7. umap/static/umap/css/icon.css +6 -0
  8. umap/static/umap/css/panel.css +9 -4
  9. umap/static/umap/img/16.svg +2 -2
  10. umap/static/umap/img/source/16.svg +3 -3
  11. umap/static/umap/js/modules/browser.js +58 -24
  12. umap/static/umap/js/modules/caption.js +118 -0
  13. umap/static/umap/js/modules/facets.js +14 -39
  14. umap/static/umap/js/modules/global.js +2 -0
  15. umap/static/umap/js/modules/orderable.js +1 -1
  16. umap/static/umap/js/modules/panel.js +13 -7
  17. umap/static/umap/js/modules/schema.js +4 -4
  18. umap/static/umap/js/modules/urls.js +1 -1
  19. umap/static/umap/js/modules/utils.js +9 -1
  20. umap/static/umap/js/umap.controls.js +40 -110
  21. umap/static/umap/js/umap.core.js +19 -20
  22. umap/static/umap/js/umap.features.js +8 -2
  23. umap/static/umap/js/umap.forms.js +95 -34
  24. umap/static/umap/js/umap.js +47 -54
  25. umap/static/umap/js/umap.layer.js +5 -8
  26. umap/static/umap/js/umap.popup.js +1 -0
  27. umap/static/umap/locale/am_ET.js +11 -12
  28. umap/static/umap/locale/am_ET.json +11 -12
  29. umap/static/umap/locale/ar.js +11 -12
  30. umap/static/umap/locale/ar.json +11 -12
  31. umap/static/umap/locale/ast.js +11 -12
  32. umap/static/umap/locale/ast.json +11 -12
  33. umap/static/umap/locale/bg.js +11 -12
  34. umap/static/umap/locale/bg.json +11 -12
  35. umap/static/umap/locale/br.js +11 -12
  36. umap/static/umap/locale/br.json +11 -12
  37. umap/static/umap/locale/ca.js +11 -12
  38. umap/static/umap/locale/ca.json +11 -12
  39. umap/static/umap/locale/cs_CZ.js +11 -12
  40. umap/static/umap/locale/cs_CZ.json +11 -12
  41. umap/static/umap/locale/da.js +11 -12
  42. umap/static/umap/locale/da.json +11 -12
  43. umap/static/umap/locale/de.js +11 -12
  44. umap/static/umap/locale/de.json +11 -12
  45. umap/static/umap/locale/el.js +11 -12
  46. umap/static/umap/locale/el.json +11 -12
  47. umap/static/umap/locale/en.js +11 -12
  48. umap/static/umap/locale/en.json +11 -12
  49. umap/static/umap/locale/en_US.json +11 -12
  50. umap/static/umap/locale/es.js +11 -12
  51. umap/static/umap/locale/es.json +11 -12
  52. umap/static/umap/locale/et.js +11 -12
  53. umap/static/umap/locale/et.json +11 -12
  54. umap/static/umap/locale/eu.js +27 -16
  55. umap/static/umap/locale/eu.json +27 -16
  56. umap/static/umap/locale/fa_IR.js +11 -12
  57. umap/static/umap/locale/fa_IR.json +11 -12
  58. umap/static/umap/locale/fi.js +11 -12
  59. umap/static/umap/locale/fi.json +11 -12
  60. umap/static/umap/locale/fr.js +11 -12
  61. umap/static/umap/locale/fr.json +11 -12
  62. umap/static/umap/locale/gl.js +11 -12
  63. umap/static/umap/locale/gl.json +11 -12
  64. umap/static/umap/locale/he.js +11 -12
  65. umap/static/umap/locale/he.json +11 -12
  66. umap/static/umap/locale/hr.js +11 -12
  67. umap/static/umap/locale/hr.json +11 -12
  68. umap/static/umap/locale/hu.js +29 -30
  69. umap/static/umap/locale/hu.json +29 -30
  70. umap/static/umap/locale/id.js +11 -12
  71. umap/static/umap/locale/id.json +11 -12
  72. umap/static/umap/locale/is.js +11 -12
  73. umap/static/umap/locale/is.json +11 -12
  74. umap/static/umap/locale/it.js +11 -12
  75. umap/static/umap/locale/it.json +11 -12
  76. umap/static/umap/locale/ja.js +11 -12
  77. umap/static/umap/locale/ja.json +11 -12
  78. umap/static/umap/locale/ko.js +11 -12
  79. umap/static/umap/locale/ko.json +11 -12
  80. umap/static/umap/locale/lt.js +11 -12
  81. umap/static/umap/locale/lt.json +11 -12
  82. umap/static/umap/locale/ms.js +20 -21
  83. umap/static/umap/locale/ms.json +20 -21
  84. umap/static/umap/locale/nl.js +11 -12
  85. umap/static/umap/locale/nl.json +11 -12
  86. umap/static/umap/locale/no.js +11 -12
  87. umap/static/umap/locale/no.json +11 -12
  88. umap/static/umap/locale/pl.js +11 -12
  89. umap/static/umap/locale/pl.json +11 -12
  90. umap/static/umap/locale/pl_PL.json +11 -12
  91. umap/static/umap/locale/pt.js +11 -12
  92. umap/static/umap/locale/pt.json +11 -12
  93. umap/static/umap/locale/pt_BR.js +11 -12
  94. umap/static/umap/locale/pt_BR.json +11 -12
  95. umap/static/umap/locale/pt_PT.js +11 -12
  96. umap/static/umap/locale/pt_PT.json +11 -12
  97. umap/static/umap/locale/ro.js +11 -12
  98. umap/static/umap/locale/ro.json +11 -12
  99. umap/static/umap/locale/ru.js +11 -12
  100. umap/static/umap/locale/ru.json +11 -12
  101. umap/static/umap/locale/si.js +240 -227
  102. umap/static/umap/locale/si.json +240 -227
  103. umap/static/umap/locale/sk_SK.js +11 -12
  104. umap/static/umap/locale/sk_SK.json +11 -12
  105. umap/static/umap/locale/sl.js +11 -12
  106. umap/static/umap/locale/sl.json +11 -12
  107. umap/static/umap/locale/sr.js +11 -12
  108. umap/static/umap/locale/sr.json +11 -12
  109. umap/static/umap/locale/sv.js +11 -12
  110. umap/static/umap/locale/sv.json +11 -12
  111. umap/static/umap/locale/th_TH.js +11 -12
  112. umap/static/umap/locale/th_TH.json +11 -12
  113. umap/static/umap/locale/tr.js +11 -12
  114. umap/static/umap/locale/tr.json +11 -12
  115. umap/static/umap/locale/uk_UA.js +11 -12
  116. umap/static/umap/locale/uk_UA.json +11 -12
  117. umap/static/umap/locale/vi.js +11 -12
  118. umap/static/umap/locale/vi.json +11 -12
  119. umap/static/umap/locale/vi_VN.json +11 -12
  120. umap/static/umap/locale/zh.js +11 -12
  121. umap/static/umap/locale/zh.json +11 -12
  122. umap/static/umap/locale/zh_CN.json +11 -12
  123. umap/static/umap/locale/zh_TW.Big5.json +11 -12
  124. umap/static/umap/locale/zh_TW.js +11 -12
  125. umap/static/umap/locale/zh_TW.json +11 -12
  126. umap/static/umap/map.css +17 -2
  127. umap/static/umap/unittests/utils.js +7 -0
  128. umap/static/umap/vars.css +10 -0
  129. umap/static/umap/vendors/dompurify/purify.es.js +96 -12
  130. umap/static/umap/vendors/dompurify/purify.es.mjs.map +1 -1
  131. umap/tests/base.py +1 -0
  132. umap/tests/integration/conftest.py +5 -4
  133. umap/tests/integration/test_browser.py +11 -2
  134. umap/tests/integration/test_caption.py +27 -0
  135. umap/tests/integration/test_choropleth.py +1 -1
  136. umap/tests/integration/test_draw_polygon.py +6 -0
  137. umap/tests/integration/test_draw_polyline.py +6 -0
  138. umap/tests/integration/test_edit_datalayer.py +34 -5
  139. umap/tests/integration/test_edit_map.py +4 -4
  140. umap/tests/integration/test_edit_marker.py +6 -6
  141. umap/tests/integration/test_edit_polygon.py +6 -6
  142. umap/tests/integration/test_facets_browser.py +85 -13
  143. umap/tests/integration/test_map.py +0 -15
  144. umap/tests/integration/test_view_marker.py +17 -0
  145. {umap_project-2.2.2.dist-info → umap_project-2.3.1.dist-info}/METADATA +9 -8
  146. {umap_project-2.2.2.dist-info → umap_project-2.3.1.dist-info}/RECORD +149 -154
  147. {umap_project-2.2.2.dist-info → umap_project-2.3.1.dist-info}/WHEEL +1 -1
  148. umap/.DS_Store +0 -0
  149. umap/static/.DS_Store +0 -0
  150. umap/static/umap/.DS_Store +0 -0
  151. umap/static/umap/favicons/.DS_Store +0 -0
  152. umap/static/umap/fonts/.DS_Store +0 -0
  153. umap/tests/.DS_Store +0 -0
  154. umap/tests/integration/.DS_Store +0 -0
  155. {umap_project-2.2.2.dist-info → umap_project-2.3.1.dist-info}/entry_points.txt +0 -0
  156. {umap_project-2.2.2.dist-info → umap_project-2.3.1.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.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.
@@ -231,6 +232,24 @@ var EXPRESSIONS = /*#__PURE__*/Object.freeze({
231
232
  CUSTOM_ELEMENT: CUSTOM_ELEMENT
232
233
  });
233
234
 
235
+ // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
236
+ const NODE_TYPE = {
237
+ element: 1,
238
+ attribute: 2,
239
+ text: 3,
240
+ cdataSection: 4,
241
+ entityReference: 5,
242
+ // Deprecated
243
+ entityNode: 6,
244
+ // Deprecated
245
+ progressingInstruction: 7,
246
+ comment: 8,
247
+ document: 9,
248
+ documentType: 10,
249
+ documentFragment: 11,
250
+ notation: 12 // Deprecated
251
+ };
252
+
234
253
  const getGlobal = function getGlobal() {
235
254
  return typeof window === 'undefined' ? null : window;
236
255
  };
@@ -282,14 +301,14 @@ function createDOMPurify() {
282
301
  * Version label, exposed for easier checks
283
302
  * if DOMPurify is up to date or not
284
303
  */
285
- DOMPurify.version = '3.1.0';
304
+ DOMPurify.version = '3.1.3';
286
305
 
287
306
  /**
288
307
  * Array of elements that DOMPurify removed during sanitation.
289
308
  * Empty if nothing was removed.
290
309
  */
291
310
  DOMPurify.removed = [];
292
- if (!window || !window.document || window.document.nodeType !== 9) {
311
+ if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document) {
293
312
  // Not running in a browser, provide a factory function
294
313
  // so that you can pass your own Window
295
314
  DOMPurify.isSupported = false;
@@ -515,6 +534,9 @@ function createDOMPurify() {
515
534
  /* Keep a reference to config to pass to hooks */
516
535
  let CONFIG = null;
517
536
 
537
+ /* Specify the maximum element nesting depth to prevent mXSS */
538
+ const MAX_NESTING_DEPTH = 255;
539
+
518
540
  /* Ideally, do not touch anything below this line */
519
541
  /* ______________________________________________ */
520
542
 
@@ -701,7 +723,7 @@ function createDOMPurify() {
701
723
  CONFIG = cfg;
702
724
  };
703
725
  const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
704
- const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'desc', 'title', 'annotation-xml']);
726
+ const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'annotation-xml']);
705
727
 
706
728
  // Certain elements are allowed in both SVG and HTML
707
729
  // namespace. We need to specify them explicitly
@@ -925,7 +947,11 @@ function createDOMPurify() {
925
947
  * @return {Boolean} true if clobbered, false if safe
926
948
  */
927
949
  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');
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');
929
955
  };
930
956
 
931
957
  /**
@@ -993,13 +1019,13 @@ function createDOMPurify() {
993
1019
  }
994
1020
 
995
1021
  /* Remove any ocurrence of processing instructions */
996
- if (currentNode.nodeType === 7) {
1022
+ if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {
997
1023
  _forceRemove(currentNode);
998
1024
  return true;
999
1025
  }
1000
1026
 
1001
1027
  /* Remove any kind of possibly harmful comments */
1002
- if (SAFE_FOR_XML && currentNode.nodeType === 8 && regExpTest(/<[/\w]/g, currentNode.data)) {
1028
+ if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(/<[/\w]/g, currentNode.data)) {
1003
1029
  _forceRemove(currentNode);
1004
1030
  return true;
1005
1031
  }
@@ -1023,7 +1049,9 @@ function createDOMPurify() {
1023
1049
  if (childNodes && parentNode) {
1024
1050
  const childCount = childNodes.length;
1025
1051
  for (let i = childCount - 1; i >= 0; --i) {
1026
- parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
1052
+ const childClone = cloneNode(childNodes[i], true);
1053
+ childClone.__removalCount = (currentNode.__removalCount || 0) + 1;
1054
+ parentNode.insertBefore(childClone, getNextSibling(currentNode));
1027
1055
  }
1028
1056
  }
1029
1057
  }
@@ -1044,7 +1072,7 @@ function createDOMPurify() {
1044
1072
  }
1045
1073
 
1046
1074
  /* Sanitize element content to be template-safe */
1047
- if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
1075
+ if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
1048
1076
  /* Get the element's text content */
1049
1077
  content = currentNode.textContent;
1050
1078
  arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
@@ -1074,7 +1102,7 @@ function createDOMPurify() {
1074
1102
  // eslint-disable-next-line complexity
1075
1103
  const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
1076
1104
  /* Make sure attribute cannot clobber */
1077
- 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')) {
1078
1106
  return false;
1079
1107
  }
1080
1108
 
@@ -1178,6 +1206,12 @@ function createDOMPurify() {
1178
1206
  continue;
1179
1207
  }
1180
1208
 
1209
+ /* Work around a security issue with comments inside attributes */
1210
+ if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title)/i, value)) {
1211
+ _removeAttribute(name, currentNode);
1212
+ continue;
1213
+ }
1214
+
1181
1215
  /* Sanitize attribute content to be template-safe */
1182
1216
  if (SAFE_FOR_TEMPLATES) {
1183
1217
  arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
@@ -1228,7 +1262,11 @@ function createDOMPurify() {
1228
1262
  /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
1229
1263
  currentNode.setAttribute(name, value);
1230
1264
  }
1231
- arrayPop(DOMPurify.removed);
1265
+ if (_isClobbered(currentNode)) {
1266
+ _forceRemove(currentNode);
1267
+ } else {
1268
+ arrayPop(DOMPurify.removed);
1269
+ }
1232
1270
  } catch (_) {}
1233
1271
  }
1234
1272
 
@@ -1255,9 +1293,32 @@ function createDOMPurify() {
1255
1293
  if (_sanitizeElements(shadowNode)) {
1256
1294
  continue;
1257
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
+ }
1258
1318
 
1259
1319
  /* Deep shadow DOM detected */
1260
1320
  if (shadowNode.content instanceof DocumentFragment) {
1321
+ shadowNode.content.__depth = shadowNode.__depth;
1261
1322
  _sanitizeShadowDOM(shadowNode.content);
1262
1323
  }
1263
1324
 
@@ -1333,7 +1394,7 @@ function createDOMPurify() {
1333
1394
  elements being stripped by the parser */
1334
1395
  body = _initDocument('<!---->');
1335
1396
  importedNode = body.ownerDocument.importNode(dirty, true);
1336
- if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {
1397
+ if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === 'BODY') {
1337
1398
  /* Node is already a body, use as is */
1338
1399
  body = importedNode;
1339
1400
  } else if (importedNode.nodeName === 'HTML') {
@@ -1373,9 +1434,32 @@ function createDOMPurify() {
1373
1434
  if (_sanitizeElements(currentNode)) {
1374
1435
  continue;
1375
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
+ }
1376
1459
 
1377
1460
  /* Shadow DOM detected, sanitize it */
1378
1461
  if (currentNode.content instanceof DocumentFragment) {
1462
+ currentNode.content.__depth = currentNode.__depth;
1379
1463
  _sanitizeShadowDOM(currentNode.content);
1380
1464
  }
1381
1465