]> git.openstreetmap.org Git - rails.git/blob - app/assets/javascripts/moderation_zone.js
Take expiry into account when checking moderation zones
[rails.git] / app / assets / javascripts / moderation_zone.js
1 //= require maplibre/map
2 //= require terra-draw/dist/terra-draw.umd
3 //= require terra-draw-maplibre-gl-adapter/dist/terra-draw-maplibre-gl-adapter.umd
4
5 /* globals terraDraw, terraDrawMaplibreGlAdapter */
6
7 $(function () {
8   const COORDINATES_FIELD_ID = "moderation_zone_zone";
9   const POSTGIS_LINE_POINTS_REGEXP = /[0-9-][ 0-9.,-]+/;
10   const SELECT_MODE_OPTIONS = {
11     flags: {
12       polygon: {
13         feature: {
14           draggable: false,
15           coordinates: {
16             midpoints: { draggable: true },
17             draggable: true,
18             snappable: true,
19             deletable: true,
20
21             // Disallow resizing of the geometry from a given origin.
22             resizable: false
23           }
24         }
25       }
26     }
27   };
28
29   const baseMap = new OSM.MapLibre.SecondaryMap();
30
31   baseMap.once("style.load", () => {
32     try {
33       const draw = createTerraDrawInstance(baseMap);
34       draw.on("finish", createTerraDrawFinishHandler(draw));
35       loadData(baseMap, draw);
36     } catch (e) {
37       // MapLibre is swallowing these exceptions silently, so I had
38       // to add this to know why my code was failing as I went.
39       console.error(e); // eslint-disable-line no-console
40       throw e;
41     }
42   });
43
44   function createTerraDrawInstance(map) {
45     return new terraDraw.TerraDraw({
46       adapter: new terraDrawMaplibreGlAdapter.TerraDrawMapLibreGLAdapter({
47         map,
48         lib: maplibregl
49       }),
50       modes: [
51         new terraDraw.TerraDrawPolygonMode(),
52         new terraDraw.TerraDrawSelectMode(SELECT_MODE_OPTIONS)
53       ]
54     });
55   }
56
57   function createTerraDrawFinishHandler(draw) {
58     return function (id, { mode, action }) {
59       if (mode === "polygon") {
60         draw.setMode("select");
61       } else if (mode === "select") {
62         // Nothing to do
63       } else {
64         throw new Error(`Unexpected mode "${mode}" (action: "${action}")`);
65       }
66
67       const feature = draw.getSnapshotFeature(id);
68       if (!feature) {
69         throw new Error(`Could not find feature with id ${id}`);
70       }
71
72       writeFormField(COORDINATES_FIELD_ID, feature);
73     };
74   }
75
76   function loadData(map, draw) {
77     const feature = readFormField(COORDINATES_FIELD_ID);
78     if (feature) {
79       startTerraDrawForEdit(draw, feature);
80     } else {
81       startTerraDrawForNew(draw);
82     }
83   }
84
85   function readFormField(fieldId) {
86     const target = document.getElementById(fieldId);
87     if (!target) {
88       throw new Error(`Could not find field #${fieldId}`);
89     }
90
91     const cleanValue = target.value.trim();
92     if (cleanValue === "") {
93       return null;
94     }
95
96     const match = POSTGIS_LINE_POINTS_REGEXP.exec(cleanValue);
97     if (!match) {
98       throw new Error(`Unexpected value in field #${fieldId}. Expected a WKT geometry, but found: ${target.value}`);
99     }
100
101     const coordinatesString = match[0];
102     const pointStrings = coordinatesString.split(",").map(s => s.trim());
103     const points = pointStrings.map(s => s.split(" ")).map(pairs => pairs.map(parseFloat));
104     return {
105       type: "Feature",
106       geometry: {
107         type: "Polygon",
108         coordinates: [points]
109       },
110       properties: {
111         mode: "polygon"
112       }
113     };
114   }
115
116   function startTerraDrawForEdit(draw, feature) {
117     draw.start();
118     draw.setMode("polygon");
119     const results = draw.addFeatures([feature]);
120     const invalidFeatures = [];
121     results.forEach(r => {
122       if (!r.valid) {
123         invalidFeatures.push(r);
124       }
125     });
126     if (invalidFeatures.length > 0) {
127       const invalidFeaturesString = invalidFeatures.map(JSON.stringify).join("\n");
128       throw new Error(`Failed to load features into TerraDraw:\n${invalidFeaturesString}`);
129     }
130     draw.setMode("select");
131   }
132
133   function startTerraDrawForNew(draw) {
134     draw.start();
135     draw.setMode("polygon");
136   }
137
138   function writeFormField(fieldId, feature) {
139     const coordinatesString = feature.geometry.coordinates[0]
140       .map(([lon, lat]) => `${lon} ${lat}`)
141       .join(",\n");
142     const target = document.getElementById(fieldId);
143     target.value = `POLYGON((\n${coordinatesString}\n))`;
144   }
145 });