@luomus/laji-form 14.3.6

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.
Files changed (302) hide show
  1. package/CHANGELOG.md +215 -0
  2. package/LICENSE +21 -0
  3. package/README.md +180 -0
  4. package/cypress/fixtures/example.json +5 -0
  5. closes suggestion list (failed).png +0 -0
  6. is marked as suggested (failed).png +0 -0
  7. package/dist/images/finnish-flag.png +0 -0
  8. package/dist/images/handled.png +0 -0
  9. package/dist/images/heard.png +0 -0
  10. package/dist/images/indirect.png +0 -0
  11. package/dist/images/media.png +0 -0
  12. package/dist/images/seen.png +0 -0
  13. package/dist/images/specimen.png +0 -0
  14. package/dist/laji-form.js +2 -0
  15. package/dist/laji-form.js.LICENSE.txt +92 -0
  16. package/dist/styles.css +3771 -0
  17. package/lib/ApiClient.d.ts +46 -0
  18. package/lib/ApiClient.js +93 -0
  19. package/lib/Context.d.ts +8 -0
  20. package/lib/Context.js +18 -0
  21. package/lib/ReactContext.d.ts +7 -0
  22. package/lib/ReactContext.js +5 -0
  23. package/lib/components/BaseComponent.d.ts +9 -0
  24. package/lib/components/BaseComponent.js +29 -0
  25. package/lib/components/LajiForm.d.ts +221 -0
  26. package/lib/components/LajiForm.js +614 -0
  27. package/lib/components/VirtualSchemaField.d.ts +42 -0
  28. package/lib/components/VirtualSchemaField.js +74 -0
  29. package/lib/components/components.d.ts +119 -0
  30. package/lib/components/components.js +606 -0
  31. package/lib/components/fields/AnnotationField.d.ts +34 -0
  32. package/lib/components/fields/AnnotationField.js +242 -0
  33. package/lib/components/fields/AnyToBooleanField.d.ts +18 -0
  34. package/lib/components/fields/AnyToBooleanField.js +20 -0
  35. package/lib/components/fields/ArrayBulkField.d.ts +23 -0
  36. package/lib/components/fields/ArrayBulkField.js +82 -0
  37. package/lib/components/fields/ArrayCombinerField.d.ts +36 -0
  38. package/lib/components/fields/ArrayCombinerField.js +138 -0
  39. package/lib/components/fields/ArrayField.d.ts +39 -0
  40. package/lib/components/fields/ArrayField.js +148 -0
  41. package/lib/components/fields/AudioArrayField.d.ts +22 -0
  42. package/lib/components/fields/AudioArrayField.js +100 -0
  43. package/lib/components/fields/AutoArrayField.d.ts +24 -0
  44. package/lib/components/fields/AutoArrayField.js +56 -0
  45. package/lib/components/fields/AutosuggestField.d.ts +69 -0
  46. package/lib/components/fields/AutosuggestField.js +299 -0
  47. package/lib/components/fields/CombinedValueDisplayField.d.ts +41 -0
  48. package/lib/components/fields/CombinedValueDisplayField.js +100 -0
  49. package/lib/components/fields/ConditionalOnChangeField.d.ts +42 -0
  50. package/lib/components/fields/ConditionalOnChangeField.js +107 -0
  51. package/lib/components/fields/ConditionalUiSchemaField.d.ts +123 -0
  52. package/lib/components/fields/ConditionalUiSchemaField.js +143 -0
  53. package/lib/components/fields/ContextInjectionField.d.ts +24 -0
  54. package/lib/components/fields/ContextInjectionField.js +68 -0
  55. package/lib/components/fields/DataLeakerField.d.ts +40 -0
  56. package/lib/components/fields/DataLeakerField.js +68 -0
  57. package/lib/components/fields/DefaultValueArrayField.d.ts +34 -0
  58. package/lib/components/fields/DefaultValueArrayField.js +59 -0
  59. package/lib/components/fields/DependentBooleanField.d.ts +38 -0
  60. package/lib/components/fields/DependentBooleanField.js +87 -0
  61. package/lib/components/fields/DependentDisableField.d.ts +35 -0
  62. package/lib/components/fields/DependentDisableField.js +71 -0
  63. package/lib/components/fields/EnumRangeArrayField.d.ts +27 -0
  64. package/lib/components/fields/EnumRangeArrayField.js +115 -0
  65. package/lib/components/fields/ExtraLabelRowField.d.ts +38 -0
  66. package/lib/components/fields/ExtraLabelRowField.js +100 -0
  67. package/lib/components/fields/FakePropertyField.d.ts +18 -0
  68. package/lib/components/fields/FakePropertyField.js +48 -0
  69. package/lib/components/fields/FilterArrayField.d.ts +73 -0
  70. package/lib/components/fields/FilterArrayField.js +121 -0
  71. package/lib/components/fields/FlatField.d.ts +29 -0
  72. package/lib/components/fields/FlatField.js +171 -0
  73. package/lib/components/fields/GeocoderField.d.ts +47 -0
  74. package/lib/components/fields/GeocoderField.js +372 -0
  75. package/lib/components/fields/GridLayoutField.d.ts +18 -0
  76. package/lib/components/fields/GridLayoutField.js +32 -0
  77. package/lib/components/fields/HiddenField.d.ts +10 -0
  78. package/lib/components/fields/HiddenField.js +11 -0
  79. package/lib/components/fields/ImageArrayField.d.ts +153 -0
  80. package/lib/components/fields/ImageArrayField.js +696 -0
  81. package/lib/components/fields/ImageDisplayField.d.ts +18 -0
  82. package/lib/components/fields/ImageDisplayField.js +44 -0
  83. package/lib/components/fields/InitiallyHiddenField.d.ts +21 -0
  84. package/lib/components/fields/InitiallyHiddenField.js +58 -0
  85. package/lib/components/fields/InjectDefaultValueField.d.ts +37 -0
  86. package/lib/components/fields/InjectDefaultValueField.js +68 -0
  87. package/lib/components/fields/InjectField.d.ts +46 -0
  88. package/lib/components/fields/InjectField.js +88 -0
  89. package/lib/components/fields/InputWithDefaultValueButtonField.d.ts +25 -0
  90. package/lib/components/fields/InputWithDefaultValueButtonField.js +61 -0
  91. package/lib/components/fields/LocalityField.d.ts +22 -0
  92. package/lib/components/fields/LocalityField.js +94 -0
  93. package/lib/components/fields/LocationChooserField.d.ts +27 -0
  94. package/lib/components/fields/LocationChooserField.js +440 -0
  95. package/lib/components/fields/MapArrayField.d.ts +78 -0
  96. package/lib/components/fields/MapArrayField.js +1783 -0
  97. package/lib/components/fields/MapField.d.ts +48 -0
  98. package/lib/components/fields/MapField.js +434 -0
  99. package/lib/components/fields/MultiAnyToBooleanField.d.ts +25 -0
  100. package/lib/components/fields/MultiAnyToBooleanField.js +100 -0
  101. package/lib/components/fields/MultiArrayField.d.ts +53 -0
  102. package/lib/components/fields/MultiArrayField.js +224 -0
  103. package/lib/components/fields/MultiLanguageField.d.ts +13 -0
  104. package/lib/components/fields/MultiLanguageField.js +52 -0
  105. package/lib/components/fields/MultiTagArrayField.d.ts +36 -0
  106. package/lib/components/fields/MultiTagArrayField.js +142 -0
  107. package/lib/components/fields/NamedPlaceChooserField.d.ts +29 -0
  108. package/lib/components/fields/NamedPlaceChooserField.js +380 -0
  109. package/lib/components/fields/NamedPlaceSaverField.d.ts +29 -0
  110. package/lib/components/fields/NamedPlaceSaverField.js +237 -0
  111. package/lib/components/fields/NestField.d.ts +148 -0
  112. package/lib/components/fields/NestField.js +289 -0
  113. package/lib/components/fields/ObjectField.d.ts +2 -0
  114. package/lib/components/fields/ObjectField.js +119 -0
  115. package/lib/components/fields/PrefillingArrayField.d.ts +22 -0
  116. package/lib/components/fields/PrefillingArrayField.js +65 -0
  117. package/lib/components/fields/SchemaField.d.ts +7 -0
  118. package/lib/components/fields/SchemaField.js +109 -0
  119. package/lib/components/fields/ScopeField.d.ts +85 -0
  120. package/lib/components/fields/ScopeField.js +521 -0
  121. package/lib/components/fields/SectionArrayField.d.ts +38 -0
  122. package/lib/components/fields/SectionArrayField.js +614 -0
  123. package/lib/components/fields/SelectTreeField.d.ts +39 -0
  124. package/lib/components/fields/SelectTreeField.js +143 -0
  125. package/lib/components/fields/SingleActiveArrayField.d.ts +49 -0
  126. package/lib/components/fields/SingleActiveArrayField.js +974 -0
  127. package/lib/components/fields/SingleItemArrayField.d.ts +15 -0
  128. package/lib/components/fields/SingleItemArrayField.js +60 -0
  129. package/lib/components/fields/SortArrayField.d.ts +73 -0
  130. package/lib/components/fields/SortArrayField.js +351 -0
  131. package/lib/components/fields/SplitField.d.ts +28 -0
  132. package/lib/components/fields/SplitField.js +65 -0
  133. package/lib/components/fields/StringToArrayField.d.ts +24 -0
  134. package/lib/components/fields/StringToArrayField.js +48 -0
  135. package/lib/components/fields/SumField.d.ts +35 -0
  136. package/lib/components/fields/SumField.js +83 -0
  137. package/lib/components/fields/TableField.d.ts +18 -0
  138. package/lib/components/fields/TableField.js +136 -0
  139. package/lib/components/fields/TagArrayField.d.ts +38 -0
  140. package/lib/components/fields/TagArrayField.js +128 -0
  141. package/lib/components/fields/ToggleAdditionalArrayFieldsField.d.ts +26 -0
  142. package/lib/components/fields/ToggleAdditionalArrayFieldsField.js +81 -0
  143. package/lib/components/fields/UiFieldApplierField.d.ts +30 -0
  144. package/lib/components/fields/UiFieldApplierField.js +106 -0
  145. package/lib/components/fields/UiFieldMapperArrayField.d.ts +42 -0
  146. package/lib/components/fields/UiFieldMapperArrayField.js +121 -0
  147. package/lib/components/fields/UnitCountShorthandField.d.ts +22 -0
  148. package/lib/components/fields/UnitCountShorthandField.js +149 -0
  149. package/lib/components/fields/UnitListShorthandArrayField.d.ts +26 -0
  150. package/lib/components/fields/UnitListShorthandArrayField.js +108 -0
  151. package/lib/components/fields/UnitShorthandField.d.ts +32 -0
  152. package/lib/components/fields/UnitShorthandField.js +220 -0
  153. package/lib/components/templates/ArrayFieldTemplate.d.ts +85 -0
  154. package/lib/components/templates/ArrayFieldTemplate.js +416 -0
  155. package/lib/components/templates/BaseInputTemplate.d.ts +11 -0
  156. package/lib/components/templates/BaseInputTemplate.js +80 -0
  157. package/lib/components/templates/DescriptionField.d.ts +1 -0
  158. package/lib/components/templates/DescriptionField.js +37 -0
  159. package/lib/components/templates/ErrorListTemplate.d.ts +9 -0
  160. package/lib/components/templates/ErrorListTemplate.js +95 -0
  161. package/lib/components/templates/FieldTemplate.d.ts +6 -0
  162. package/lib/components/templates/FieldTemplate.js +112 -0
  163. package/lib/components/templates/ObjectFieldTemplate.d.ts +7 -0
  164. package/lib/components/templates/ObjectFieldTemplate.js +66 -0
  165. package/lib/components/templates/TitleField.d.ts +9 -0
  166. package/lib/components/templates/TitleField.js +51 -0
  167. package/lib/components/widgets/AnyToBooleanWidget.d.ts +20 -0
  168. package/lib/components/widgets/AnyToBooleanWidget.js +49 -0
  169. package/lib/components/widgets/AutosuggestWidget.d.ts +66 -0
  170. package/lib/components/widgets/AutosuggestWidget.js +1127 -0
  171. package/lib/components/widgets/CheckboxWidget.d.ts +37 -0
  172. package/lib/components/widgets/CheckboxWidget.js +139 -0
  173. package/lib/components/widgets/DateTimeWidget.d.ts +62 -0
  174. package/lib/components/widgets/DateTimeWidget.js +251 -0
  175. package/lib/components/widgets/DateWidget.d.ts +23 -0
  176. package/lib/components/widgets/DateWidget.js +41 -0
  177. package/lib/components/widgets/HiddenWidget.d.ts +15 -0
  178. package/lib/components/widgets/HiddenWidget.js +19 -0
  179. package/lib/components/widgets/ImageSelectWidget.d.ts +14 -0
  180. package/lib/components/widgets/ImageSelectWidget.js +57 -0
  181. package/lib/components/widgets/InformalTaxonGroupChooserWidget.d.ts +43 -0
  182. package/lib/components/widgets/InformalTaxonGroupChooserWidget.js +237 -0
  183. package/lib/components/widgets/InputGroupWidget.d.ts +21 -0
  184. package/lib/components/widgets/InputGroupWidget.js +36 -0
  185. package/lib/components/widgets/InputWithDefaultValueButtonWidget.d.ts +21 -0
  186. package/lib/components/widgets/InputWithDefaultValueButtonWidget.js +47 -0
  187. package/lib/components/widgets/NumberWidget.d.ts +13 -0
  188. package/lib/components/widgets/NumberWidget.js +21 -0
  189. package/lib/components/widgets/PlainTextWidget.d.ts +12 -0
  190. package/lib/components/widgets/PlainTextWidget.js +24 -0
  191. package/lib/components/widgets/SelectWidget.d.ts +52 -0
  192. package/lib/components/widgets/SelectWidget.js +158 -0
  193. package/lib/components/widgets/SeparatedDateTimeWidget.d.ts +19 -0
  194. package/lib/components/widgets/SeparatedDateTimeWidget.js +59 -0
  195. package/lib/components/widgets/TaxonImageWidget.d.ts +13 -0
  196. package/lib/components/widgets/TaxonImageWidget.js +30 -0
  197. package/lib/components/widgets/TextSelectWidget.d.ts +25 -0
  198. package/lib/components/widgets/TextSelectWidget.js +94 -0
  199. package/lib/components/widgets/TextareaWidget.d.ts +32 -0
  200. package/lib/components/widgets/TextareaWidget.js +87 -0
  201. package/lib/components/widgets/TimeWidget.d.ts +11 -0
  202. package/lib/components/widgets/TimeWidget.js +19 -0
  203. package/lib/components/widgets/URLWidget.d.ts +14 -0
  204. package/lib/components/widgets/URLWidget.js +12 -0
  205. package/lib/components/widgets/UpperCaseWidget.d.ts +13 -0
  206. package/lib/components/widgets/UpperCaseWidget.js +21 -0
  207. package/lib/index.d.ts +20 -0
  208. package/lib/index.js +50 -0
  209. package/lib/services/blocker-service.d.ts +11 -0
  210. package/lib/services/blocker-service.js +55 -0
  211. package/lib/services/custom-event-service.d.ts +17 -0
  212. package/lib/services/custom-event-service.js +35 -0
  213. package/lib/services/dom-id-service.d.ts +8 -0
  214. package/lib/services/dom-id-service.js +30 -0
  215. package/lib/services/focus-service.d.ts +13 -0
  216. package/lib/services/focus-service.js +60 -0
  217. package/lib/services/id-service.d.ts +22 -0
  218. package/lib/services/id-service.js +130 -0
  219. package/lib/services/key-handler-service.d.ts +56 -0
  220. package/lib/services/key-handler-service.js +184 -0
  221. package/lib/services/root-instance-service.d.ts +25 -0
  222. package/lib/services/root-instance-service.js +49 -0
  223. package/lib/services/settings-service.d.ts +34 -0
  224. package/lib/services/settings-service.js +154 -0
  225. package/lib/services/singleton-map-service.d.ts +23 -0
  226. package/lib/services/singleton-map-service.js +44 -0
  227. package/lib/services/submit-hook-service.d.ts +24 -0
  228. package/lib/services/submit-hook-service.js +73 -0
  229. package/lib/styles.d.ts +1 -0
  230. package/lib/styles.js +4 -0
  231. package/lib/themes/bs3.d.ts +3 -0
  232. package/lib/themes/bs3.js +133 -0
  233. package/lib/themes/bs5.d.ts +3 -0
  234. package/lib/themes/bs5.js +111 -0
  235. package/lib/themes/glyphicon-fa-mapping.d.ts +3 -0
  236. package/lib/themes/glyphicon-fa-mapping.js +271 -0
  237. package/lib/themes/stub.d.ts +3 -0
  238. package/lib/themes/stub.js +82 -0
  239. package/lib/themes/theme.d.ts +233 -0
  240. package/lib/themes/theme.js +2 -0
  241. package/lib/translations.json +842 -0
  242. package/lib/utils.d.ts +167 -0
  243. package/lib/utils.js +1191 -0
  244. package/lib/validation.d.ts +7 -0
  245. package/lib/validation.js +141 -0
  246. package/llol +10 -0
  247. package/llol.pdf +10 -0
  248. package/package.json +99 -0
  249. package/q +196 -0
  250. package/test-export/array-spec.d.ts +1 -0
  251. package/test-export/array-spec.js +204 -0
  252. package/test-export/bird-point-count-spec.d.ts +1 -0
  253. package/test-export/bird-point-count-spec.js +62 -0
  254. package/test-export/collection-contest-form-spec.d.ts +1 -0
  255. package/test-export/collection-contest-form-spec.js +38 -0
  256. package/test-export/dataset-form-spec.d.ts +1 -0
  257. package/test-export/dataset-form-spec.js +50 -0
  258. package/test-export/date-time-widget-spec.d.ts +1 -0
  259. package/test-export/date-time-widget-spec.js +188 -0
  260. package/test-export/geocoder-spec.d.ts +1 -0
  261. package/test-export/geocoder-spec.js +135 -0
  262. package/test-export/image-array-spec.d.ts +1 -0
  263. package/test-export/image-array-spec.js +94 -0
  264. package/test-export/inject-field-spec.d.ts +1 -0
  265. package/test-export/inject-field-spec.js +148 -0
  266. package/test-export/internal-uuids-spec.d.ts +1 -0
  267. package/test-export/internal-uuids-spec.js +157 -0
  268. package/test-export/invasive-species-eradication-np-spec.d.ts +1 -0
  269. package/test-export/invasive-species-eradication-np-spec.js +18 -0
  270. package/test-export/invasive-species-eradication-spec.d.ts +1 -0
  271. package/test-export/invasive-species-eradication-spec.js +25 -0
  272. package/test-export/line-transect-spec.d.ts +1 -0
  273. package/test-export/line-transect-spec.js +121 -0
  274. package/test-export/mobile-form-spec.d.ts +1 -0
  275. package/test-export/mobile-form-spec.js +84 -0
  276. package/test-export/nafi-spec.d.ts +1 -0
  277. package/test-export/nafi-spec.js +85 -0
  278. package/test-export/select-widget-spec.d.ts +1 -0
  279. package/test-export/select-widget-spec.js +68 -0
  280. package/test-export/single-item-array-field-spec.d.ts +1 -0
  281. package/test-export/single-item-array-field-spec.js +92 -0
  282. package/test-export/syke-butterfly-spec.d.ts +1 -0
  283. package/test-export/syke-butterfly-spec.js +163 -0
  284. package/test-export/test-utils.d.ts +184 -0
  285. package/test-export/test-utils.js +354 -0
  286. package/test-export/transaction-form-spec.d.ts +1 -0
  287. package/test-export/transaction-form-spec.js +63 -0
  288. package/test-export/trip-report-autosuggest-spec.d.ts +1 -0
  289. package/test-export/trip-report-autosuggest-spec.js +272 -0
  290. package/test-export/trip-report-spec.d.ts +1 -0
  291. package/test-export/trip-report-spec.js +456 -0
  292. package/test-export/unit-list-shorthand-array-field-spec.d.ts +1 -0
  293. package/test-export/unit-list-shorthand-array-field-spec.js +71 -0
  294. package/test-export/validation-spec.d.ts +1 -0
  295. package/test-export/validation-spec.js +336 -0
  296. package/test-export/water-bird-spec.d.ts +1 -0
  297. package/test-export/water-bird-spec.js +30 -0
  298. package/test-export/wbc-spec.d.ts +1 -0
  299. package/test-export/wbc-spec.js +82 -0
  300. package/tsconfig.json +25 -0
  301. package/tsconfig.lib.json +11 -0
  302. package/tsconfig.test.json +10 -0
@@ -0,0 +1,1783 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __rest = (this && this.__rest) || function (s, e) {
9
+ var t = {};
10
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
11
+ t[p] = s[p];
12
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
13
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
14
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
15
+ t[p[i]] = s[p[i]];
16
+ }
17
+ return t;
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.getFeatureStyleWithHighlight = exports.getFeatureStyleWithLowerOpacity = exports.Map = exports.MapComponent = exports.parseGeometries = void 0;
21
+ const React = require("react");
22
+ const PropTypes = require("prop-types");
23
+ const react_dom_1 = require("react-dom");
24
+ const immutability_helper_1 = require("immutability-helper");
25
+ const equals = require("deep-equal");
26
+ const merge = require("deepmerge");
27
+ const laji_map_1 = require("@luomus/laji-map");
28
+ const utils_1 = require("@luomus/laji-map/lib/utils");
29
+ const globals_1 = require("@luomus/laji-map/lib/globals");
30
+ const components_1 = require("../components");
31
+ const utils_2 = require("../../utils");
32
+ const Context_1 = require("../../Context");
33
+ const ReactContext_1 = require("../../ReactContext");
34
+ const NestField_1 = require("./NestField");
35
+ const ArrayFieldTemplate_1 = require("../templates/ArrayFieldTemplate");
36
+ const ArrayField_1 = require("./ArrayField");
37
+ const utils_3 = require("@rjsf/utils");
38
+ function parseGeometries(geometry) {
39
+ return ((geometry && geometry.type === "GeometryCollection") ? geometry.geometries : [geometry])
40
+ .filter(geometry => geometry)
41
+ .reduce((geometries, _geometry) => {
42
+ if (geometry.type === "GeometryCollection") {
43
+ geometries = [...geometries, ...parseGeometries(_geometry)];
44
+ }
45
+ else if ("type" in geometry) {
46
+ geometries.push(geometry);
47
+ }
48
+ return geometries;
49
+ }, []);
50
+ }
51
+ exports.parseGeometries = parseGeometries;
52
+ class MapArrayField extends React.Component {
53
+ render() {
54
+ const { geometryMapper = "default" } = utils_2.getUiOptions(this.props.uiSchema);
55
+ switch (geometryMapper) {
56
+ case "default":
57
+ return React.createElement(DefaultMapArrayField, Object.assign({}, this.props));
58
+ case "units":
59
+ return React.createElement(UnitsMapArrayField, Object.assign({}, this.props));
60
+ case "lineTransect":
61
+ return React.createElement(LineTransectMapArrayField, Object.assign({}, this.props));
62
+ case "lolife":
63
+ return React.createElement(LolifeMapArrayField, Object.assign({}, this.props));
64
+ }
65
+ }
66
+ }
67
+ exports.default = MapArrayField;
68
+ MapArrayField.propTypes = {
69
+ uiSchema: PropTypes.shape({
70
+ "ui:options": PropTypes.shape({
71
+ geometryField: PropTypes.string,
72
+ // Strategy for getting geometry data.
73
+ geometryMapper: PropTypes.oneOf(["default", "units", "lineTransect", "lolife", "lolifeNamedPlace"]),
74
+ topOffset: PropTypes.number,
75
+ bottomOffset: PropTypes.number,
76
+ popupFields: PropTypes.arrayOf(PropTypes.object),
77
+ computeAreaField: PropTypes.string,
78
+ areaInHectares: PropTypes.bool,
79
+ mapSizes: PropTypes.shape({
80
+ lg: PropTypes.number,
81
+ md: PropTypes.number,
82
+ sm: PropTypes.number,
83
+ xs: PropTypes.number
84
+ }),
85
+ data: PropTypes.arrayOf(PropTypes.shape({
86
+ geometryField: PropTypes.string.isRequired
87
+ })),
88
+ help: PropTypes.string
89
+ }).isRequired,
90
+ }),
91
+ schema: PropTypes.shape({
92
+ type: PropTypes.oneOf(["array"])
93
+ }).isRequired,
94
+ formData: PropTypes.oneOfType([PropTypes.array, PropTypes.object])
95
+ };
96
+ let DefaultMapArrayField = class DefaultMapArrayField extends React.Component {
97
+ constructor(props) {
98
+ super(props);
99
+ this.onMapChangeCreateGathering = this.onMapChangeCreateGathering.bind(this);
100
+ this.onChange = this.onChange.bind(this);
101
+ this.getGeometry = this.getGeometry.bind(this);
102
+ }
103
+ getOptions(options) {
104
+ const { formData } = this.props;
105
+ const geometries = this.getData();
106
+ const emptyMode = !formData || !formData.length;
107
+ const draw = (options.draw === false || (utils_2.isNullOrUndefined(this.state.activeIdx) && !emptyMode)) ? false : Object.assign({ featureCollection: {
108
+ type: "FeatureCollection",
109
+ features: (geometries || []).map(geometry => {
110
+ return { type: "Feature", properties: {}, geometry };
111
+ })
112
+ }, getDraftStyle: this.getDraftStyle, onChange: emptyMode ? this.onMapChangeCreateGathering : this.onChange }, (options.draw && options.draw.constructor === Object && options.draw !== null ? options.draw : {}));
113
+ const controls = (emptyMode || this.state.activeIdx !== undefined)
114
+ ? { drawCopy: true }
115
+ : { draw: false };
116
+ const data = geometries && geometries.length || !options.placeholderGeometry
117
+ ? []
118
+ : [{
119
+ geoData: options.placeholderGeometry,
120
+ getFeatureStyle: this._getPlaceholderStyle
121
+ }];
122
+ const extraData = (options.data || []).map((dataItem) => ({ geoData: dataItem.geometryField ? this.getGeometry(formData, dataItem.geometryField) : dataItem }));
123
+ return { draw, controls, emptyMode, data: [...data, ...extraData] };
124
+ }
125
+ onMapChangeCreateGathering(events) {
126
+ const { geometryField } = utils_2.getUiOptions(this.props.uiSchema);
127
+ if (!geometryField) {
128
+ return;
129
+ }
130
+ let formData = utils_2.getDefaultFormState(this.props.schema.items);
131
+ const geometries = events.filter(e => e.type === "create").map(e => e.feature.geometry);
132
+ let splittedPath = geometryField.split("/").filter(s => !utils_2.isEmptyString(s));
133
+ let _cumulatedPointer = "";
134
+ let _schema = this.props.schema.items;
135
+ formData = splittedPath.reduce((_formData, split, i) => {
136
+ _cumulatedPointer += `/${split}`;
137
+ _schema = _schema.properties
138
+ ? _schema.properties[split]
139
+ : _schema.items;
140
+ return immutability_helper_1.default(_formData, utils_2.getUpdateObjectFromJSONPointer(_cumulatedPointer, { $set: i === splittedPath.length - 1
141
+ ? {
142
+ type: "GeometryCollection",
143
+ geometries
144
+ }
145
+ : utils_2.getDefaultFormState(_schema)
146
+ }));
147
+ }, formData);
148
+ this.props.onChange(ArrayField_1.onArrayFieldChange([formData], this.props));
149
+ this.setState({ activeIdx: 0 });
150
+ }
151
+ getGeometry(formData, _geometryField) {
152
+ const { uiSchema } = this.props;
153
+ const { geometryField } = utils_2.getUiOptions(uiSchema);
154
+ const { activeIdx } = this.state;
155
+ if (!formData) {
156
+ return;
157
+ }
158
+ const item = formData[activeIdx];
159
+ if (activeIdx === undefined || !item) {
160
+ return;
161
+ }
162
+ const geometryItem = utils_2.parseJSONPointer(formData[activeIdx], _geometryField || geometryField);
163
+ return geometryItem;
164
+ }
165
+ getGeometries() {
166
+ return this.getData();
167
+ }
168
+ getData() {
169
+ const geometryItem = this.getGeometry(this.props.formData);
170
+ if (geometryItem && geometryItem.type) {
171
+ return parseGeometries(geometryItem);
172
+ }
173
+ return [];
174
+ }
175
+ onChange(events) {
176
+ let formData = this.props.formData ||
177
+ [utils_2.getDefaultFormState(this.props.schema.items)];
178
+ let addOrDelete = false;
179
+ events.forEach(e => {
180
+ switch (e.type) {
181
+ case "create":
182
+ addOrDelete = true;
183
+ formData = this.onAdd(e, formData);
184
+ break;
185
+ case "delete":
186
+ addOrDelete = true;
187
+ formData = this.onRemove(e, formData);
188
+ break;
189
+ case "edit":
190
+ formData = this.onEdited(e, formData);
191
+ break;
192
+ case "insert":
193
+ addOrDelete = true;
194
+ formData = this.onInsert(e, formData);
195
+ break;
196
+ }
197
+ });
198
+ this.props.onChange(addOrDelete ? ArrayField_1.onArrayFieldChange(formData, this.props) : formData);
199
+ }
200
+ onAdd({ feature: { geometry } }, formData) {
201
+ const { geometryField } = utils_2.getUiOptions(this.props.uiSchema);
202
+ return utils_2.updateSafelyWithJSONPointer(formData, { type: "GeometryCollection", geometries: [...parseGeometries(this.getGeometry(formData)), geometry] }, `/${this.state.activeIdx}/${geometryField}`);
203
+ }
204
+ onRemove({ idxs }, formData) {
205
+ const { geometryField } = utils_2.getUiOptions(this.props.uiSchema);
206
+ let splices = [];
207
+ idxs.sort().reverse().forEach((idx) => {
208
+ splices.push([idx, 1]);
209
+ });
210
+ const geometry = this.getGeometry(formData);
211
+ return immutability_helper_1.default(formData, { [this.state.activeIdx]: utils_2.getUpdateObjectFromJSONPointer(geometryField, geometry && geometry.type === "GeometryCollection" ?
212
+ { geometries: { $splice: splices } } : { $set: undefined }) });
213
+ }
214
+ onEdited({ features }, formData) {
215
+ const { geometryField } = utils_2.getUiOptions(this.props.uiSchema);
216
+ const geometry = this.getGeometry(formData);
217
+ return immutability_helper_1.default(formData, { [this.state.activeIdx]: utils_2.getUpdateObjectFromJSONPointer(geometryField, geometry.type === "GeometryCollection" ? {
218
+ geometries: Object.keys(features).reduce((obj, idx) => {
219
+ obj[idx] = { $set: features[idx].geometry };
220
+ return obj;
221
+ }, {})
222
+ } : { $set: features[0].geometry }) });
223
+ }
224
+ onInsert({ idx, feature }, formData) {
225
+ const { geometryField } = utils_2.getUiOptions(this.props.uiSchema);
226
+ return immutability_helper_1.default(formData, { [this.state.activeIdx]: utils_2.getUpdateObjectFromJSONPointer(geometryField, {
227
+ geometries: { $splice: [[idx, 0, feature.geometry]] }
228
+ }) });
229
+ }
230
+ afterActiveChange(idx) {
231
+ if (idx === undefined)
232
+ return;
233
+ this.map.zoomToData();
234
+ }
235
+ };
236
+ DefaultMapArrayField = __decorate([
237
+ _MapArrayField
238
+ ], DefaultMapArrayField);
239
+ let UnitsMapArrayField = class UnitsMapArrayField extends React.Component {
240
+ constructor(props) {
241
+ super(props);
242
+ this.field = "units";
243
+ this.isGeometryCollection = (idx) => {
244
+ return this.props.formData[this.state.activeIdx].units[idx].unitGathering.geometry.type === "GeometryCollection";
245
+ };
246
+ this.getOptions = (options) => {
247
+ const { formData } = this.props;
248
+ const { gatherings = [], units = [] } = this.getData();
249
+ const emptyMode = !formData || !formData.length;
250
+ const draw = (options.draw === false || (utils_2.isNullOrUndefined(this.state.activeIdx) && !emptyMode)) ? false : Object.assign({ featureCollection: {
251
+ type: "FeatureCollection",
252
+ features: gatherings.map(geometry => {
253
+ return { type: "Feature", properties: {}, geometry };
254
+ })
255
+ }, getDraftStyle: this.getDraftStyle, onChange: emptyMode ? this.onMapChangeCreateGathering : this.onChange }, (options.draw && options.draw.constructor === Object && options.draw !== null ? options.draw : {}));
256
+ // Separate non geometry collections and geometry collections with single geometry to
257
+ // unitGeometries, and put the rest to unitGeometryCollections. This is for optimization.
258
+ let unitGeometryCollections = {}, unitGeometries = {};
259
+ units.forEach((geometry, idx) => {
260
+ const target = (geometry.type !== "GeometryCollection" || geometry.geometries.length === 1)
261
+ ? unitGeometries
262
+ : unitGeometryCollections;
263
+ target[idx] = geometry.type === "GeometryCollection" && geometry.geometries.length === 1
264
+ ? geometry.geometries[0]
265
+ : geometry;
266
+ });
267
+ this.unitIdxToGeometryIdx = {};
268
+ this.geometryIdxUnitIdx = {};
269
+ this.unitIdxToGeometryCollectionIdx = {};
270
+ this.geometryCollectionIdxUnitIdx = {};
271
+ const reducer = ([uToG, gToU], idx, _idx) => {
272
+ uToG[idx] = _idx;
273
+ gToU[_idx] = idx;
274
+ return [uToG, gToU];
275
+ };
276
+ Object.keys(unitGeometries).reduce(reducer, [this.unitIdxToGeometryIdx, this.geometryIdxUnitIdx]);
277
+ Object.keys(unitGeometryCollections).reduce(reducer, [this.unitIdxToGeometryCollectionIdx, this.geometryCollectionIdxUnitIdx]);
278
+ if (!this.unitChangeHandlers) {
279
+ this.unitChangeHandlers = { onChange: {}, mouseOver: {}, mouseOut: {} };
280
+ }
281
+ const getCommonOptions = unitIdx => {
282
+ // Store so change detection doesn't think it's a new function.
283
+ const unitChangeHandler = this.unitChangeHandlers.onChange[unitIdx] || this.onUnitChange(unitIdx ? +unitIdx : undefined);
284
+ this.unitChangeHandlers.onChange[unitIdx] = unitChangeHandler;
285
+ const mouseOver = this.unitChangeHandlers.mouseOver[unitIdx] || this.onMouseOver(unitIdx ? +unitIdx : undefined);
286
+ this.unitChangeHandlers.mouseOver[unitIdx] = mouseOver;
287
+ const mouseOut = this.unitChangeHandlers.mouseOut[unitIdx] || this.onMouseOut(unitIdx ? +unitIdx : undefined);
288
+ this.unitChangeHandlers.mouseOut[unitIdx] = mouseOut;
289
+ return {
290
+ getPopup: this.getPopup,
291
+ getFeatureStyle: this.getUnitFeatureStyle,
292
+ getDraftStyle: this.getDraftStyle,
293
+ editable: true,
294
+ onChange: unitChangeHandler,
295
+ on: {
296
+ mouseover: mouseOver,
297
+ mouseout: mouseOut
298
+ }
299
+ };
300
+ };
301
+ const data = [
302
+ Object.assign({ featureCollection: {
303
+ type: "FeatureCollection",
304
+ features: Object.keys(unitGeometries).reduce((units, idx) => {
305
+ idx = +idx;
306
+ const geometry = unitGeometries[idx];
307
+ if (geometry)
308
+ units.push({ type: "Feature", properties: { idx }, geometry });
309
+ return units;
310
+ }, [])
311
+ } }, getCommonOptions()),
312
+ ...Object.keys(unitGeometryCollections).map(idx => {
313
+ idx = +idx;
314
+ const geometryCollection = unitGeometryCollections[idx];
315
+ return Object.assign({ featureCollection: {
316
+ type: "FeatureCollection",
317
+ features: geometryCollection.geometries.map(geometry => ({
318
+ type: "Feature", properties: { idx }, geometry
319
+ }))
320
+ } }, getCommonOptions(this.geometryCollectionIdxUnitIdx[idx]));
321
+ })
322
+ ];
323
+ this.unitFeatures = data[0].featureCollection.features;
324
+ const controls = (emptyMode || !utils_2.isNullOrUndefined(this.state.activeIdx)) ?
325
+ {} : { draw: false };
326
+ return { draw, data, controls, emptyMode };
327
+ };
328
+ this.getUnitFeatureStyle = () => {
329
+ let color = "#55AEFA";
330
+ if (this._highlightedUnit !== undefined) {
331
+ color = utils_1.combineColors(color, "#ffffff", 30);
332
+ }
333
+ return { color: color, fillColor: color, weight: 4 };
334
+ };
335
+ this.startHighlight = ({ idx }) => {
336
+ const color = utils_1.combineColors(this.getUnitFeatureStyle().color, "#ffffff", 30);
337
+ if (idx in this.unitIdxToGeometryCollectionIdx) {
338
+ const _idx = this.unitIdxToGeometryCollectionIdx[idx];
339
+ this.map.data[_idx + 1].group.getLayers().forEach(layer => {
340
+ this.map.setLayerStyle(layer, { color });
341
+ });
342
+ }
343
+ else {
344
+ const _idx = this.unitIdxToGeometryIdx[idx];
345
+ const layer = this.map.getLayerByIdxTuple([0, _idx]);
346
+ layer && this.map.setLayerStyle(layer, { color });
347
+ }
348
+ };
349
+ this.endHighlight = ({ idx }) => {
350
+ const color = this.getUnitFeatureStyle().color;
351
+ if (idx in this.unitIdxToGeometryCollectionIdx) {
352
+ const _idx = this.unitIdxToGeometryCollectionIdx[idx];
353
+ this.map.data[_idx + 1].group.getLayers().forEach(layer => {
354
+ this.map.setLayerStyle(layer, { color });
355
+ });
356
+ }
357
+ else {
358
+ const _idx = this.unitIdxToGeometryIdx[idx];
359
+ const layer = this.map.getLayerByIdxTuple([0, _idx]);
360
+ layer && this.map.setLayerStyle(layer, { color });
361
+ }
362
+ };
363
+ this.onMouseOver = (unitIdx) => (e, { feature }) => {
364
+ const idx = unitIdx !== undefined ? unitIdx : feature.properties.idx;
365
+ if (idx === undefined) {
366
+ return;
367
+ }
368
+ this._highlightedUnit = idx;
369
+ this.startHighlight(idx);
370
+ const id = `${this.props.idSchema.$id}_${this.state.activeIdx}_units_${idx}`;
371
+ this.highlightedElem = this.props.formContext.utils.getSchemaElementById(id);
372
+ if (this.highlightedElem) {
373
+ this.highlightedElem.className += " map-highlight";
374
+ }
375
+ };
376
+ this.onMouseOut = (unitIdx) => (e, { feature }) => {
377
+ const idx = unitIdx !== undefined ? unitIdx : feature.properties.idx;
378
+ if (idx === undefined) {
379
+ return;
380
+ }
381
+ this._highlightedUnit = undefined;
382
+ this.endHighlight(idx);
383
+ if (this.highlightedElem) {
384
+ this.highlightedElem.className = this.highlightedElem.className.replace(" map-highlight", "");
385
+ }
386
+ };
387
+ this.onUnitChange = (unitIdx) => (events) => {
388
+ events.forEach(e => {
389
+ switch (e.type) {
390
+ case "delete":
391
+ this.onUnitRemove(e, unitIdx);
392
+ break;
393
+ case "edit":
394
+ this.onUnitEdited(e, unitIdx);
395
+ break;
396
+ }
397
+ });
398
+ };
399
+ this.onUnitRemove = (e, unitIdx) => {
400
+ if (unitIdx === undefined) { // Isn't a geometry collection (unitIdx stored in feature properties)
401
+ const idxs = e.idxs.map(idx => this.unitFeatures[idx].properties.idx);
402
+ const { formData } = this.props;
403
+ const unitIdxs = idxs;
404
+ let updateObject = { [this.state.activeIdx]: {
405
+ units: unitIdxs.reduce((obj, idx) => {
406
+ obj[idx] = {
407
+ unitGathering: {
408
+ geometry: {
409
+ $set: utils_2.getDefaultFormState(this.props.schema.items.properties.units.items.properties.unitGathering.properties.geometry)
410
+ }
411
+ }
412
+ };
413
+ return obj;
414
+ }, {})
415
+ } };
416
+ this.props.onChange(immutability_helper_1.default(formData, updateObject));
417
+ }
418
+ else { // Is a geometry collection.
419
+ const { idxs } = e;
420
+ this.props.onChange(immutability_helper_1.default(this.props.formData, {
421
+ [this.state.activeIdx]: {
422
+ units: {
423
+ [unitIdx]: {
424
+ unitGathering: {
425
+ geometry: {
426
+ geometries: {
427
+ $splice: idxs.sort().reverse().map(idx => [idx, 1])
428
+ }
429
+ }
430
+ }
431
+ }
432
+ }
433
+ }
434
+ }));
435
+ }
436
+ };
437
+ this.onUnitEdited = ({ features }, unitIdx) => {
438
+ if (unitIdx === undefined) { // Isn't a geometry collection (unitIdx stored in feature properties)
439
+ const unitEditGeometries = Object.keys(features).reduce((unitEditGeometries, idx) => {
440
+ unitEditGeometries[features[idx].properties.idx] = features[idx].geometry;
441
+ return unitEditGeometries;
442
+ }, {});
443
+ const updateObject = {
444
+ [this.state.activeIdx]: {
445
+ units: Object.keys(unitEditGeometries).reduce((o, i) => {
446
+ o[i] = { unitGathering: { geometry: { $set: unitEditGeometries[i] } } };
447
+ return o;
448
+ }, {})
449
+ }
450
+ };
451
+ this.props.onChange(immutability_helper_1.default(this.props.formData, updateObject));
452
+ }
453
+ else { // Is a geometry collection.
454
+ this.props.onChange(immutability_helper_1.default(this.props.formData, {
455
+ [this.state.activeIdx]: {
456
+ units: {
457
+ [unitIdx]: {
458
+ unitGathering: {
459
+ geometry: { $set: Object.keys(features).reduce((geometryCollection, idx) => {
460
+ const feature = features[idx];
461
+ geometryCollection.geometries[idx] = feature.geometry;
462
+ return geometryCollection;
463
+ }, this.props.formData[this.state.activeIdx].units[unitIdx].unitGathering.geometry)
464
+ }
465
+ }
466
+ }
467
+ }
468
+ }
469
+ }));
470
+ }
471
+ };
472
+ this.onMapChangeCreateGathering = DefaultMapArrayField.prototype.onMapChangeCreateGathering.bind(this);
473
+ this.onChange = DefaultMapArrayField.prototype.onChange.bind(this);
474
+ this.onAdd = DefaultMapArrayField.prototype.onAdd.bind(this);
475
+ this.onRemove = DefaultMapArrayField.prototype.onRemove.bind(this);
476
+ this.onEdited = DefaultMapArrayField.prototype.onEdited.bind(this);
477
+ this.onInsert = DefaultMapArrayField.prototype.onInsert.bind(this);
478
+ this.afterActiveChange = DefaultMapArrayField.prototype.afterActiveChange.bind(this);
479
+ this.getGeometry = DefaultMapArrayField.prototype.getGeometry.bind(this);
480
+ }
481
+ componentDidMount() {
482
+ this.props.formContext.services.customEvents.add(this.props.idSchema.$id, "startHighlight", this.startHighlight);
483
+ this.props.formContext.services.customEvents.add(this.props.idSchema.$id, "endHighlight", this.endHighlight);
484
+ }
485
+ componentWillUnmount() {
486
+ this.props.formContext.services.customEvents.remove(this.props.idSchema.$id, "startHighlight", this.startHighlight);
487
+ this.props.formContext.services.customEvents.remove(this.props.idSchema.$id, "endHighlight", this.endHighlight);
488
+ }
489
+ getData() {
490
+ const { formData } = this.props;
491
+ const idx = this.state.activeIdx;
492
+ if (!formData)
493
+ return {};
494
+ const item = formData[idx];
495
+ const gatherings = DefaultMapArrayField.prototype.getData.call(this);
496
+ const units = ((item && item.units) ? item.units : []).reduce((units, unit, idx) => {
497
+ if (unit.unitGathering) {
498
+ const { unitGathering: { geometry } } = unit;
499
+ if (geometry && utils_2.hasData(geometry)) {
500
+ units[idx] = geometry;
501
+ }
502
+ }
503
+ return units;
504
+ }, []);
505
+ return { gatherings, units };
506
+ }
507
+ getGeometries() {
508
+ const { gatherings, units } = this.getData();
509
+ return [
510
+ ...parseGeometries(gatherings),
511
+ ...parseGeometries(units)
512
+ ];
513
+ }
514
+ parsePopupPointer(col, options) {
515
+ return col.replace("[idx]", options.feature.properties.idx);
516
+ }
517
+ };
518
+ UnitsMapArrayField = __decorate([
519
+ _MapArrayField
520
+ ], UnitsMapArrayField);
521
+ let LineTransectMapArrayField = class LineTransectMapArrayField extends React.Component {
522
+ constructor(props) {
523
+ super(props);
524
+ this.onLineCreate = ([event]) => {
525
+ this.props.onChange(ArrayField_1.onArrayFieldChange(immutability_helper_1.default(this.props.formData, { 0: { geometry: { $set: event.feature.geometry
526
+ } } }), this.props));
527
+ };
528
+ this.onChange = (events) => {
529
+ const { geometryField } = utils_2.getUiOptions(this.props.uiSchema);
530
+ let state = {};
531
+ let { formData } = this.props;
532
+ let formDataChanged = false;
533
+ let addOrDelete = false;
534
+ events.forEach(e => {
535
+ switch (e.type) {
536
+ case "insert": {
537
+ formDataChanged = true;
538
+ addOrDelete = true;
539
+ const newItem = utils_2.getDefaultFormState(this.props.schema.items);
540
+ newItem[geometryField] = e.geometry;
541
+ formData = immutability_helper_1.default(formData, {
542
+ $splice: [[e.idx, 0, newItem]]
543
+ });
544
+ break;
545
+ }
546
+ case "edit": {
547
+ formDataChanged = true;
548
+ formData = immutability_helper_1.default(formData, {
549
+ [e.idx]: {
550
+ [geometryField]: { $set: e.geometry }
551
+ }
552
+ });
553
+ break;
554
+ }
555
+ case "delete": {
556
+ formDataChanged = true;
557
+ addOrDelete = true;
558
+ formData = immutability_helper_1.default(formData, { $splice: [[e.idx, 1]] });
559
+ break;
560
+ }
561
+ case "merge": {
562
+ formDataChanged = true;
563
+ addOrDelete = true;
564
+ const [first, second] = e.idxs;
565
+ formData = immutability_helper_1.default(formData, { [first]: { units: { $set: [
566
+ ...(formData[first].units || []),
567
+ ...(formData[second].units || [])
568
+ ] } } });
569
+ formData = immutability_helper_1.default(formData, {
570
+ [first]: {
571
+ [geometryField]: { $set: e.geometry }
572
+ }
573
+ });
574
+ formData = immutability_helper_1.default(formData, { $splice: [[second, 1]] });
575
+ break;
576
+ }
577
+ case "move": {
578
+ formDataChanged = true;
579
+ const { idx, target } = e;
580
+ let splices = [
581
+ [idx, 1],
582
+ [target, 0, formData[idx]],
583
+ ];
584
+ // Splices must be executed in reverse order to keep idxs correct.
585
+ if (target > idx)
586
+ splices = splices.reverse();
587
+ formData = immutability_helper_1.default(formData, { $splice: splices });
588
+ break;
589
+ }
590
+ case "active": {
591
+ state.activeIdx = e.idx;
592
+ }
593
+ }
594
+ });
595
+ const afterState = () => {
596
+ if (formDataChanged) {
597
+ this.props.onChange(addOrDelete ? ArrayField_1.onArrayFieldChange(formData, this.props) : formData);
598
+ }
599
+ if ("activeIdx" in state) {
600
+ this.afterActiveChange(state.activeIdx);
601
+ }
602
+ };
603
+ Object.keys(state).length ? this.setState(state, afterState()) : afterState();
604
+ };
605
+ this.getFeatureStyle = ({ lineIdx, style, type }) => {
606
+ if (this.props.errorSchema[lineIdx]) {
607
+ return (type === L.CircleMarker) // eslint-disable-line no-undef
608
+ ? style
609
+ : Object.assign(Object.assign({}, style), { fillColor: "#f33" });
610
+ }
611
+ const { gatheringFact = {} } = this.props.formData[lineIdx] || {};
612
+ const { lineTransectSegmentCounted } = gatheringFact;
613
+ if (!lineTransectSegmentCounted) {
614
+ return Object.assign(Object.assign({}, style), { fillColor: "#444444" });
615
+ }
616
+ };
617
+ this.getTooltip = (lineIdx, content) => {
618
+ const { translations } = this.props.formContext;
619
+ if (this.props.errorSchema[lineIdx]) {
620
+ content = `${content}<br/><span class="text-danger">${translations.LineTransectSegmentHasErrors}!</span>`;
621
+ }
622
+ const { gatheringFact = {} } = this.props.formData[lineIdx];
623
+ const { lineTransectSegmentCounted } = gatheringFact;
624
+ if (!lineTransectSegmentCounted)
625
+ content = `${content}<br/>${translations.LineTransectSegmentNotCounted}`;
626
+ return content;
627
+ };
628
+ this.focusOnMap = (idx) => {
629
+ if (!this.hasLineTransectFeature(this.props)) {
630
+ setTimeout(() => this.map.zoomToData({ paddingInMeters: 200 }));
631
+ return;
632
+ }
633
+ this.props.formContext.setTimeout(() => {
634
+ this.map && this.map.fitBounds(L.featureGroup(this.map._corridorLayers[idx]).getBounds(), { paddingInMeters: 100 }); // eslint-disable-line no-undef
635
+ });
636
+ };
637
+ this.state = { showLTTools: false };
638
+ }
639
+ getOptions() {
640
+ const { formData, disabled, readonly } = this.props;
641
+ const { geometryField, placeholderGeometry } = utils_2.getUiOptions(this.props.uiSchema);
642
+ const lineTransect = this.hasLineTransectFeature(this.props)
643
+ ? { type: "MultiLineString", coordinates: formData.map(item => item[geometryField].coordinates) }
644
+ : undefined;
645
+ return {
646
+ lineTransect: lineTransect ? {
647
+ feature: { geometry: lineTransect },
648
+ activeIdx: this.state.activeIdx,
649
+ onChange: this.onChange,
650
+ getFeatureStyle: this.getFeatureStyle,
651
+ getTooltip: this.getTooltip,
652
+ editable: !disabled && !readonly
653
+ } : undefined,
654
+ draw: lineTransect ? false : {
655
+ line: true,
656
+ marker: false,
657
+ circle: false,
658
+ rectangle: false,
659
+ polygon: false,
660
+ onChange: this.onLineCreate
661
+ },
662
+ data: lineTransect || !placeholderGeometry ? false : {
663
+ geoData: placeholderGeometry,
664
+ getFeatureStyle: this._getPlaceholderStyle
665
+ },
666
+ controls: {
667
+ lineTransect: {
668
+ split: true,
669
+ splitByMeters: this.state.showLTTools,
670
+ createPoint: this.state.showLTTools,
671
+ shiftPoint: this.state.showLTTools,
672
+ deletePoints: this.state.showLTTools,
673
+ undo: this.state.showLTTools,
674
+ redo: this.state.showLTTools
675
+ },
676
+ draw: {
677
+ undo: false,
678
+ redo: false
679
+ }
680
+ },
681
+ customControls: [{
682
+ iconCls: `glyphicon glyphicon-${this.state.showLTTools ? "menu-up" : "option-vertical"}`,
683
+ fn: () => {
684
+ this.setState({ showLTTools: !this.state.showLTTools });
685
+ },
686
+ text: this.props.formContext.translations[this.state.showLTTools ? "HideLineTransectControls" : "ShowLineTransectControls"],
687
+ group: "lineTransect"
688
+ }]
689
+ };
690
+ }
691
+ afterActiveChange(idx) {
692
+ this.focusOnMap(idx);
693
+ }
694
+ hasLineTransectFeature(props) {
695
+ const { geometryField } = utils_2.getUiOptions(props.uiSchema);
696
+ return props.formData && props.formData[0] && Object.keys(props.formData[0][geometryField] || {}).length;
697
+ }
698
+ componentDidUpdate(prevProps) {
699
+ if (!this.hasLineTransectFeature(prevProps) || !this.hasLineTransectFeature(this.props))
700
+ return;
701
+ for (let lineIdx = 0; lineIdx < this.props.formData.length; lineIdx++) {
702
+ this.map._updateLTStyleForLineIdx(lineIdx);
703
+ }
704
+ }
705
+ };
706
+ LineTransectMapArrayField.contextType = ReactContext_1.default;
707
+ LineTransectMapArrayField = __decorate([
708
+ _MapArrayField
709
+ ], LineTransectMapArrayField);
710
+ let LolifeMapArrayField = class LolifeMapArrayField extends React.Component {
711
+ constructor(props) {
712
+ super(props);
713
+ this.onChangeForGathering = (idx) => (events) => {
714
+ let formData = this.getGatherings ? this.getGatherings() : this.props.formData;
715
+ events.forEach(e => {
716
+ switch (e.type) {
717
+ case "edit":
718
+ formData = immutability_helper_1.default(formData, formData[idx].geometry.type === "GeometryCollection"
719
+ ? Object.keys(e.features).reduce((updates, _idx) => (Object.assign(Object.assign({}, updates), { [idx]: { geometry: { geometries: { [_idx]: { $set: e.features[_idx].geometry } } } } })), {})
720
+ : { [idx]: { geometry: { $set: e.features[0].geometry } } });
721
+ break;
722
+ case "create":
723
+ formData = immutability_helper_1.default(formData, { [idx]: { geometry: { $set: e.feature.geometry } } });
724
+ break;
725
+ case "delete":
726
+ if (formData[idx].geometry.type === "GeometryCollection") {
727
+ let splices = [];
728
+ e.idxs.sort().reverse().forEach((idx) => {
729
+ splices.push([idx, 1]);
730
+ });
731
+ formData = immutability_helper_1.default(formData, { [idx]: { geometry: { geometries: { $splice: splices } } } });
732
+ }
733
+ else {
734
+ formData = immutability_helper_1.default(formData, { [idx]: { geometry: { $set: undefined } } });
735
+ }
736
+ break;
737
+ }
738
+ });
739
+ this.props.onChange(formData);
740
+ };
741
+ this.onChangeForUnits = (events) => {
742
+ let formData = this.props.formData[0].units;
743
+ events.forEach(e => {
744
+ switch (e.type) {
745
+ case "edit":
746
+ formData = utils_2.updateSafelyWithJSONPointer(formData, e.features[0].geometry, `/${e.features[0].properties.idx}/unitGathering/geometry`);
747
+ break;
748
+ case "create":
749
+ throw new Error("Lolife map shouldn't me able to send create for unit");
750
+ case "delete":
751
+ formData = utils_2.updateSafelyWithJSONPointer(formData, undefined, `/${e.features[0].properties.idx}/unitGathering/geometry`);
752
+ break;
753
+ }
754
+ });
755
+ this.props.onChange(utils_2.updateSafelyWithJSONPointer(this.props.formData, formData, "/0/units"));
756
+ };
757
+ this.getFeatureStyle = ({ feature }, highlight) => {
758
+ if (!feature) {
759
+ return {};
760
+ }
761
+ const namedPlaceStyle = { color: "#777777", fillOpacity: 0.2, weight: 6 };
762
+ const foragingStyle = { color: "#FFCD38" };
763
+ const breedingAndRestingStyle = { color: "#a9d18e" };
764
+ const accessStyle = { color: "#F489A7" };
765
+ const coreZoneStyle = { color: "#F2764D" };
766
+ const habitatZoneStyle = { color: "#937D32" };
767
+ const applicableZoneStyle = { color: "#8EC0D1" };
768
+ let idx = undefined;
769
+ const gathering = this.props.formData.find((item, _idx) => {
770
+ idx = _idx;
771
+ return utils_2.getUUID(item) === feature.properties.id;
772
+ });
773
+ if (!gathering) {
774
+ return {};
775
+ }
776
+ let style;
777
+ const { gatheringType } = gathering;
778
+ switch (gatheringType) {
779
+ case "MY.gatheringTypeForagingArea":
780
+ style = foragingStyle;
781
+ break;
782
+ case "MY.gatheringTypeBreedingAndRestingArea":
783
+ style = breedingAndRestingStyle;
784
+ break;
785
+ case "MY.gatheringTypeLolifeAccess":
786
+ style = accessStyle;
787
+ break;
788
+ case "MY.gatheringTypeLolifeCoreZone":
789
+ style = coreZoneStyle;
790
+ break;
791
+ case "MY.gatheringTypeLolifeHabitatZone":
792
+ style = habitatZoneStyle;
793
+ break;
794
+ case "MY.gatheringTypeLolifeApplicableZone":
795
+ style = applicableZoneStyle;
796
+ break;
797
+ default:
798
+ style = namedPlaceStyle;
799
+ }
800
+ const { activeIdx } = this.state;
801
+ if (highlight || activeIdx !== undefined) {
802
+ if (idx !== activeIdx) {
803
+ return exports.getFeatureStyleWithLowerOpacity(style);
804
+ }
805
+ return exports.getFeatureStyleWithHighlight(style);
806
+ }
807
+ return style;
808
+ };
809
+ this.getUnitFeatureStyle = ({ feature }) => {
810
+ const droppingsTreeStyle = { color: "#b89220" };
811
+ const nestTreeStyle = { color: "#9e713b" };
812
+ const observationStyle = { color: globals_1.NORMAL_COLOR };
813
+ const unit = this.props.formData[0].units.find((item) => utils_2.getUUID(item) === feature.properties.id);
814
+ if (!unit) {
815
+ return {};
816
+ }
817
+ const { nestType, indirectObservationType } = unit;
818
+ let style = observationStyle;
819
+ if (nestType) {
820
+ style = nestTreeStyle;
821
+ }
822
+ else if (indirectObservationType) {
823
+ style = droppingsTreeStyle;
824
+ }
825
+ const { activeIdx } = this.state;
826
+ if (activeIdx !== undefined) {
827
+ return exports.getFeatureStyleWithLowerOpacity(style);
828
+ }
829
+ return style;
830
+ };
831
+ this.startHighlight = ({ id }) => {
832
+ let mapIdx = this.map.data.findIndex(d => ((d.featureCollection.features[0] || {}).properties || {}).id === id);
833
+ let style = this.map.data[mapIdx].getFeatureStyle({ dataIdx: mapIdx, feature: this.map.data[mapIdx].featureCollection.features[0] });
834
+ if (!style.color) {
835
+ return;
836
+ }
837
+ const color = utils_1.combineColors(style.color, "#ffffff", 150);
838
+ const layer = this.map.getLayerByIdxTuple([mapIdx, 0]);
839
+ layer && this.map.setLayerStyle(layer, Object.assign(Object.assign({}, style), { color, fillColor: color }));
840
+ };
841
+ this.endHighlight = ({ id }) => {
842
+ let mapIdx = this.map.data.findIndex(d => ((d.featureCollection.features[0] || {}).properties || {}).id === id);
843
+ const style = this.map.data[mapIdx].getFeatureStyle({ dataIdx: mapIdx, feature: this.map.data[mapIdx].featureCollection.features[0] });
844
+ if (!style) {
845
+ return;
846
+ }
847
+ if (!style.fillOpacity) {
848
+ style.fillOpacity = 0.4; // LajiMap default fill opacity.
849
+ }
850
+ const layer = this.map.getLayerByIdxTuple([mapIdx, 0]);
851
+ layer && this.map.setLayerStyle(layer, style);
852
+ };
853
+ this.onClick = (e, { feature }) => {
854
+ const { idx, unit } = feature.properties;
855
+ if (!unit && !idx) {
856
+ return;
857
+ }
858
+ const { topOffset, bottomOffset } = this.props.formContext;
859
+ if (!unit) {
860
+ this.setState({ activeIdx: idx });
861
+ }
862
+ const elem = this.getHighlightElem(idx, unit);
863
+ utils_2.scrollIntoViewIfNeeded(elem, topOffset, bottomOffset);
864
+ utils_2.highlightElem(elem);
865
+ };
866
+ this.onMouseOver = this.onMouseOver.bind(this);
867
+ this.onMouseOut = this.onMouseOut.bind(this);
868
+ this.startHighlight = this.startHighlight.bind(this);
869
+ this.endHighlight = this.endHighlight.bind(this);
870
+ this.onChanges = {};
871
+ }
872
+ componentDidMount() {
873
+ this.props.formContext.services.customEvents.add(this.props.idSchema.$id, "startHighlight", this.startHighlight);
874
+ this.props.formContext.services.customEvents.add(this.props.idSchema.$id, "endHighlight", this.endHighlight);
875
+ }
876
+ componentWillUnmount() {
877
+ this.props.formContext.services.customEvents.remove(this.props.idSchema.$id, "startHighlight", this.startHighlight);
878
+ this.props.formContext.services.customEvents.remove(this.props.idSchema.$id, "endHighlight", this.endHighlight);
879
+ }
880
+ componentDidUpdate(prevProps, prevState) {
881
+ if (this.highlightedElem && prevState.activeIdx !== this.state.activeIdx) {
882
+ this.highlightedElem.className = this.highlightedElem.className.replace(" map-highlight", "");
883
+ }
884
+ }
885
+ getOptions() {
886
+ const data = this.getData();
887
+ return {
888
+ draw: this.getDraw(),
889
+ data,
890
+ controls: {
891
+ draw: {
892
+ undo: false,
893
+ redo: false
894
+ }
895
+ }
896
+ };
897
+ }
898
+ getDraftStyle() {
899
+ return this.getFeatureStyle({ feature: { properties: { id: utils_2.getUUID(this.props.formData[this.state.activeIdx]) } } }, !!"higlight");
900
+ }
901
+ getDraw() {
902
+ const active = this.props.formData[this.state.activeIdx];
903
+ if (!active) {
904
+ return false;
905
+ }
906
+ return {
907
+ geoData: this.getFeatureCollection(active, { idx: this.state.activeIdx }),
908
+ onChange: this.getOnChangeForIdx(this.state.activeIdx),
909
+ getFeatureStyle: this.getFeatureStyle,
910
+ getDraftStyle: this.getDraftStyle,
911
+ marker: false,
912
+ on: {
913
+ mouseover: this.onMouseOver,
914
+ mouseout: this.onMouseOut,
915
+ },
916
+ };
917
+ }
918
+ getOnChangeForIdx(idx) {
919
+ // Store so change detection doesn't think it's a new function.
920
+ const onChangeForIdx = this.onChanges[idx] || this.onChangeForGathering(idx);
921
+ this.onChanges[idx] = onChangeForIdx;
922
+ return onChangeForIdx;
923
+ }
924
+ getFeatureCollection(geometryContainer, properties = {}, geometryField = "/geometry") {
925
+ return { type: "FeatureCollection", features: parseGeometries(utils_2.parseJSONPointer(geometryContainer, geometryField)).map(g => ({ type: "Feature", properties: Object.assign({ id: utils_2.getUUID(geometryContainer) }, properties), geometry: g })) };
926
+ }
927
+ getData() {
928
+ return this._getData(this.props.formData);
929
+ }
930
+ _getData(formData) {
931
+ let gatherings = (formData || []).map((gathering, idx) => ({
932
+ featureCollection: this.getFeatureCollection(gathering, { idx }),
933
+ getFeatureStyle: this.getFeatureStyle,
934
+ on: {
935
+ mouseover: this.onMouseOver,
936
+ mouseout: this.onMouseOut,
937
+ click: this.onClick
938
+ },
939
+ onChange: idx && this.getOnChangeForIdx(idx),
940
+ editable: !!idx,
941
+ getPopup: idx && this.getPopup
942
+ }));
943
+ const { activeIdx } = this.state;
944
+ if (activeIdx !== undefined) {
945
+ gatherings.splice(activeIdx, 1);
946
+ }
947
+ const units = (formData[0].units || []).map((unit, idx) => ({
948
+ featureCollection: this.getFeatureCollection(unit, { unit: true, idx }, "/unitGathering/geometry"),
949
+ editable: true,
950
+ onChange: this.onChangeForUnits,
951
+ getFeatureStyle: this.getUnitFeatureStyle,
952
+ on: {
953
+ mouseover: this.onMouseOver,
954
+ mouseout: this.onMouseOut,
955
+ click: this.onClick
956
+ },
957
+ getPopup: this.getPopup
958
+ })).filter(item => item.featureCollection.features.length);
959
+ return [...gatherings, ...units];
960
+ }
961
+ getGeometries() {
962
+ return this._getGeometries(this.getData());
963
+ }
964
+ _getGeometries(data) {
965
+ return data.reduce((geometries, { featureCollection }) => [
966
+ ...geometries,
967
+ ...featureCollection.features.map(f => f.geometry)
968
+ ], []);
969
+ }
970
+ cavityTreeStyle() { return { color: "#9e713b" }; }
971
+ droppingsTreeStyle() { return { color: "#b89220" }; }
972
+ nestTreeStyle() { return { color: "#ff0000" }; }
973
+ observationStyle() { return { color: globals_1.NORMAL_COLOR }; }
974
+ getHighlightElem(idx, unit) {
975
+ if (unit) {
976
+ return this.props.formContext.utils.getSchemaElementById(`${this.props.idSchema.$id}_0_units_${idx}`);
977
+ }
978
+ else {
979
+ return document.getElementById(`${this.props.idSchema.$id}_${idx}-panel`);
980
+ }
981
+ }
982
+ onMouseOver(e, { feature }) {
983
+ const { idx, unit } = feature.properties;
984
+ if (!unit && !idx) {
985
+ return;
986
+ }
987
+ this.highlightedElem = this.getHighlightElem(idx, unit);
988
+ if (this.highlightedElem) {
989
+ this.highlightedElem.className += " map-highlight";
990
+ }
991
+ }
992
+ onMouseOut(e, { feature }) {
993
+ const { idx, unit } = feature.properties;
994
+ if (!unit && !idx) {
995
+ return;
996
+ }
997
+ this.highlightedElem = this.getHighlightElem(idx, unit);
998
+ if (this.highlightedElem) {
999
+ this.highlightedElem.className = this.highlightedElem.className.replace(" map-highlight", "");
1000
+ }
1001
+ }
1002
+ getFormDataForPopup({ feature }) {
1003
+ if (feature.properties.unit) {
1004
+ return this.props.formData[0].units.find(item => utils_2.getUUID(item) === feature.properties.id);
1005
+ }
1006
+ return this.props.formData.find(item => utils_2.getUUID(item) === feature.properties.id);
1007
+ }
1008
+ };
1009
+ LolifeMapArrayField = __decorate([
1010
+ _MapArrayField
1011
+ ], LolifeMapArrayField);
1012
+ function _MapArrayField(ComposedComponent) {
1013
+ class _MapArrayField extends ComposedComponent {
1014
+ constructor(props) {
1015
+ super(props);
1016
+ this.geocode = () => {
1017
+ // Zoom map to area. Area ID is accessed from schema field defined in options.areaField
1018
+ const item = (this.props.formData || [])[this.state.activeIdx];
1019
+ const { areaField } = utils_2.getUiOptions(this.props.uiSchema);
1020
+ if (!item || !areaField) {
1021
+ return;
1022
+ }
1023
+ let area = item[areaField];
1024
+ if (area instanceof Array) {
1025
+ area = area[0];
1026
+ }
1027
+ const geometries = this.getGeometries();
1028
+ if (geometries.length === 0 && area && area.length > 0) {
1029
+ this.props.formContext.apiClient.fetch(`/areas/${area}`, undefined, undefined).then((result) => {
1030
+ this.map.geocode(result.name, undefined, 8);
1031
+ });
1032
+ }
1033
+ };
1034
+ this.computeArea = () => {
1035
+ const { activeIdx } = this.state;
1036
+ if (activeIdx === undefined)
1037
+ return;
1038
+ let { computeAreaField, areaInHectares } = utils_2.getUiOptions(this.props.uiSchema);
1039
+ const { formData } = this.props;
1040
+ if (!computeAreaField)
1041
+ return;
1042
+ const geometries = this.getGeometries();
1043
+ const polygonsArea = geometries
1044
+ .filter(({ type }) => type === "Polygon")
1045
+ .map(({ coordinates }) => coordinates[0].slice(1).map(c => L.latLng(c.slice(0).reverse())))
1046
+ .reduce((area, latLngs) => area + L.GeometryUtil.geodesicArea(latLngs), 0);
1047
+ const circlesArea = geometries
1048
+ .filter(({ type, radius }) => type === "Point" && radius)
1049
+ .reduce((_area, { radius }) => _area + (Math.PI) * (radius * radius), 0);
1050
+ const sumArea = polygonsArea + circlesArea;
1051
+ const area = sumArea === 0
1052
+ ? undefined
1053
+ : Math.round(areaInHectares ? sumArea / 10000 : sumArea);
1054
+ const currentArea = utils_2.parseJSONPointer(formData[activeIdx], computeAreaField, true);
1055
+ currentArea !== area && this.props.onChange(utils_2.updateSafelyWithJSONPointer(formData, area, `/${activeIdx}/${computeAreaField}`));
1056
+ };
1057
+ this.getContainer = () => react_dom_1.findDOMNode(this.refs._stretch);
1058
+ this.onResize = () => this.refs.map.map.map.invalidateSize({ debounceMoveend: true });
1059
+ this.onPopupClose = () => {
1060
+ // Move popup content back to the React container so React won't crash.
1061
+ if (this.refs.popupContainer && this.refs.popup.refs.popup) {
1062
+ react_dom_1.findDOMNode(this.refs.popupContainer).appendChild(this.refs.popup.refs.popup);
1063
+ }
1064
+ this.setState({ popupIdx: undefined });
1065
+ };
1066
+ this.onFocusGrab = () => this.setState({ focusGrabbed: true });
1067
+ this.onFocusRelease = () => this.setState({ focusGrabbed: false });
1068
+ this.onOptionsChanged = (options) => this.setState({ mapOptions: Object.assign(Object.assign({}, this.state.mapOptions), options) }, () => {
1069
+ if (this._tileLayerNameOnNextTickCallback) {
1070
+ this._tileLayerNameOnNextTickCallback();
1071
+ this._tileLayerNameOnNextTickCallback = undefined;
1072
+ }
1073
+ });
1074
+ this.getAlignmentAnchor = () => this.refs._stretch;
1075
+ this.onEnterViewPort = () => {
1076
+ this.afterActiveChange(this.state.activeIdx, !!"initial call");
1077
+ };
1078
+ this.getMapOptions = () => {
1079
+ const options = utils_2.getUiOptions(this.props.uiSchema);
1080
+ let _options = merge.all([
1081
+ { clickBeforeZoomAndPan: true },
1082
+ (options.mapOptions || {}),
1083
+ (this.getOptions(options) || {}),
1084
+ (this.state.mapOptions || {})
1085
+ ]);
1086
+ const changes = {};
1087
+ if (options.createOnLocate && !_options.locate) {
1088
+ changes.locate = [this.onLocate];
1089
+ }
1090
+ const { readonly, disabled } = this.props;
1091
+ if (readonly || disabled) {
1092
+ if (utils_2.isObject(_options.draw)) {
1093
+ changes.draw = Object.assign(Object.assign({}, _options.draw), { editable: false });
1094
+ }
1095
+ if (_options.data) {
1096
+ if (_options.data instanceof Array) {
1097
+ changes.data = _options.data.map(d => (Object.assign(Object.assign({}, d), { editable: false })));
1098
+ }
1099
+ else if (utils_2.isObject(_options.data)) {
1100
+ changes.data = Object.assign(Object.assign({}, _options.data), { editable: false });
1101
+ }
1102
+ }
1103
+ }
1104
+ if (Object.keys(changes).length) {
1105
+ _options = Object.assign(Object.assign({}, _options), changes);
1106
+ }
1107
+ return _options;
1108
+ };
1109
+ this.onActiveChange = (idx, prop, callback) => {
1110
+ this.nestedHandledActiveChange = true;
1111
+ this.setState({ activeIdx: idx }, () => {
1112
+ if (!callback)
1113
+ return;
1114
+ callback();
1115
+ });
1116
+ };
1117
+ this.customAdd = () => () => {
1118
+ const nextActive = this.props.formData.length;
1119
+ this.props.onChange(ArrayField_1.onArrayFieldChange([...this.props.formData, utils_2.getDefaultFormState(this.props.schema.items)], this.props));
1120
+ this.setState({ activeIdx: nextActive });
1121
+ };
1122
+ this.mapKeyFunctions = {
1123
+ splitLineTransectByMeters: () => {
1124
+ this.map.splitLTByMeters(this.state.activeIdx);
1125
+ }
1126
+ };
1127
+ this.getPopup = (options, openPopupCallback) => {
1128
+ if (!this.refs.popup)
1129
+ return;
1130
+ this.setState({ popupIdx: this.filterPopupOptions(options) }, () => {
1131
+ this.refs.popup && utils_2.hasData(this.getPopupData(options)) && openPopupCallback(this.refs.popup.refs.popup);
1132
+ });
1133
+ };
1134
+ this.popupStrategies = {
1135
+ lolifeUnit: (formData) => {
1136
+ const { nestType, indirectObservationType, identifications } = formData;
1137
+ if (nestType) {
1138
+ return { value: this.props.formContext.translations.NestObservation };
1139
+ }
1140
+ else if (indirectObservationType) {
1141
+ return { value: this.props.formContext.translations.TraceObservation };
1142
+ }
1143
+ else if (identifications) {
1144
+ return { value: this.props.formContext.translations.Observation };
1145
+ }
1146
+ }
1147
+ };
1148
+ this.getFeaturePopupData = (options) => {
1149
+ if (!options)
1150
+ return [];
1151
+ const { popupFields } = utils_2.getUiOptions(this.props.uiSchema);
1152
+ const formData = this.getFormDataForPopup(options);
1153
+ let data = [];
1154
+ popupFields.forEach(({ field: col, template, value: _value, title: _title, if: _if, strategy }) => {
1155
+ let value, title;
1156
+ if (strategy) {
1157
+ const strategyResult = this.popupStrategies[strategy](formData);
1158
+ if (strategyResult) {
1159
+ value = strategyResult.value;
1160
+ title = strategyResult.title;
1161
+ }
1162
+ }
1163
+ else if (_value) {
1164
+ value = _value;
1165
+ title = _title;
1166
+ }
1167
+ else if (col) {
1168
+ if (this.parsePopupPointer) {
1169
+ col = this.parsePopupPointer(col, options);
1170
+ }
1171
+ const _formData = utils_2.parseJSONPointer(formData, col);
1172
+ const schema = utils_2.parseSchemaFromFormDataPointer(this.props.schema.items || this.props.schema, col);
1173
+ const uiSchema = utils_2.parseUiSchemaFromFormDataPointer(this.props.uiSchema.items || this.props.uiSchema, col);
1174
+ title = schema.title;
1175
+ value = utils_2.formatValue(Object.assign(Object.assign({}, this.props), { formData: _formData, schema, uiSchema }));
1176
+ }
1177
+ if (!utils_2.isEmptyString(value)) {
1178
+ let result;
1179
+ if (_if) {
1180
+ result = ["dataIdx", "featureIdx"].every(opt => !(opt in _if) || options[opt] === _if[opt]);
1181
+ if (_if.reverse) {
1182
+ result = !result;
1183
+ }
1184
+ }
1185
+ if (!_if || result) {
1186
+ data.push({ title, template, value });
1187
+ }
1188
+ }
1189
+ });
1190
+ return data;
1191
+ };
1192
+ this.onLocate = (latlng, radius) => {
1193
+ this.location = latlng ? { latlng, radius } : undefined;
1194
+ this.onLocateOrAddNew();
1195
+ };
1196
+ this.onLocateOrAddNew = () => {
1197
+ if (!this.location)
1198
+ return;
1199
+ const { latlng, radius } = this.location;
1200
+ const { createOnLocate } = utils_2.getUiOptions(this.props.uiSchema);
1201
+ if (!createOnLocate)
1202
+ return;
1203
+ const geometry = this.getGeometry(this.props.formData);
1204
+ if (this.props.formData.length === 0 || (!geometry || !Object.keys(geometry).length)) {
1205
+ let geometry = undefined;
1206
+ if (createOnLocate === "marker") {
1207
+ geometry = { type: "Point", coordinates: [latlng.lng, latlng.lat] };
1208
+ }
1209
+ if (createOnLocate === "circle") {
1210
+ geometry = { type: "Point", coordinates: [latlng.lng, latlng.lat], radius };
1211
+ }
1212
+ this.map.addFeatureToDraw({
1213
+ type: "Feature",
1214
+ properties: {},
1215
+ geometry
1216
+ });
1217
+ }
1218
+ };
1219
+ this.props.formContext.services.settings.bind(this, props);
1220
+ this._context = Context_1.default(`${props.formContext.contextId}_MAP_CONTAINER`);
1221
+ this._context.featureIdxsToItemIdxs = {};
1222
+ this._context.setState = (state, callback) => this.setState(state, callback);
1223
+ const initialState = Object.assign(Object.assign({}, (this.state || {})), { activeIdx: (this.props.formData || []).length === 1 ? 0 : undefined });
1224
+ const options = utils_2.getUiOptions(props.uiSchema);
1225
+ if ((this.props.formData || []).length && "activeIdx" in options)
1226
+ initialState.activeIdx = options.activeIdx;
1227
+ this.state = Object.assign(Object.assign({}, initialState), (this.state || {}));
1228
+ this.getDraftStyle = this.getDraftStyle.bind(this);
1229
+ }
1230
+ componentDidMount() {
1231
+ if (super.componentDidMount)
1232
+ super.componentDidMount();
1233
+ this.setState({ mounted: true });
1234
+ this.props.formContext.services.keyHandler.addKeyHandler(`${this.props.idSchema.$id}`, this.mapKeyFunctions);
1235
+ this.map = this.refs.map.refs.map.map;
1236
+ this._setActiveEventHandler = idx => {
1237
+ this.setState({ activeIdx: idx });
1238
+ };
1239
+ this._zoomToDataEventHandler = () => {
1240
+ this._zoomToDataOnNextTick = true;
1241
+ };
1242
+ this._tileLayersEventHandler = (tileLayerOptions, callback) => {
1243
+ this._tileLayerNameOnNextTick = tileLayerOptions;
1244
+ this._tileLayerNameOnNextTickCallback = callback;
1245
+ };
1246
+ this.props.formContext.services.customEvents.add(this.props.idSchema.$id, "activeIdx", this._setActiveEventHandler);
1247
+ this.props.formContext.services.customEvents.add(this.props.idSchema.$id, "zoomToData", this._zoomToDataEventHandler);
1248
+ this.props.formContext.services.customEvents.add(this.props.idSchema.$id, "tileLayers", this._tileLayersEventHandler);
1249
+ if (this.state.activeIdx !== undefined) {
1250
+ this.afterActiveChange(this.state.activeIdx, !!"initial call");
1251
+ }
1252
+ }
1253
+ afterActiveChange(idx) {
1254
+ super.afterActiveChange && super.afterActiveChange(idx);
1255
+ this.onLocateOrAddNew();
1256
+ }
1257
+ componentWillUnmount() {
1258
+ this.setState({ mounted: false });
1259
+ this.props.formContext.services.keyHandler.removeKeyHandler(`${this.props.idSchema.$id}`, this.mapKeyFunctions);
1260
+ this.props.formContext.services.customEvents.remove(this.props.idSchema.$id, "activeIdx", this._setActiveEventHandler);
1261
+ this.props.formContext.services.customEvents.remove(this.props.idSchema.$id, "zoomToData", this._zoomToDataEventHandler);
1262
+ this.props.formContext.services.customEvents.remove(this.props.idSchema.$id, "tileLayers", this._tileLayersEventHandler);
1263
+ }
1264
+ componentDidUpdate(...params) {
1265
+ if (super.componentDidUpdate)
1266
+ super.componentDidUpdate(...params);
1267
+ const [prevProps, prevState] = params; // eslint-disable-line no-unused-vars
1268
+ if (prevState.activeIdx !== this.state.activeIdx) {
1269
+ if (!this.nestedHandledActiveChange && this.state.activeIdx !== undefined) {
1270
+ const { idToFocusAfterNavigate, idToScrollAfterNavigate } = utils_2.getUiOptions(this.props.uiSchema);
1271
+ this.props.formContext.utils.focusAndScroll(idToFocusAfterNavigate || `${this.props.idSchema.$id}_${this.state.activeIdx}`, idToScrollAfterNavigate);
1272
+ }
1273
+ this.nestedHandledActiveChange = false;
1274
+ this.afterActiveChange(this.state.activeIdx);
1275
+ }
1276
+ if (this.refs.stretch) {
1277
+ const { resizeTimeout } = utils_2.getUiOptions(this.props.uiSchema);
1278
+ if (resizeTimeout) {
1279
+ this.props.formContext.setTimeout(this.refs.stretch.update, resizeTimeout);
1280
+ }
1281
+ else {
1282
+ this.refs.stretch.update();
1283
+ }
1284
+ }
1285
+ if (this._zoomToDataOnNextTick) {
1286
+ this._zoomToDataOnNextTick = false;
1287
+ this.map.zoomToData();
1288
+ }
1289
+ if (this._tileLayerNameOnNextTick) {
1290
+ const tileLayerName = this._tileLayerNameOnNextTick;
1291
+ this._tileLayerNameOnNextTick = false;
1292
+ this.map.setTileLayerByName(tileLayerName);
1293
+ }
1294
+ this.computeArea(prevProps);
1295
+ }
1296
+ _getPlaceholderStyle() {
1297
+ return {
1298
+ color: "#999999",
1299
+ fillOpacity: 0,
1300
+ weight: 8
1301
+ };
1302
+ }
1303
+ getSchemas() {
1304
+ if (super.getSchemas)
1305
+ return super.getSchemas();
1306
+ return this.props;
1307
+ }
1308
+ render() {
1309
+ const { registry: { fields: { SchemaField } } } = this.props;
1310
+ let { uiSchema, errorSchema, schema } = this.getSchemas();
1311
+ const options = utils_2.getUiOptions(this.props.uiSchema);
1312
+ const { popupFields, geometryField, topOffset, bottomOffset, belowFields, propsToPassToInlineSchema = [], emptyHelp, passActiveIdxToBelow = true } = options;
1313
+ let { belowUiSchemaRoot = {}, inlineUiSchemaRoot = {}, idToFocusAfterNavigate, idToScrollAfterNavigate } = options;
1314
+ const { activeIdx } = this.state;
1315
+ const activeIdxProps = {
1316
+ activeIdx,
1317
+ onActiveChange: this.onActiveChange,
1318
+ idToFocusAfterNavigate,
1319
+ idToScrollAfterNavigate
1320
+ };
1321
+ uiSchema = utils_2.getInnerUiSchema(uiSchema);
1322
+ if (utils_2.getUiOptions(this.props.uiSchema).buttons) {
1323
+ uiSchema = Object.assign(Object.assign({}, uiSchema), { "ui:options": Object.assign(Object.assign({}, uiSchema["ui:options"]), { buttons: [...(uiSchema["ui:options"].buttons || []), ...utils_2.getUiOptions(this.props.uiSchema).buttons] }) });
1324
+ }
1325
+ let mapOptions = this.getMapOptions();
1326
+ const mapSizes = options.mapSizes || utils_2.getBootstrapCols(6);
1327
+ const schemaSizes = ["lg", "md", "sm", "xs"].reduce((sizes, size) => {
1328
+ sizes[size] = 12 - mapSizes[size] || 12;
1329
+ return sizes;
1330
+ }, {});
1331
+ const getChildProps = () => {
1332
+ return {
1333
+ schema: schema.items,
1334
+ uiSchema: uiSchema.items || {},
1335
+ idSchema: this.props.registry.schemaUtils.toIdSchema(schema.items, `${this.props.idSchema.$id}_${activeIdx}`),
1336
+ formData: (this.props.formData || [])[activeIdx],
1337
+ errorSchema: this.props.errorSchema[activeIdx] || {}
1338
+ };
1339
+ };
1340
+ const putChildsToParents = (props, key) => {
1341
+ if (!this.onChangeFor) {
1342
+ this.onChangeFor = {};
1343
+ }
1344
+ if (!this.onChangeFor[key]) {
1345
+ this.onChangeFor[key] = formData => {
1346
+ this.props.onChange(formData.map((item, idx) => {
1347
+ return Object.assign(Object.assign({}, (this.props.formData[idx] || utils_2.getDefaultFormState(this.props.schema.items))), item);
1348
+ }));
1349
+ };
1350
+ }
1351
+ return Object.assign(Object.assign({}, this.props), { schema: Object.assign(Object.assign({}, schema), { items: props.schema }), uiSchema: Object.assign(Object.assign({}, uiSchema), { items: props.uiSchema }), onChange: this.onChangeFor[key] });
1352
+ };
1353
+ const defaultProps = Object.assign(Object.assign({}, this.props), { schema, uiSchema });
1354
+ const overrideProps = propsToPassToInlineSchema.reduce((_props, field) => {
1355
+ _props[field] = this.props[field];
1356
+ return _props;
1357
+ }, {});
1358
+ const childProps = getChildProps();
1359
+ const inlineSchemaProps = putChildsToParents(NestField_1.getPropsForFields(childProps, Object.keys(schema.items.properties).filter(field => !(belowFields || []).includes(field))));
1360
+ const belowSchemaProps = belowFields ? putChildsToParents(NestField_1.getPropsForFields(childProps, belowFields)) : null;
1361
+ const inlineItemsUiSchema = Object.assign(Object.assign({}, uiSchema.items), inlineSchemaProps.uiSchema.items);
1362
+ let inlineUiSchema = Object.assign({}, inlineSchemaProps.uiSchema);
1363
+ if (inlineUiSchemaRoot) {
1364
+ inlineUiSchema = Object.assign(Object.assign({}, inlineUiSchema), inlineUiSchemaRoot);
1365
+ inlineUiSchema.items = Object.assign(Object.assign({}, inlineItemsUiSchema), (inlineUiSchemaRoot.items || {}));
1366
+ }
1367
+ else {
1368
+ inlineUiSchema.items = inlineItemsUiSchema;
1369
+ }
1370
+ let belowUiSchema = belowSchemaProps ? Object.assign(Object.assign({}, belowSchemaProps.uiSchema), belowUiSchemaRoot) : {};
1371
+ inlineUiSchema = Object.assign(Object.assign({}, inlineUiSchema), { "ui:options": Object.assign(Object.assign({}, (inlineUiSchema["ui:options"] || {})), activeIdxProps) });
1372
+ belowUiSchema = Object.assign(Object.assign({}, belowUiSchema), { "ui:options": Object.assign(Object.assign({}, (belowUiSchema["ui:options"] || {})), (passActiveIdxToBelow ? activeIdxProps : {})) });
1373
+ if (!belowUiSchema.items) {
1374
+ belowUiSchema.items = {};
1375
+ }
1376
+ if (!belowUiSchema.items["ui:options"]) {
1377
+ belowUiSchema.items["ui:options"] = {};
1378
+ }
1379
+ belowUiSchema.items["ui:options"].reserveId = false;
1380
+ const { buttonsPath, addButtonPath, showErrors = true } = utils_2.getUiOptions(this.props.uiSchema);
1381
+ if (addButtonPath)
1382
+ console.warn("addButtonPath option for MapArrayField is deprecated - use buttonsPath instead!");
1383
+ let _buttonsPath = buttonsPath || addButtonPath;
1384
+ const prependAddButton = (buttons) => {
1385
+ const addButton = buttons.find(({ fn }) => fn === "add");
1386
+ return [
1387
+ ...buttons.filter(button => button !== addButton),
1388
+ Object.assign(Object.assign({}, (addButton || {})), { fn: this.customAdd, fnName: "add", glyph: "plus", id: this.props.idSchema.$id })
1389
+ ];
1390
+ };
1391
+ let buttons = undefined;
1392
+ let renderButtonsBelow = false;
1393
+ if ((mapOptions.emptyMode || activeIdx !== undefined) && options.buttons) {
1394
+ if (_buttonsPath) {
1395
+ buttons = prependAddButton(options.buttons);
1396
+ belowUiSchema = utils_2.injectButtons(belowUiSchema, buttons, _buttonsPath);
1397
+ inlineUiSchema["ui:options"].renderAdd = false;
1398
+ }
1399
+ else if (options.renderButtonsBelow) {
1400
+ buttons = prependAddButton(options.buttons);
1401
+ inlineUiSchema["ui:options"].renderAdd = false;
1402
+ renderButtonsBelow = true;
1403
+ }
1404
+ else {
1405
+ buttons = options.buttons;
1406
+ }
1407
+ }
1408
+ if (activeIdx === undefined || (!_buttonsPath && !renderButtonsBelow)) {
1409
+ inlineUiSchema["ui:options"].buttons = options.buttons || [];
1410
+ }
1411
+ const inlineSchema = React.createElement(SchemaField, Object.assign({}, defaultProps, inlineSchemaProps, { uiSchema: inlineUiSchema }, overrideProps));
1412
+ const belowSchema = belowFields ? React.createElement(SchemaField, Object.assign({}, this.props, belowSchemaProps, { uiSchema: belowUiSchema })) : null;
1413
+ buttons = buttons && (!_buttonsPath || mapOptions.emptyMode)
1414
+ ? buttons.map(button => ArrayFieldTemplate_1.getButton(button, {
1415
+ canAdd: mapOptions.emptyMode ? (button.fn !== "add" && button.fnName !== "add") : true,
1416
+ uiSchema: this.props.uiSchema,
1417
+ idSchema: this.props.idSchema,
1418
+ formData: this.props.formData,
1419
+ formContext: this.props.formContext,
1420
+ disabled: this.props.disabled,
1421
+ readonly: this.props.readonly,
1422
+ })).filter(button => button)
1423
+ : undefined;
1424
+ const _errors = errorSchema && utils_2.parseJSONPointer(errorSchema[activeIdx] || {}, geometryField);
1425
+ const errors = _errors
1426
+ ? _errors.__errors.map(utils_2.formatErrorMessage)
1427
+ : null;
1428
+ const errorId = geometryField && geometryField[0] === "/" ? geometryField.replace(/\//g, "_") : `_${geometryField}`;
1429
+ const wholeErrorId = `${this.props.idSchema.$id}_${activeIdx}${errorId}`;
1430
+ const mapPropsToPass = Object.assign({ formContext: this.props.formContext, onPopupClose: this.onPopupClose, markerPopupOffset: 45, featurePopupOffset: 5, popupOnHover: true, onFocusGrab: this.onFocusGrab, onFocusRelease: this.onFocusRelease, panel: errors && errors.length && showErrors ? {
1431
+ header: this.props.formContext.translations.Error,
1432
+ panelTextContent: React.createElement("div", null, errors),
1433
+ variant: "danger",
1434
+ id: `laji-form-error-container-${wholeErrorId}`
1435
+ } : null, draw: false, zoomToData: true, onOptionsChanged: this.onOptionsChanged, fullscreenable: true, help: options.help }, mapOptions);
1436
+ const map = (React.createElement(MapComponent, Object.assign({ ref: "map" }, mapPropsToPass)));
1437
+ const wrapperProps = {
1438
+ getContainer: this.getContainer,
1439
+ topOffset: topOffset === undefined ? this.props.formContext.topOffset : topOffset,
1440
+ bottomOffset: bottomOffset === undefined ? this.props.formContext.bottomOffset : bottomOffset,
1441
+ onResize: this.onResize,
1442
+ mounted: this.state.mounted,
1443
+ className: this.state.focusGrabbed ? "pass-block" : "",
1444
+ minHeight: utils_2.getUiOptions(this.props.uiSchema).minHeight,
1445
+ onEnterViewPort: this.onEnterViewPort,
1446
+ enterViewPortTreshold: 200
1447
+ };
1448
+ const wrappedMap = (React.createElement(components_1.Stretch, Object.assign({}, wrapperProps, { ref: "stretch" }), map));
1449
+ const TitleFieldTemplate = utils_3.getTemplate("TitleFieldTemplate", this.props.registry, utils_2.getUiOptions(this.props.uiSchema));
1450
+ const { Popover, Row, Col, ButtonToolbar } = this.context.theme;
1451
+ return (React.createElement(React.Fragment, null,
1452
+ React.createElement(Row, null,
1453
+ React.createElement(Col, Object.assign({}, mapSizes), wrappedMap),
1454
+ React.createElement(Col, Object.assign({}, schemaSizes, { ref: "_stretch" }), mapOptions.emptyMode ?
1455
+ (!emptyHelp && (!buttons || !buttons.length) ? null :
1456
+ React.createElement(Popover, { placement: "right", id: `${this.props.idSchema.$id}-help` }, React.createElement("div", null,
1457
+ emptyHelp,
1458
+ buttons && buttons.length ? ` ${this.props.formContext.translations.or}` : null,
1459
+ buttons))) :
1460
+ inlineSchema)),
1461
+ popupFields ?
1462
+ React.createElement("div", { style: { display: "none" }, ref: "popupContainer" },
1463
+ React.createElement(Popup, { data: this.getPopupData(this.state.popupIdx), ref: "popup" })) : null,
1464
+ React.createElement(Row, null, mapOptions.emptyMode ? null : belowSchema),
1465
+ renderButtonsBelow && !mapOptions.emptyMode && buttons.length ? (React.createElement(Row, { className: "map-array-field-below-buttons" },
1466
+ React.createElement(TitleFieldTemplate, { title: utils_2.getUiOptions(uiSchema).buttonsTitle, schema: this.props.schema }),
1467
+ React.createElement(ButtonToolbar, null, buttons))) : null));
1468
+ }
1469
+ getDraftStyle() {
1470
+ if (super.getDraftStyle) {
1471
+ return super.getDraftStyle();
1472
+ }
1473
+ return { color: "#25B4CA", opacity: 1 };
1474
+ }
1475
+ filterPopupOptions({ dataIdx, featureIdx, feature }) {
1476
+ return { dataIdx, featureIdx, feature };
1477
+ }
1478
+ getPopupData(options) {
1479
+ if (super.getPopupData) {
1480
+ return super.getPopupData(options);
1481
+ }
1482
+ else {
1483
+ return this.getFeaturePopupData(options);
1484
+ }
1485
+ }
1486
+ getFormDataForPopup(options) {
1487
+ if (super.getFormDataForPopup) {
1488
+ return super.getFormDataForPopup(options);
1489
+ }
1490
+ else {
1491
+ return this.state.activeIdx !== undefined ? this.props.formData[this.state.activeIdx] : undefined;
1492
+ }
1493
+ }
1494
+ } // eslint-disable-line indent
1495
+ _MapArrayField.contextType = ReactContext_1.default;
1496
+ return _MapArrayField; // eslint-disable-line indent
1497
+ }
1498
+ class Popup extends React.Component {
1499
+ render() {
1500
+ const { data } = this.props;
1501
+ return data && data.length &&
1502
+ React.createElement("ul", { ref: "popup", className: "map-data-tooltip" }, data.map(({ value, title, template }, i) => {
1503
+ switch (template) {
1504
+ case "title":
1505
+ return React.createElement("li", { key: title || i },
1506
+ React.createElement("strong", null, Array.isArray(value) ? value.join(", ") : value));
1507
+ case "description":
1508
+ return React.createElement("li", { key: title || i },
1509
+ React.createElement("i", null, Array.isArray(value) ? value.join(", ") : value));
1510
+ default:
1511
+ return React.createElement("li", { key: title || i },
1512
+ React.createElement("strong", null,
1513
+ title,
1514
+ ":"),
1515
+ " ",
1516
+ Array.isArray(value) ? value.join(", ") : value);
1517
+ }
1518
+ }));
1519
+ }
1520
+ }
1521
+ class MapComponent extends React.Component {
1522
+ constructor(props) {
1523
+ super(props);
1524
+ this.tileLayerChange = ({ tileLayers }) => {
1525
+ this.setState({ mapOptions: Object.assign(Object.assign({}, this.state.mapOptions), { tileLayers }) });
1526
+ };
1527
+ this.overlaysChange = ({ overlayNames }) => {
1528
+ this.setState({ mapOptions: Object.assign(Object.assign({}, this.state.mapOptions), { overlayNames }) });
1529
+ };
1530
+ this.tileLayerOpacityChangeEnd = ({ tileLayerOpacity }) => {
1531
+ this.setState({ mapOptions: Object.assign(Object.assign({}, this.state.mapOptions), { tileLayerOpacity }) });
1532
+ };
1533
+ this.locateToggle = ({ locate }) => {
1534
+ this.setState({ mapOptions: Object.assign(Object.assign({}, this.state.mapOptions), { locate }) });
1535
+ };
1536
+ this.grabFocus = () => {
1537
+ this.props.formContext.services.blocker.push();
1538
+ this.setState({ focusGrabbed: true }, () => {
1539
+ if (this.props.onFocusGrab)
1540
+ this.props.onFocusGrab();
1541
+ });
1542
+ };
1543
+ this.releaseFocus = () => {
1544
+ this.props.formContext.services.blocker.push();
1545
+ this.setState({ focusGrabbed: false }, () => {
1546
+ if (this.props.onFocusRelease)
1547
+ this.props.onFocusRelease();
1548
+ });
1549
+ };
1550
+ this.showPanel = (options) => {
1551
+ this.setState(Object.assign({ panel: true }, options));
1552
+ };
1553
+ this.hidePanel = () => {
1554
+ this.setState({ panel: false });
1555
+ };
1556
+ this.showHelp = () => {
1557
+ this.setState({ showHelp: true });
1558
+ };
1559
+ this.hideHelp = () => {
1560
+ this.setState({ showHelp: false });
1561
+ };
1562
+ this.setMapState = (options, callback) => {
1563
+ this._callback = callback;
1564
+ this.setState({ mapOptions: options });
1565
+ };
1566
+ this.setOnUpdateMap = (fn) => {
1567
+ this._permaCallback = fn;
1568
+ };
1569
+ this.state = { mapOptions: {} };
1570
+ this.mainContext = Context_1.default(props.formContext.contextId);
1571
+ this._context = Context_1.default(`${props.formContext.contextId}_MAP`);
1572
+ this._context.grabFocus = this.grabFocus;
1573
+ this._context.releaseFocus = this.releaseFocus;
1574
+ this._context.showPanel = this.showPanel;
1575
+ this._context.hidePanel = this.hidePanel;
1576
+ this._context.setMapState = this.setMapState;
1577
+ this._context.setOnUpdateMap = this.setOnUpdateMap;
1578
+ }
1579
+ componentDidMount() {
1580
+ this.map = this.refs.map.map;
1581
+ const { map } = this.map;
1582
+ this._context.map = this.map;
1583
+ map.on("tileLayersChange", this.tileLayerChange);
1584
+ map.on("locateToggle", this.locateToggle);
1585
+ }
1586
+ componentWillUnmount() {
1587
+ const { map } = this.map;
1588
+ if (!map)
1589
+ return;
1590
+ map.off("tileLayersChange", this.tileLayerChange);
1591
+ map.off("locateToggle", this.locateToggle);
1592
+ }
1593
+ componentDidUpdate(prevProps, prevState) {
1594
+ if (this._callback)
1595
+ this._callback();
1596
+ this._callback = undefined;
1597
+ if (this.props.onOptionsChanged && ["tileLayers", "locate"].some(name => !equals(...[this.state, prevState].map(state => state.mapOptions[name])))) {
1598
+ this.props.onOptionsChanged(this.state.mapOptions);
1599
+ }
1600
+ if (this._permaCallback)
1601
+ this._permaCallback();
1602
+ }
1603
+ render() {
1604
+ const _a = this.props, { panel, onFocusGrab, onFocusRelease, onOptionsChanged } = _a, mapOptions = __rest(_a, ["panel", "onFocusGrab", "onFocusRelease", "onOptionsChanged"]); // eslint-disable-line
1605
+ const { Modal } = this.context.theme;
1606
+ const controlledPanel = panel ?
1607
+ React.createElement(MapPanel, { id: panel.id, variant: panel.variant || undefined, buttonThemeRole: panel.buttonThemeRole, header: panel.header, text: panel.panelTextContent })
1608
+ : null;
1609
+ return (React.createElement("div", { className: "laji-form-map-container" + (this.state.focusGrabbed ? " pass-block" : "") },
1610
+ controlledPanel,
1611
+ this.state.panel &&
1612
+ React.createElement(MapPanel, { id: panel.id, show: this.state.panel, text: this.state.panelTextContent, onClick: this.state.panelButtonOnClick, buttonText: this.state.panelButtonContent, buttonThemeRole: this.state.panelButtonBsStyle }),
1613
+ this.state.showHelp &&
1614
+ React.createElement(Modal, { dialogClassName: "laji-form", show: true, onHide: this.hideHelp },
1615
+ React.createElement(Modal.Header, { closeButton: true }),
1616
+ React.createElement(Modal.Body, null,
1617
+ React.createElement("span", { dangerouslySetInnerHTML: { __html: mapOptions.help } }))),
1618
+ React.createElement(Map, Object.assign({ className: this.props.className, style: this.props.style, ref: "map", showHelp: this.showHelp, hideHelp: this.hideHelp, formContext: this.props.formContext }, Object.assign(Object.assign({}, mapOptions), this.state.mapOptions)))));
1619
+ }
1620
+ }
1621
+ exports.MapComponent = MapComponent;
1622
+ MapComponent.contextType = ReactContext_1.default;
1623
+ class Map extends React.Component {
1624
+ constructor(props) {
1625
+ super(props);
1626
+ this.getMapOptions = (props) => {
1627
+ const { className, // eslint-disable-line @typescript-eslint/no-unused-vars
1628
+ style, // eslint-disable-line @typescript-eslint/no-unused-vars
1629
+ hidden, // eslint-disable-line @typescript-eslint/no-unused-vars
1630
+ singleton, // eslint-disable-line @typescript-eslint/no-unused-vars
1631
+ emptyMode, // eslint-disable-line @typescript-eslint/no-unused-vars
1632
+ onComponentDidMount, // eslint-disable-line @typescript-eslint/no-unused-vars
1633
+ fullscreenable, // eslint-disable-line @typescript-eslint/no-unused-vars
1634
+ formContext, // eslint-disable-line @typescript-eslint/no-unused-vars
1635
+ controlSettings } = props, // eslint-disable-line @typescript-eslint/no-unused-vars
1636
+ mapOptions = __rest(props, ["className", "style", "hidden", "singleton", "emptyMode", "onComponentDidMount", "fullscreenable", "formContext", "controlSettings"]);
1637
+ return mapOptions;
1638
+ };
1639
+ this.getEnhancedMapOptions = (props) => {
1640
+ const mapOptions = this.getMapOptions(props);
1641
+ const { fullscreenable, help, formContext = {} } = props;
1642
+ if (fullscreenable) {
1643
+ mapOptions.controls = Object.assign({ fullscreen: true }, (utils_2.isObject(mapOptions.controls)
1644
+ ? mapOptions.controls
1645
+ : {}));
1646
+ }
1647
+ if (help) {
1648
+ mapOptions.customControls = [
1649
+ ...(mapOptions.customControls || []),
1650
+ {
1651
+ iconCls: "glyphicon glyphicon-question-sign",
1652
+ fn: this.props.showHelp,
1653
+ position: "bottomright",
1654
+ text: formContext.translations.Instructions
1655
+ }
1656
+ ];
1657
+ }
1658
+ mapOptions.lang = mapOptions.lang || formContext.lang;
1659
+ mapOptions.googleApiKey = formContext.googleApiKey;
1660
+ mapOptions.rootElem = this.refs.map;
1661
+ const { lajiGeoServerAddress } = props.formContext;
1662
+ if (lajiGeoServerAddress) {
1663
+ mapOptions.lajiGeoServerAddress = lajiGeoServerAddress;
1664
+ }
1665
+ return mapOptions;
1666
+ };
1667
+ this.setMapOptions = (prevOptions, options) => {
1668
+ if (!this.map) {
1669
+ return;
1670
+ }
1671
+ const mapOptions = this.getMapOptions(options);
1672
+ const prevMapOptions = this.getMapOptions(prevOptions);
1673
+ Object.keys(mapOptions).forEach(key => {
1674
+ switch (key) {
1675
+ case "draw": // More optimal way of updating draw data than setting the draw option
1676
+ if (!equals(mapOptions.draw, prevMapOptions.draw)) {
1677
+ this.map.updateDrawData(mapOptions.draw);
1678
+ }
1679
+ break;
1680
+ case "rootElem": // deeqEquals on DOM node causes maximum call stack size exceeding.
1681
+ if (mapOptions[key] !== prevMapOptions[key]) {
1682
+ this.map.setOption(key, mapOptions[key]);
1683
+ }
1684
+ break;
1685
+ default:
1686
+ if (!equals(mapOptions[key], prevMapOptions[key])) {
1687
+ this.map.setOption(key, mapOptions[key]);
1688
+ if (this.props.singleton && mapOptions.zoomToData && key === "data") {
1689
+ this.map.zoomToData(mapOptions.zoomToData);
1690
+ }
1691
+ }
1692
+ }
1693
+ });
1694
+ };
1695
+ this.initializeMap = (props) => {
1696
+ const mapOptions = this.getEnhancedMapOptions(props);
1697
+ if (props.singleton) {
1698
+ const singletonMapService = props.formContext.services.singletonMap;
1699
+ this.map = singletonMapService.grab(this, mapOptions);
1700
+ this.setMapOptions(this.map.getOptions(), mapOptions);
1701
+ }
1702
+ else {
1703
+ this.map = new laji_map_1.default(mapOptions);
1704
+ }
1705
+ this.map.map.invalidateSize();
1706
+ if (props.onComponentDidMount)
1707
+ props.onComponentDidMount(this.map);
1708
+ };
1709
+ this.state = {};
1710
+ }
1711
+ componentDidMount() {
1712
+ this.mounted = true;
1713
+ let options = Object.assign({}, this.props);
1714
+ // Backward compatibility for bad settings.
1715
+ ["tileLayerName", "overlayNames", "tileLayerOpacity"].forEach(prop => {
1716
+ if (prop in options && options[prop] === undefined) {
1717
+ options = utils_2.immutableDelete(options, prop);
1718
+ }
1719
+ });
1720
+ if (this.props.hidden) {
1721
+ return;
1722
+ }
1723
+ this.initializeMap(options);
1724
+ }
1725
+ componentWillUnmount() {
1726
+ if (this.props.singleton) {
1727
+ this.props.formContext.services.singletonMap.release(this);
1728
+ }
1729
+ else {
1730
+ this.map && this.map.destroy();
1731
+ }
1732
+ this.mounted = false;
1733
+ }
1734
+ componentDidUpdate(prevProps) {
1735
+ const { hidden, onComponentDidMount, singleton } = this.props;
1736
+ const props = __rest(this.props, []);
1737
+ if (!hidden && !this.map) {
1738
+ this.initializeMap(props);
1739
+ if (onComponentDidMount)
1740
+ onComponentDidMount(this.map);
1741
+ }
1742
+ if (!singleton || this.props.formContext.services.singletonMap.amOwner(this)) {
1743
+ if (this.map && prevProps.lineTransect && props.lineTransect && "activeIdx" in props.lineTransect) {
1744
+ this.map.setLTActiveIdx(props.lineTransect.activeIdx);
1745
+ }
1746
+ if (prevProps.lineTransect)
1747
+ delete props.lineTransect;
1748
+ this.setMapOptions(this.getEnhancedMapOptions(prevProps), this.getEnhancedMapOptions(this.props));
1749
+ }
1750
+ }
1751
+ render() {
1752
+ return (React.createElement(React.Fragment, null,
1753
+ React.createElement("div", { key: "map", className: "laji-form-map" + (this.props.className ? " " + this.props.className : ""), style: this.props.style, ref: "map" })));
1754
+ }
1755
+ }
1756
+ exports.Map = Map;
1757
+ Map.defaultProps = {
1758
+ tileLayerName: "maastokartta",
1759
+ availableTileLayerNamesBlacklist: ["pohjakartta"]
1760
+ };
1761
+ class MapPanel extends React.Component {
1762
+ render() {
1763
+ const { Panel } = this.context.theme;
1764
+ return (React.createElement(Panel, { variant: this.props.variant || undefined, className: "laji-form-popped", id: this.props.id },
1765
+ this.props.header ? (React.createElement(Panel.Heading, null, this.props.header)) : null,
1766
+ React.createElement(Panel.Body, null,
1767
+ this.props.text,
1768
+ this.props.buttonText ?
1769
+ React.createElement(components_1.Button, { variant: this.props.buttonThemeRole || "default", onClick: this.props.onClick }, this.props.buttonText) :
1770
+ null)));
1771
+ }
1772
+ }
1773
+ MapPanel.contextType = ReactContext_1.default;
1774
+ const saneOpacityRange = (opacity) => Math.min(1, Math.max(0, opacity || 0));
1775
+ const getFeatureStyleWithLowerOpacity = style => (Object.assign(Object.assign({}, style), { opacity: saneOpacityRange(style.opacity || 1 - 0.5), fillOpacity: saneOpacityRange(style.fillOpacity || 0.4 - 0.3) }));
1776
+ exports.getFeatureStyleWithLowerOpacity = getFeatureStyleWithLowerOpacity;
1777
+ const getFeatureStyleWithHighlight = style => {
1778
+ const color = style.color
1779
+ ? utils_1.combineColors(style.color, "#ffffff", 30)
1780
+ : undefined;
1781
+ return Object.assign(Object.assign({}, style), { color, fillOpacity: saneOpacityRange(style.fillOpacity || 0.4 + 0.4) });
1782
+ };
1783
+ exports.getFeatureStyleWithHighlight = getFeatureStyleWithHighlight;