@trailstash/ultra 5.0.2 → 5.0.4

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.
@@ -7,8 +7,8 @@ options:
7
7
  popupTemplate: >
8
8
  <h2>
9
9
  {{ type }}
10
- <a href="https://openhistoricalmap.org/{{ type }}/{{ id }}" target="_blank">{{ id }}</a>
11
- <a href="https://openhistoricalmap.org/edit?{{ type }}={{ id }}" target="_blank">✏️</a>
10
+ <a href="https://openstreetmap.org/{{ type }}/{{ id }}" target="_blank">{{ id }}</a>
11
+ <a href="https://openstreetmap.org/edit?{{ type }}={{ id }}" target="_blank">✏️</a>
12
12
  </h2>
13
13
  {% assign wikidata = tags["siren:model:wikidata"] ?? tags["model:wikidata"] %}
14
14
  {%- if wikidata %}
@@ -22,7 +22,12 @@ const defaultTemplate = `
22
22
  <br>
23
23
  {%- endfor %}
24
24
  `;
25
- const defaultContextBuilder = ({ properties }) => ({ properties });
25
+
26
+ const defaultContextBuilder = ({ properties, geometry }) => {
27
+ const context = { properties: structuredClone(properties) };
28
+ if (geometry.type === "Point") context.geometry = geometry;
29
+ return context;
30
+ };
26
31
 
27
32
  export class MapPopup extends HTMLElement {
28
33
  constructor() {
@@ -357,7 +357,15 @@ export class UltraMap extends HTMLElement {
357
357
  });
358
358
  if (this.transform) {
359
359
  if (sandbox) {
360
- source.data = await sandbox(this.transform, source.data);
360
+ source.data = await Promise.race([
361
+ sandbox(this.transform, source.data),
362
+ new Promise((resolve, reject) => {
363
+ controller.signal.onabort = () => {
364
+ this.#cachedTransform = null;
365
+ reject(new DOMException("", "AbortError"));
366
+ };
367
+ }),
368
+ ]);
361
369
  } else {
362
370
  throw new Error("sandbox could not be initialized");
363
371
  }
package/lib/sandbox.js CHANGED
@@ -1,46 +1,104 @@
1
- const makeSandbox = () => {
2
- const iframe = window.document.createElement("iframe");
3
- const sandboxId = crypto.randomUUID();
4
- iframe.style.display = "none";
5
- iframe.src =
6
- "data:text/html;base64," +
7
- btoa(`<!DOCTYPE html>
8
- <script type="module">
9
- const p = "${window.location.origin}"
10
-
11
- window.addEventListener(
1
+ const sandboxInit = async (sandboxId, p) => {
2
+ const workerInit = (workerId) => {
3
+ self.addEventListener(
12
4
  "message",
13
5
  async (event) => {
14
- console.debug(event);
15
-
16
- if (event.origin !== p) return;
6
+ console.debug("worker recived msg from sandbox", event);
17
7
 
18
8
  let id;
19
9
  try {
20
10
  const msg = JSON.parse(event.data);
21
11
  id = msg.id;
22
- console.debug(msg)
12
+ console.debug("parsed message", msg);
23
13
 
24
14
  const { default: transform } = await import(msg.transform);
25
15
 
26
16
  const o = await Promise.resolve(transform(msg.data));
27
- event.source.postMessage(JSON.stringify({id: msg.id, data: o}), p);
17
+ self.postMessage(JSON.stringify({ id: msg.id, data: o }));
28
18
  } catch (e) {
29
- event.source.postMessage(JSON.stringify({id: id, error: e.toString()}), p);
19
+ self.postMessage(JSON.stringify({ id: id, error: e.toString() }));
30
20
  }
31
21
  },
32
22
  false,
33
23
  );
34
24
 
35
- window.parent.postMessage(JSON.stringify({id: "${sandboxId}"}), p);
36
- </script>
37
- `);
25
+ self.postMessage(JSON.stringify({ id: workerId }));
26
+ };
27
+
28
+ const workerBlob = new Blob([`(${workerInit.toString()})("${sandboxId}");`], {
29
+ type: "module",
30
+ });
31
+ const worker = new Worker(URL.createObjectURL(workerBlob));
32
+
33
+ const waitForWorkerReady = () =>
34
+ new Promise((resolve, reject) => {
35
+ const listener = (event) => {
36
+ worker.removeEventListener("message", listener, false);
37
+ console.debug("sandbox recived msg from worker", event);
38
+ try {
39
+ const msg = JSON.parse(event.data);
40
+ if (msg.id === sandboxId) {
41
+ resolve();
42
+ return;
43
+ }
44
+ console.warn("unexpected msg!");
45
+ } catch (e) {
46
+ reject(e);
47
+ return;
48
+ }
49
+ };
50
+ worker.addEventListener("message", listener, false);
51
+ });
52
+
53
+ // wait for ready msg from worker
54
+ await waitForWorkerReady();
55
+ console.log("worker ready");
56
+
57
+ // Relay messages from parent to worker
58
+ window.addEventListener(
59
+ "message",
60
+ (event) => {
61
+ console.debug("sandbox recieved msg from parent", event);
62
+ worker.postMessage(event.data);
63
+ },
64
+ false,
65
+ );
66
+ // Relay messages from worker to parent
67
+ worker.addEventListener(
68
+ "message",
69
+ (event) => {
70
+ console.debug("sandbox recieved msg from worker", event);
71
+ window.parent.postMessage(event.data, p);
72
+ },
73
+ false,
74
+ );
75
+
76
+ window.parent.postMessage(JSON.stringify({ id: sandboxId }), p);
77
+ };
78
+ const makeSandbox = () => {
79
+ const iframe = window.document.createElement("iframe");
80
+ const sandboxId = crypto.randomUUID();
81
+ iframe.style.display = "none";
82
+ const sandboxBlob = new Blob(
83
+ [
84
+ `
85
+ <!DOCTYPE html>
86
+ <script type="module">
87
+ (${sandboxInit.toString()})("${sandboxId}", "${window.location.origin}");
88
+ </script>
89
+ `,
90
+ ],
91
+ {
92
+ type: "text/html",
93
+ },
94
+ );
95
+ iframe.src = URL.createObjectURL(sandboxBlob);
38
96
 
39
97
  const run = (transform, data) => {
40
98
  const messageID = crypto.randomUUID();
41
99
  return new Promise((resolve, reject) => {
42
100
  const listener = (event) => {
43
- console.debug(event);
101
+ console.debug("parent recieved msg from sandbox", event);
44
102
  try {
45
103
  const msg = JSON.parse(event.data);
46
104
  if (msg.id === messageID) {
@@ -73,10 +131,11 @@ const makeSandbox = () => {
73
131
  return new Promise((resolve) => {
74
132
  const listener = (event) => {
75
133
  window.removeEventListener("message", listener, false);
76
- console.debug(event);
134
+ console.debug("parent recieved msg from sandbox", event);
77
135
  try {
78
136
  const msg = JSON.parse(event.data);
79
137
  if (msg.id === sandboxId) {
138
+ console.log("sandbox ready");
80
139
  resolve(run);
81
140
  return;
82
141
  }
package/lib/style.js CHANGED
@@ -91,11 +91,15 @@ export async function getStyle(style, source) {
91
91
  } else if (typeof style.sprite === "string") {
92
92
  style.sprite = [{ id: "default", url: style.sprite }];
93
93
  }
94
+ const spritesheets = style.sprite.map(({ id }) => id);
94
95
  const extendedStyle = {
95
96
  ...parentStyle,
96
97
  ...style,
97
98
  sources: { ...parentStyle.sources, ...(style.sources || {}) },
98
- sprite: [...parentStyle.sprite, ...style.sprite],
99
+ sprite: [
100
+ ...parentStyle.sprite.filter(({ id }) => !spritesheets.includes(id)),
101
+ ...style.sprite,
102
+ ],
99
103
  layers,
100
104
  };
101
105
  return ensureSourceAndLayers(extendedStyle, source);
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "5.0.2",
6
+ "version": "5.0.4",
7
7
  "description": "A web based tool for making MapLibre GL maps with data from sources such as Overpass, GeoJSON, GPX, KML, TCX, etc",
8
8
  "main": "index.js",
9
9
  "scripts": {