From accc3d9c67e004aa814d1592d97342d3a7766bb4 Mon Sep 17 00:00:00 2001
From: Joris
Date: Tue, 5 Jul 2022 21:55:41 +0200
Subject: WIP Rewrite in TS
---
.gitignore | 7 +-
.gitlab-ci.yml | 10 -
.tmuxinator.yml | 11 -
Makefile | 21 --
README.md | 30 +-
bin/watch.sh | 8 +
bsconfig.json | 22 --
deploy | 12 -
dev | 28 --
package-lock.json | 167 ---------
package.json | 13 -
public/index.html | 47 ++-
public/leaflet/leaflet.css | 2 +-
public/leaflet/leaflet.js | 5 +-
public/leaflet/leaflet.js.map | 1 -
public/main.css | 24 +-
rollup.config.js | 13 -
shell.nix | 13 +-
src/Color.ml | 38 --
src/Lib/CSV.ml | 76 ----
src/Lib/ContextMenu.ml | 40 ---
src/Lib/Dom/Document.ml | 20 --
src/Lib/Dom/Element.ml | 51 ---
src/Lib/Dom/Event.ml | 17 -
src/Lib/Dom/H.ml | 65 ----
src/Lib/Dom/HA.ml | 43 ---
src/Lib/Dom/HE.ml | 13 -
src/Lib/Dom/History.ml | 2 -
src/Lib/Dom/Location.ml | 7 -
src/Lib/Dom/Window.ml | 2 -
src/Lib/File.ml | 21 --
src/Lib/FontAwesome.ml | 788 ------------------------------------------
src/Lib/Fun.ml | 2 -
src/Lib/Leaflet.ml | 89 -----
src/Lib/Modal.ml | 25 --
src/Lib/Option.ml | 9 -
src/Lib/String.ml | 35 --
src/Lib/URI.ml | 2 -
src/Main.ml | 3 -
src/State.ml | 119 -------
src/View/Button.ml | 19 -
src/View/Form.ml | 65 ----
src/View/Form/Autocomplete.ml | 80 -----
src/View/Layout.ml | 9 -
src/View/Map.ml | 131 -------
src/View/Map/Icon.ml | 32 --
src/View/Map/Marker.ml | 105 ------
src/lib/autoComplete.ts | 114 ++++++
src/lib/button.ts | 29 ++
src/lib/contextMenu.ts | 35 ++
src/lib/fontAwesome.ts | 788 ++++++++++++++++++++++++++++++++++++++++++
src/lib/form.ts | 80 +++++
src/lib/h.ts | 41 +++
src/lib/layout.ts | 15 +
src/lib/modal.ts | 28 ++
src/main.ts | 3 +
src/map.ts | 126 +++++++
src/marker.ts | 125 +++++++
src/types/leaflet.d.ts | 28 ++
tsconfig.json | 13 +
60 files changed, 1489 insertions(+), 2278 deletions(-)
delete mode 100644 .gitlab-ci.yml
delete mode 100644 .tmuxinator.yml
delete mode 100644 Makefile
create mode 100755 bin/watch.sh
delete mode 100644 bsconfig.json
delete mode 100755 deploy
delete mode 100755 dev
delete mode 100644 package-lock.json
delete mode 100644 package.json
delete mode 100644 public/leaflet/leaflet.js.map
delete mode 100644 rollup.config.js
delete mode 100644 src/Color.ml
delete mode 100644 src/Lib/CSV.ml
delete mode 100644 src/Lib/ContextMenu.ml
delete mode 100644 src/Lib/Dom/Document.ml
delete mode 100644 src/Lib/Dom/Element.ml
delete mode 100644 src/Lib/Dom/Event.ml
delete mode 100644 src/Lib/Dom/H.ml
delete mode 100644 src/Lib/Dom/HA.ml
delete mode 100644 src/Lib/Dom/HE.ml
delete mode 100644 src/Lib/Dom/History.ml
delete mode 100644 src/Lib/Dom/Location.ml
delete mode 100644 src/Lib/Dom/Window.ml
delete mode 100644 src/Lib/File.ml
delete mode 100644 src/Lib/FontAwesome.ml
delete mode 100644 src/Lib/Fun.ml
delete mode 100644 src/Lib/Leaflet.ml
delete mode 100644 src/Lib/Modal.ml
delete mode 100644 src/Lib/Option.ml
delete mode 100644 src/Lib/String.ml
delete mode 100644 src/Lib/URI.ml
delete mode 100644 src/Main.ml
delete mode 100644 src/State.ml
delete mode 100644 src/View/Button.ml
delete mode 100644 src/View/Form.ml
delete mode 100644 src/View/Form/Autocomplete.ml
delete mode 100644 src/View/Layout.ml
delete mode 100644 src/View/Map.ml
delete mode 100644 src/View/Map/Icon.ml
delete mode 100644 src/View/Map/Marker.ml
create mode 100644 src/lib/autoComplete.ts
create mode 100644 src/lib/button.ts
create mode 100644 src/lib/contextMenu.ts
create mode 100644 src/lib/fontAwesome.ts
create mode 100644 src/lib/form.ts
create mode 100644 src/lib/h.ts
create mode 100644 src/lib/layout.ts
create mode 100644 src/lib/modal.ts
create mode 100644 src/main.ts
create mode 100644 src/map.ts
create mode 100644 src/marker.ts
create mode 100644 src/types/leaflet.d.ts
create mode 100644 tsconfig.json
diff --git a/.gitignore b/.gitignore
index 05e0f57..b62f3b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1 @@
-node_modules/
-lib/
-.merlin
-*.bs.js
-public/main.js
-.bsb.lock
+/public/main.js
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
deleted file mode 100644
index a872f80..0000000
--- a/.gitlab-ci.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-image: alpine:latest
-pages:
- stage: deploy
- script:
- - echo 'Nothing to do...'
- artifacts:
- paths:
- - public
- only:
- - pages
diff --git a/.tmuxinator.yml b/.tmuxinator.yml
deleted file mode 100644
index 45f4dd4..0000000
--- a/.tmuxinator.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-name: map
-
-windows:
- - main:
- panes:
- - ocaml:
- - ./dev watch-ocaml
- - js:
- - ./dev watch-js
- - server:
- - python -m http.server --directory public
diff --git a/Makefile b/Makefile
deleted file mode 100644
index c40999d..0000000
--- a/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-export PATH := node_modules/.bin:$(PATH)
-
-build: public/main.js
-
-public/main.js: install $(shell find src \( -type d -o \( -type f -a -regex ".*\.ml" \) \))
- @echo "Building $@"
- @bsb -make-world
- @rollup --config rollup.config.js
- @terser $@ --output $@ --compress --mangle
-
-install:
- @npm install
- @bsb -init init
- @mv init/node_modules/bs-platform node_modules
- @rm -rf init
-
-clean:
- @echo "Cleaning"
- @rm -f public/main.js
- @rm -rf node_modules lib
- @find src -name '*.bs.js' -exec rm {} \;
diff --git a/README.md b/README.md
index 8442abb..9f5b91f 100644
--- a/README.md
+++ b/README.md
@@ -1,29 +1,9 @@
-# Map
+# Getting started
-Available at [https://guyonvarch.gitlab.io/map](https://guyonvarch.gitlab.io/map).
+Run:
-## Gettings started
-
-Start the environment with:
-
-```bash
-./dev start
-```
-
-Later, stop the environment with:
-
-```bash
-./dev stop
+```sh
+nix-shell --run bin/watch.sh
```
-## Deploy
-
-```bash
-nix-shell --run ./deploy
-```
-
-## Bucklescript links
-
-- [Documentation](https://bucklescript.github.io/docs/en/interop-overview)
-- [Ocaml std API](https://caml.inria.fr/pub/docs/manual-ocaml-4.02/stdlib.html)
-- [Libraries](https://bucklescript.github.io/bucklescript/api/index.html)
+Then, open your browser at `http://localhost:8000`.
diff --git a/bin/watch.sh b/bin/watch.sh
new file mode 100755
index 0000000..064414d
--- /dev/null
+++ b/bin/watch.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+python -m http.server --directory public 8000 &
+
+trap "fuser -k 8000/tcp" EXIT
+
+tsc --build tsconfig.json --watch
diff --git a/bsconfig.json b/bsconfig.json
deleted file mode 100644
index 95e864d..0000000
--- a/bsconfig.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "name": "map",
- "version": "0.1.0",
- "sources": {
- "dir": "src",
- "subdirs": true
- },
- "package-specs": {
- "module": "es6",
- "in-source": true
- },
- "suffix": ".bs.js",
- "bs-dependencies": [],
- "warnings": {
- "number": "+A-42-40-4",
- "error": "+A-40-4"
- },
- "bsc-flags": [
- "-bs-super-errors"
- ],
- "refmt": 3
-}
diff --git a/deploy b/deploy
deleted file mode 100755
index 6abf9b0..0000000
--- a/deploy
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-# Build
-git branch -D pages || true
-git checkout -b pages
-make clean build
-git add --force public/main.js
-git commit -m "Deploy pages"
-git push --force origin pages
-git checkout master
-git branch -D pages
diff --git a/dev b/dev
deleted file mode 100755
index 178fe6f..0000000
--- a/dev
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-cd "$(dirname $0)"
-CMD="$1"
-PROJECT="map"
-
-if [ "$CMD" = "start" ]; then
-
- nix-shell --run "make node_modules && tmuxinator local"
-
-elif [ "$CMD" = "stop" ]; then
-
- nix-shell --run "tmux kill-session -t $PROJECT"
-
-elif [ "$CMD" = "watch-ocaml" ]; then
-
- bsb -make-world -w
-
-elif [ "$CMD" = "watch-js" ]; then
-
- node_modules/.bin/rollup --watch --config rollup.config.js
-
-else
-
- echo "Usage: $0 start|stop|watch-ocaml|watch-js"
- exit 1
-
-fi
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index 6aa4899..0000000
--- a/package-lock.json
+++ /dev/null
@@ -1,167 +0,0 @@
-{
- "name": "map",
- "version": "0.1.0",
- "lockfileVersion": 1,
- "requires": true,
- "dependencies": {
- "@rollup/plugin-node-resolve": {
- "version": "8.4.0",
- "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-8.4.0.tgz",
- "integrity": "sha512-LFqKdRLn0ShtQyf6SBYO69bGE1upV6wUhBX0vFOUnLAyzx5cwp8svA0eHUnu8+YU57XOkrMtfG63QOpQx25pHQ==",
- "dev": true,
- "requires": {
- "@rollup/pluginutils": "^3.1.0",
- "@types/resolve": "1.17.1",
- "builtin-modules": "^3.1.0",
- "deep-freeze": "^0.0.1",
- "deepmerge": "^4.2.2",
- "is-module": "^1.0.0",
- "resolve": "^1.17.0"
- }
- },
- "@rollup/pluginutils": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
- "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==",
- "dev": true,
- "requires": {
- "@types/estree": "0.0.39",
- "estree-walker": "^1.0.1",
- "picomatch": "^2.2.2"
- }
- },
- "@types/estree": {
- "version": "0.0.39",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
- "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
- "dev": true
- },
- "@types/node": {
- "version": "14.0.22",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.22.tgz",
- "integrity": "sha512-emeGcJvdiZ4Z3ohbmw93E/64jRzUHAItSHt8nF7M4TGgQTiWqFVGB8KNpLGFmUHmHLvjvBgFwVlqNcq+VuGv9g==",
- "dev": true
- },
- "@types/resolve": {
- "version": "1.17.1",
- "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
- "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==",
- "dev": true,
- "requires": {
- "@types/node": "*"
- }
- },
- "buffer-from": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
- "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
- "dev": true
- },
- "builtin-modules": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz",
- "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==",
- "dev": true
- },
- "commander": {
- "version": "2.20.3",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
- "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
- "dev": true
- },
- "deep-freeze": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/deep-freeze/-/deep-freeze-0.0.1.tgz",
- "integrity": "sha1-OgsABd4YZygZ39OM0x+RF5yJPoQ=",
- "dev": true
- },
- "deepmerge": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
- "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
- "dev": true
- },
- "estree-walker": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
- "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==",
- "dev": true
- },
- "fsevents": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
- "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
- "dev": true,
- "optional": true
- },
- "is-module": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
- "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
- "dev": true
- },
- "leaflet": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.6.0.tgz",
- "integrity": "sha512-CPkhyqWUKZKFJ6K8umN5/D2wrJ2+/8UIpXppY7QDnUZW5bZL5+SEI2J7GBpwh4LIupOKqbNSQXgqmrEJopHVNQ==",
- "dev": true
- },
- "path-parse": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
- "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
- "dev": true
- },
- "picomatch": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
- "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
- "dev": true
- },
- "resolve": {
- "version": "1.17.0",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
- "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==",
- "dev": true,
- "requires": {
- "path-parse": "^1.0.6"
- }
- },
- "rollup": {
- "version": "2.21.0",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.21.0.tgz",
- "integrity": "sha512-BEGgy+wSzux7Ycq58pRiWEOBZaXRXTuvzl1gsm7gqmsAHxkWf9nyA5V2LN9fGSHhhDQd0/C13iRzSh4bbIpWZQ==",
- "dev": true,
- "requires": {
- "fsevents": "~2.1.2"
- }
- },
- "source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true
- },
- "source-map-support": {
- "version": "0.5.19",
- "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
- "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
- "dev": true,
- "requires": {
- "buffer-from": "^1.0.0",
- "source-map": "^0.6.0"
- }
- },
- "terser": {
- "version": "4.8.0",
- "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
- "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==",
- "dev": true,
- "requires": {
- "commander": "^2.20.0",
- "source-map": "~0.6.1",
- "source-map-support": "~0.5.12"
- }
- }
- }
-}
diff --git a/package.json b/package.json
deleted file mode 100644
index 2a80a56..0000000
--- a/package.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "name": "map",
- "version": "0.1.0",
- "keywords": [],
- "author": "Joris Guyonvarch",
- "license": "MIT",
- "devDependencies": {
- "@rollup/plugin-node-resolve": "^8.1.0",
- "rollup": "^2.21.0",
- "terser": "^4.8.0",
- "leaflet": "^1.6.0"
- }
-}
diff --git a/public/index.html b/public/index.html
index 143f477..36007b3 100644
--- a/public/index.html
+++ b/public/index.html
@@ -1,23 +1,34 @@
-
+
+
+
+
Map
+
+
-
-
-
- Map
-
-
+
+
-
-
+
+
+
-
-
-
-
+
+
-
-
-
-
-
+
+
diff --git a/public/leaflet/leaflet.css b/public/leaflet/leaflet.css
index 983d605..601476f 100644
--- a/public/leaflet/leaflet.css
+++ b/public/leaflet/leaflet.css
@@ -532,7 +532,7 @@ svg.leaflet-image-layer.leaflet-interactive path {
}
.leaflet-oldie .leaflet-popup-content-wrapper {
- zoom: 1;
+ -ms-zoom: 1;
}
.leaflet-oldie .leaflet-popup-tip {
width: 24px;
diff --git a/public/leaflet/leaflet.js b/public/leaflet/leaflet.js
index bc9ef0f..21f499c 100644
--- a/public/leaflet/leaflet.js
+++ b/public/leaflet/leaflet.js
@@ -1,5 +1,6 @@
/* @preserve
- * Leaflet 1.6.0+Detached: 0c81bdf904d864fd12a286e3d1979f47aba17991.0c81bdf, a JS library for interactive maps. http://leafletjs.com
+ * Leaflet 1.7.1, a JS library for interactive maps. http://leafletjs.com
* (c) 2010-2019 Vladimir Agafonkin, (c) 2010-2011 CloudMade
*/
-!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports):"function"==typeof define&&define.amd?define(["exports"],i):i(t.L={})}(this,function(t){"use strict";var i=Object.freeze;function h(t){var i,e,n,o;for(e=1,n=arguments.length;e=this.min.x&&e.x<=this.max.x&&i.y>=this.min.y&&e.y<=this.max.y},intersects:function(t){t=R(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>=i.x&&n.x<=e.x,r=o.y>=i.y&&n.y<=e.y;return s&&r},overlaps:function(t){t=R(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>i.x&&n.xi.y&&n.y=n.lat&&e.lat<=o.lat&&i.lng>=n.lng&&e.lng<=o.lng},intersects:function(t){t=D(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>=i.lat&&n.lat<=e.lat,r=o.lng>=i.lng&&n.lng<=e.lng;return s&&r},overlaps:function(t){t=D(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>i.lat&&n.lati.lng&&n.lng';var i=t.firstChild;return i.style.behavior="url(#default#VML)",i&&"object"==typeof i.adj}catch(t){return!1}}();function Bt(t){return 0<=navigator.userAgent.toLowerCase().indexOf(t)}var At=(Object.freeze||Object)({ie:it,ielt9:et,edge:nt,webkit:ot,android:st,android23:rt,androidStock:ht,opera:ut,chrome:lt,gecko:ct,safari:_t,phantom:dt,opera12:pt,win:mt,ie3d:ft,webkit3d:gt,gecko3d:vt,any3d:yt,mobile:xt,mobileWebkit:wt,mobileWebkit3d:Pt,msPointer:Lt,pointer:bt,touch:Tt,mobileOpera:zt,mobileGecko:Mt,retina:Ct,passiveEvents:Et,canvas:St,svg:Zt,vml:kt}),It=Lt?"MSPointerDown":"pointerdown",Ot=Lt?"MSPointerMove":"pointermove",Rt=Lt?"MSPointerUp":"pointerup",Nt=Lt?"MSPointerCancel":"pointercancel",Dt=["INPUT","SELECT","OPTION"],jt={},Wt=!1,Ht=0;function Ft(t,i,e,n){return"touchstart"===i?function(t,i,e){var n=a(function(t){if("mouse"!==t.pointerType&&t.MSPOINTER_TYPE_MOUSE&&t.pointerType!==t.MSPOINTER_TYPE_MOUSE){if(!(Dt.indexOf(t.target.tagName)<0))return;ji(t)}Gt(t,i)});t["_leaflet_touchstart"+e]=n,t.addEventListener(It,n,!1),Wt||(document.documentElement.addEventListener(It,Ut,!0),document.documentElement.addEventListener(Ot,Vt,!0),document.documentElement.addEventListener(Rt,qt,!0),document.documentElement.addEventListener(Nt,qt,!0),Wt=!0)}(t,e,n):"touchmove"===i?function(t,i,e){function n(t){(t.pointerType!==t.MSPOINTER_TYPE_MOUSE&&"mouse"!==t.pointerType||0!==t.buttons)&&Gt(t,i)}t["_leaflet_touchmove"+e]=n,t.addEventListener(Ot,n,!1)}(t,e,n):"touchend"===i&&function(t,i,e){function n(t){Gt(t,i)}t["_leaflet_touchend"+e]=n,t.addEventListener(Rt,n,!1),t.addEventListener(Nt,n,!1)}(t,e,n),this}function Ut(t){jt[t.pointerId]=t,Ht++}function Vt(t){jt[t.pointerId]&&(jt[t.pointerId]=t)}function qt(t){delete jt[t.pointerId],Ht--}function Gt(t,i){for(var e in t.touches=[],jt)t.touches.push(jt[e]);t.changedTouches=[t],i(t)}var Kt=Lt?"MSPointerDown":bt?"pointerdown":"touchstart",Yt=Lt?"MSPointerUp":bt?"pointerup":"touchend",Xt="_leaflet_";function Jt(t,o,i){var s,r,a=!1;function e(t){var i;if(bt){if(!nt||"mouse"===t.pointerType)return;i=Ht}else i=t.touches.length;if(!(1this.options.maxZoom)?this.setZoom(t):this},panInsideBounds:function(t,i){this._enforcingBounds=!0;var e=this.getCenter(),n=this._limitCenter(e,this._zoom,D(t));return e.equals(n)||this.panTo(n,i),this._enforcingBounds=!1,this},panInside:function(t,i){var e=I((i=i||{}).paddingTopLeft||i.padding||[0,0]),n=I(i.paddingBottomRight||i.padding||[0,0]),o=this.getCenter(),s=this.project(o),r=this.project(t),a=this.getPixelBounds(),h=a.getSize().divideBy(2),u=R([a.min.add(e),a.max.subtract(n)]);if(!u.contains(r)){this._enforcingBounds=!0;var l=s.subtract(r),c=I(r.x+l.x,r.y+l.y);(r.xu.max.x)&&(c.x=s.x-l.x,0u.max.y)&&(c.y=s.y-l.y,0=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,i){for(var e,n=[],o="mouseout"===i||"mouseover"===i,s=t.target||t.srcElement,r=!1;s;){if((e=this._targets[u(s)])&&("click"===i||"preclick"===i)&&!t._simulated&&this._draggableMoved(e)){r=!0;break}if(e&&e.listens(i,!0)){if(o&&!Yi(s,t))break;if(n.push(e),o)break}if(s===this._container)break;s=s.parentNode}return n.length||r||o||!Yi(s,t)||(n=[this]),n},_handleDOMEvent:function(t){if(this._loaded&&!Ki(t)){var i=t.type;"mousedown"!==i&&"keypress"!==i&&"keyup"!==i&&"keydown"!==i||Mi(t.target||t.srcElement),this._fireDOMEvent(t,i)}},_mouseEvents:["click","dblclick","mouseover","mouseout","contextmenu"],_fireDOMEvent:function(t,i,e){if("click"===t.type){var n=h({},t);n.type="preclick",this._fireDOMEvent(n,n.type,e)}if(!t._stopped&&(e=(e||[]).concat(this._findEventTargets(t,i))).length){var o=e[0];"contextmenu"===i&&o.listens(i,!0)&&ji(t);var s={originalEvent:t};if("keypress"!==t.type&&"keydown"!==t.type&&"keyup"!==t.type){var r=o.getLatLng&&(!o._radius||o._radius<=10);s.containerPoint=r?this.latLngToContainerPoint(o.getLatLng()):this.mouseEventToContainerPoint(t),s.layerPoint=this.containerPointToLayerPoint(s.containerPoint),s.latlng=r?o.getLatLng():this.layerPointToLatLng(s.layerPoint)}for(var a=0;athis.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(i),o=this._getCenterOffset(t)._divideBy(1-1/n);return!(!0!==e.animate&&!this.getSize().contains(o))&&(M(function(){this._moveStart(!0,!1)._animateZoom(t,i,!0)},this),!0)},_animateZoom:function(t,i,e,n){this._mapPane&&(e&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=i,mi(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:i,noUpdate:n}),setTimeout(a(this._onZoomTransitionEnd,this),250))},_onZoomTransitionEnd:function(){this._animatingZoom&&(this._mapPane&&fi(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom),M(function(){this._moveEnd(!0)},this))}});function Qi(t){return new te(t)}var te=S.extend({options:{position:"topright"},initialize:function(t){p(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var i=this._map;return i&&i.removeControl(this),this.options.position=t,i&&i.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var i=this._container=this.onAdd(t),e=this.getPosition(),n=t._controlCorners[e];return mi(i,"leaflet-control"),-1!==e.indexOf("bottom")?n.insertBefore(i,n.firstChild):n.appendChild(i),this._map.on("unload",this.remove,this),this},remove:function(){return this._map&&(li(this._container),this.onRemove&&this.onRemove(this._map),this._map.off("unload",this.remove,this),this._map=null),this},_refocusOnMap:function(t){this._map&&t&&0",n=document.createElement("div");return n.innerHTML=e,n.firstChild},_addItem:function(t){var i,e=document.createElement("label"),n=this._map.hasLayer(t.layer);t.overlay?((i=document.createElement("input")).type="checkbox",i.className="leaflet-control-layers-selector",i.defaultChecked=n):i=this._createRadioElement("leaflet-base-layers_"+u(this),n),this._layerControlInputs.push(i),i.layerId=u(t.layer),ki(i,"click",this._onInputClick,this);var o=document.createElement("span");o.innerHTML=" "+t.name;var s=document.createElement("div");return e.appendChild(s),s.appendChild(i),s.appendChild(o),(t.overlay?this._overlaysList:this._baseLayersList).appendChild(e),this._checkDisabledLayers(),e},_onInputClick:function(){var t,i,e=this._layerControlInputs,n=[],o=[];this._handlingClick=!0;for(var s=e.length-1;0<=s;s--)t=e[s],i=this._getLayer(t.layerId).layer,t.checked?n.push(i):t.checked||o.push(i);for(s=0;si.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expand:function(){return this.expand()},_collapse:function(){return this.collapse()}}),ee=te.extend({options:{position:"topleft",zoomInText:"+",zoomInTitle:"Zoom in",zoomOutText:"−",zoomOutTitle:"Zoom out"},onAdd:function(t){var i="leaflet-control-zoom",e=ui("div",i+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,i+"-in",e,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,i+"-out",e,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),e},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,i,e,n,o){var s=ui("a",e,n);return s.innerHTML=t,s.href="#",s.title=i,s.setAttribute("role","button"),s.setAttribute("aria-label",i),Di(s),ki(s,"click",Wi),ki(s,"click",o,this),ki(s,"click",this._refocusOnMap,this),s},_updateDisabled:function(){var t=this._map,i="leaflet-disabled";fi(this._zoomInButton,i),fi(this._zoomOutButton,i),!this._disabled&&t._zoom!==t.getMinZoom()||mi(this._zoomOutButton,i),!this._disabled&&t._zoom!==t.getMaxZoom()||mi(this._zoomInButton,i)}});$i.mergeOptions({zoomControl:!0}),$i.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new ee,this.addControl(this.zoomControl))});var ne=te.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var i="leaflet-control-scale",e=ui("div",i),n=this.options;return this._addScales(n,i+"-line",e),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),e},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,i,e){t.metric&&(this._mScale=ui("div",i,e)),t.imperial&&(this._iScale=ui("div",i,e))},_update:function(){var t=this._map,i=t.getSize().y/2,e=t.distance(t.containerPointToLatLng([0,i]),t.containerPointToLatLng([this.options.maxWidth,i]));this._updateScales(e)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var i=this._getRoundNum(t),e=i<1e3?i+" m":i/1e3+" km";this._updateScale(this._mScale,e,i/t)},_updateImperial:function(t){var i,e,n,o=3.2808399*t;5280Leaflet'},initialize:function(t){p(this,t),this._attributions={}},onAdd:function(t){for(var i in(t.attributionControl=this)._container=ui("div","leaflet-control-attribution"),Di(this._container),t._layers)t._layers[i].getAttribution&&this.addAttribution(t._layers[i].getAttribution());return this._update(),this._container},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t&&(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update()),this},removeAttribution:function(t){return t&&this._attributions[t]&&(this._attributions[t]--,this._update()),this},_update:function(){if(this._map){var t=[];for(var i in this._attributions)this._attributions[i]&&t.push(i);var e=[];this.options.prefix&&e.push(this.options.prefix),t.length&&e.push(t.join(", ")),this._container.innerHTML=e.join(" | ")}}});$i.mergeOptions({attributionControl:!0}),$i.addInitHook(function(){this.options.attributionControl&&(new oe).addTo(this)});te.Layers=ie,te.Zoom=ee,te.Scale=ne,te.Attribution=oe,Qi.layers=function(t,i,e){return new ie(t,i,e)},Qi.zoom=function(t){return new ee(t)},Qi.scale=function(t){return new ne(t)},Qi.attribution=function(t){return new oe(t)};var se=S.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled||(this._enabled=!0,this.addHooks()),this},disable:function(){return this._enabled&&(this._enabled=!1,this.removeHooks()),this},enabled:function(){return!!this._enabled}});se.addTo=function(t,i){return t.addHandler(i,this),this};var re,ae={Events:Z},he=Tt?"touchstart mousedown":"mousedown",ue={mousedown:"mouseup",touchstart:"touchend",pointerdown:"touchend",MSPointerDown:"touchend"},le={mousedown:"mousemove",touchstart:"touchmove",pointerdown:"touchmove",MSPointerDown:"touchmove"},ce=k.extend({options:{clickTolerance:3},initialize:function(t,i,e,n){p(this,n),this._element=t,this._dragStartTarget=i||t,this._preventOutline=e},enable:function(){this._enabled||(ki(this._dragStartTarget,he,this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(ce._dragging===this&&this.finishDrag(),Ai(this._dragStartTarget,he,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){if(!t._simulated&&this._enabled&&(this._moved=!1,!pi(this._element,"leaflet-zoom-anim")&&!(ce._dragging||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||((ce._dragging=this)._preventOutline&&Mi(this._element),Ti(),Qt(),this._moving)))){this.fire("down");var i=t.touches?t.touches[0]:t,e=Ei(this._element);this._startPoint=new B(i.clientX,i.clientY),this._parentScale=Si(e),ki(document,le[t.type],this._onMove,this),ki(document,ue[t.type],this._onUp,this)}},_onMove:function(t){if(!t._simulated&&this._enabled)if(t.touches&&1i.max.x&&(e|=2),t.yi.max.y&&(e|=8),e}function ge(t,i,e,n){var o,s=i.x,r=i.y,a=e.x-s,h=e.y-r,u=a*a+h*h;return 0this._layersMaxZoom&&this.setZoom(this._layersMaxZoom),void 0===this.options.minZoom&&this._layersMinZoom&&this.getZoom()t.y!=n.y>t.y&&t.x<(n.x-e.x)*(t.y-e.y)/(n.y-e.y)+e.x&&(u=!u);return u||je.prototype._containsPoint.call(this,t,!0)}});var He=ke.extend({initialize:function(t,i){p(this,i),this._layers={},t&&this.addData(t)},addData:function(t){var i,e,n,o=v(t)?t:t.features;if(o){for(i=0,e=o.length;iu.x&&(l=s.x+n-u.x+h.x),s.x-l-a.x<0&&(l=s.x-a.x),s.y+e+h.y>u.y&&(c=s.y+e-u.y+h.y),s.y-c-a.y<0&&(c=s.y-a.y),(l||c)&&t.fire("autopanstart").panBy([l,c])}},_onCloseButtonClick:function(t){this._close(),Wi(t)},_getAnchor:function(){return I(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}});$i.mergeOptions({closePopupOnClick:!0}),$i.include({openPopup:function(t,i,e){return t instanceof sn||(t=new sn(e).setContent(t)),i&&t.setLatLng(i),this.hasLayer(t)?this:(this._popup&&this._popup.options.autoClose&&this.closePopup(),this._popup=t,this.addLayer(t))},closePopup:function(t){return t&&t!==this._popup||(t=this._popup,this._popup=null),t&&this.removeLayer(t),this}}),Se.include({bindPopup:function(t,i){return t instanceof sn?(p(t,i),(this._popup=t)._source=this):(this._popup&&!i||(this._popup=new sn(i,this)),this._popup.setContent(t)),this._popupHandlersAdded||(this.on({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t,i){return this._popup&&this._map&&(i=this._popup._prepareOpen(this,t,i),this._map.openPopup(this._popup,i)),this},closePopup:function(){return this._popup&&this._popup._close(),this},togglePopup:function(t){return this._popup&&(this._popup._map?this.closePopup():this.openPopup(t)),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var i=t.layer||t.target;this._popup&&this._map&&(Wi(t),i instanceof Re?this.openPopup(t.layer||t.target,t.latlng):this._map.hasLayer(this._popup)&&this._popup._source===i?this.closePopup():this.openPopup(i,t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)},_onKeyPress:function(t){13===t.originalEvent.keyCode&&this._openPopup(t)}});var rn=on.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,interactive:!1,opacity:.9},onAdd:function(t){on.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&this._source.fire("tooltipopen",{tooltip:this},!0)},onRemove:function(t){on.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&this._source.fire("tooltipclose",{tooltip:this},!0)},getEvents:function(){var t=on.prototype.getEvents.call(this);return Tt&&!this.options.permanent&&(t.preclick=this._close),t},_close:function(){this._map&&this._map.closeTooltip(this)},_initLayout:function(){var t="leaflet-tooltip "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=ui("div",t)},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var i=this._map,e=this._container,n=i.latLngToContainerPoint(i.getCenter()),o=i.layerPointToContainerPoint(t),s=this.options.direction,r=e.offsetWidth,a=e.offsetHeight,h=I(this.options.offset),u=this._getAnchor();t="top"===s?t.add(I(-r/2+h.x,-a+h.y+u.y,!0)):"bottom"===s?t.subtract(I(r/2-h.x,-h.y,!0)):"center"===s?t.subtract(I(r/2+h.x,a/2-u.y+h.y,!0)):"right"===s||"auto"===s&&o.xthis.options.maxZoom||ethis.options.maxZoom||void 0!==this.options.minZoom&&oe.max.x)||!i.wrapLat&&(t.ye.max.y))return!1}if(!this.options.bounds)return!0;var n=this._tileCoordsToBounds(t);return D(this.options.bounds).overlaps(n)},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToNwSe:function(t){var i=this._map,e=this.getTileSize(),n=t.scaleBy(e),o=n.add(e);return[i.unproject(n,t.z),i.unproject(o,t.z)]},_tileCoordsToBounds:function(t){var i=this._tileCoordsToNwSe(t),e=new N(i[0],i[1]);return this.options.noWrap||(e=this._map.wrapLatLngBounds(e)),e},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var i=t.split(":"),e=new B(+i[0],+i[1]);return e.z=+i[2],e},_removeTile:function(t){var i=this._tiles[t];i&&(li(i.el),delete this._tiles[t],this.fire("tileunload",{tile:i.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){mi(t,"leaflet-tile");var i=this.getTileSize();t.style.width=i.x+"px",t.style.height=i.y+"px",t.onselectstart=l,t.onmousemove=l,et&&this.options.opacity<1&&yi(t,this.options.opacity),st&&!rt&&(t.style.WebkitBackfaceVisibility="hidden")},_addTile:function(t,i){var e=this._getTilePos(t),n=this._tileCoordsToKey(t),o=this.createTile(this._wrapCoords(t),a(this._tileReady,this,t));this._initTile(o),this.createTile.length<2&&M(a(this._tileReady,this,t,null,o)),Pi(o,e),this._tiles[n]={el:o,coords:t,current:!0},i.appendChild(o),this.fire("tileloadstart",{tile:o,coords:t})},_tileReady:function(t,i,e){i&&this.fire("tileerror",{error:i,tile:e,coords:t});var n=this._tileCoordsToKey(t);(e=this._tiles[n])&&(e.loaded=+new Date,this._map._fadeAnimated?(yi(e.el,0),C(this._fadeFrame),this._fadeFrame=M(this._updateOpacity,this)):(e.active=!0,this._pruneTiles()),i||(mi(e.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:e.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),et||!this._map._fadeAnimated?M(this._pruneTiles,this):setTimeout(a(this._pruneTiles,this),250)))},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var i=new B(this._wrapX?r(t.x,this._wrapX):t.x,this._wrapY?r(t.y,this._wrapY):t.y);return i.z=t.z,i},_pxBoundsToTileRange:function(t){var i=this.getTileSize();return new O(t.min.unscaleBy(i).floor(),t.max.unscaleBy(i).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}});var un=hn.extend({options:{minZoom:0,maxZoom:18,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1},initialize:function(t,i){this._url=t,(i=p(this,i)).detectRetina&&Ct&&0')}}catch(t){return function(t){return document.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}(),fn={_initContainer:function(){this._container=ui("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(_n.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var i=t._container=mn("shape");mi(i,"leaflet-vml-shape "+(this.options.className||"")),i.coordsize="1 1",t._path=mn("path"),i.appendChild(t._path),this._updateStyle(t),this._layers[u(t)]=t},_addPath:function(t){var i=t._container;this._container.appendChild(i),t.options.interactive&&t.addInteractiveTarget(i)},_removePath:function(t){var i=t._container;li(i),t.removeInteractiveTarget(i),delete this._layers[u(t)]},_updateStyle:function(t){var i=t._stroke,e=t._fill,n=t.options,o=t._container;o.stroked=!!n.stroke,o.filled=!!n.fill,n.stroke?(i||(i=t._stroke=mn("stroke")),o.appendChild(i),i.weight=n.weight+"px",i.color=n.color,i.opacity=n.opacity,n.dashArray?i.dashStyle=v(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):i.dashStyle="",i.endcap=n.lineCap.replace("butt","flat"),i.joinstyle=n.lineJoin):i&&(o.removeChild(i),t._stroke=null),n.fill?(e||(e=t._fill=mn("fill")),o.appendChild(e),e.color=n.fillColor||n.color,e.opacity=n.fillOpacity):e&&(o.removeChild(e),t._fill=null)},_updateCircle:function(t){var i=t._point.round(),e=Math.round(t._radius),n=Math.round(t._radiusY||e);this._setPath(t,t._empty()?"M0 0":"AL "+i.x+","+i.y+" "+e+","+n+" 0,23592600")},_setPath:function(t,i){t._path.v=i},_bringToFront:function(t){_i(t._container)},_bringToBack:function(t){di(t._container)}},gn=kt?mn:$,vn=_n.extend({getEvents:function(){var t=_n.prototype.getEvents.call(this);return t.zoomstart=this._onZoomStart,t},_initContainer:function(){this._container=gn("svg"),this._container.setAttribute("pointer-events","none"),this._rootGroup=gn("g"),this._container.appendChild(this._rootGroup)},_destroyContainer:function(){li(this._container),Ai(this._container),delete this._container,delete this._rootGroup,delete this._svgSize},_onZoomStart:function(){this._update()},_update:function(){if(!this._map._animatingZoom||!this._bounds){_n.prototype._update.call(this);var t=this._bounds,i=t.getSize(),e=this._container;this._svgSize&&this._svgSize.equals(i)||(this._svgSize=i,e.setAttribute("width",i.x),e.setAttribute("height",i.y)),Pi(e,t.min),e.setAttribute("viewBox",[t.min.x,t.min.y,i.x,i.y].join(" ")),this.fire("update")}},_initPath:function(t){var i=t._path=gn("path");t.options.className&&mi(i,t.options.className),t.options.interactive&&mi(i,"leaflet-interactive"),this._updateStyle(t),this._layers[u(t)]=t},_addPath:function(t){this._rootGroup||this._initContainer(),this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){li(t._path),t.removeInteractiveTarget(t._path),delete this._layers[u(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var i=t._path,e=t.options;i&&(e.stroke?(i.setAttribute("stroke",e.color),i.setAttribute("stroke-opacity",e.opacity),i.setAttribute("stroke-width",e.weight),i.setAttribute("stroke-linecap",e.lineCap),i.setAttribute("stroke-linejoin",e.lineJoin),e.dashArray?i.setAttribute("stroke-dasharray",e.dashArray):i.removeAttribute("stroke-dasharray"),e.dashOffset?i.setAttribute("stroke-dashoffset",e.dashOffset):i.removeAttribute("stroke-dashoffset")):i.setAttribute("stroke","none"),e.fill?(i.setAttribute("fill",e.fillColor||e.color),i.setAttribute("fill-opacity",e.fillOpacity),i.setAttribute("fill-rule",e.fillRule||"evenodd")):i.setAttribute("fill","none"))},_updatePoly:function(t,i){this._setPath(t,Q(t._parts,i))},_updateCircle:function(t){var i=t._point,e=Math.max(Math.round(t._radius),1),n="a"+e+","+(Math.max(Math.round(t._radiusY),1)||e)+" 0 1,0 ",o=t._empty()?"M0 0":"M"+(i.x-e)+","+i.y+n+2*e+",0 "+n+2*-e+",0 ";this._setPath(t,o)},_setPath:function(t,i){t._path.setAttribute("d",i)},_bringToFront:function(t){_i(t._path)},_bringToBack:function(t){di(t._path)}});function yn(t){return Zt||kt?new vn(t):null}kt&&vn.include(fn),$i.include({getRenderer:function(t){var i=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer;return i||(i=this._renderer=this._createRenderer()),this.hasLayer(i)||this.addLayer(i),i},_getPaneRenderer:function(t){if("overlayPane"===t||void 0===t)return!1;var i=this._paneRenderers[t];return void 0===i&&(i=this._createRenderer({pane:t}),this._paneRenderers[t]=i),i},_createRenderer:function(t){return this.options.preferCanvas&&pn(t)||yn(t)}});var xn=We.extend({initialize:function(t,i){We.prototype.initialize.call(this,this._boundsToLatLngs(t),i)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return[(t=D(t)).getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}});vn.create=gn,vn.pointsToPath=Q,He.geometryToLayer=Fe,He.coordsToLatLng=Ve,He.coordsToLatLngs=qe,He.latLngToCoords=Ge,He.latLngsToCoords=Ke,He.getFeature=Ye,He.asFeature=Xe,$i.mergeOptions({boxZoom:!0});var wn=se.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._resetStateTimeout=0,t.on("unload",this._destroy,this)},addHooks:function(){ki(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){Ai(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_destroy:function(){li(this._pane),delete this._pane},_resetState:function(){this._resetStateTimeout=0,this._moved=!1},_clearDeferredResetState:function(){0!==this._resetStateTimeout&&(clearTimeout(this._resetStateTimeout),this._resetStateTimeout=0)},_onMouseDown:function(t){if(!t.shiftKey||1!==t.which&&1!==t.button)return!1;this._clearDeferredResetState(),this._resetState(),Qt(),Ti(),this._startPoint=this._map.mouseEventToContainerPoint(t),ki(document,{contextmenu:Wi,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=ui("div","leaflet-zoom-box",this._container),mi(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var i=new O(this._point,this._startPoint),e=i.getSize();Pi(this._box,i.min),this._box.style.width=e.x+"px",this._box.style.height=e.y+"px"},_finish:function(){this._moved&&(li(this._box),fi(this._container,"leaflet-crosshair")),ti(),zi(),Ai(document,{contextmenu:Wi,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){if((1===t.which||1===t.button)&&(this._finish(),this._moved)){this._clearDeferredResetState(),this._resetStateTimeout=setTimeout(a(this._resetState,this),0);var i=new N(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point));this._map.fitBounds(i).fire("boxzoomend",{boxZoomBounds:i})}},_onKeyDown:function(t){27===t.keyCode&&this._finish()}});$i.addInitHook("addHandler","boxZoom",wn),$i.mergeOptions({doubleClickZoom:!0});var Pn=se.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var i=this._map,e=i.getZoom(),n=i.options.zoomDelta,o=t.originalEvent.shiftKey?e-n:e+n;"center"===i.options.doubleClickZoom?i.setZoom(o):i.setZoomAround(t.containerPoint,o)}});$i.addInitHook("addHandler","doubleClickZoom",Pn),$i.mergeOptions({dragging:!0,inertia:!rt,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0});var Ln=se.extend({addHooks:function(){if(!this._draggable){var t=this._map;this._draggable=new ce(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on("predrag",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDragWrap,this),t.on("zoomend",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))}mi(this._map._container,"leaflet-grab leaflet-touch-drag"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){fi(this._map._container,"leaflet-grab"),fi(this._map._container,"leaflet-touch-drag"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDragStart:function(){var t=this._map;if(t._stop(),this._map.options.maxBounds&&this._map.options.maxBoundsViscosity){var i=D(this._map.options.maxBounds);this._offsetLimit=R(this._map.latLngToContainerPoint(i.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(i.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))}else this._offsetLimit=null;t.fire("movestart").fire("dragstart"),t.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){if(this._map.options.inertia){var i=this._lastTime=+new Date,e=this._lastPos=this._draggable._absPos||this._draggable._newPos;this._positions.push(e),this._times.push(i),this._prunePositions(i)}this._map.fire("move",t).fire("drag",t)},_prunePositions:function(t){for(;1i.max.x&&(t.x=this._viscousLimit(t.x,i.max.x)),t.y>i.max.y&&(t.y=this._viscousLimit(t.y,i.max.y)),this._draggable._newPos=this._draggable._startPos.add(t)}},_onPreDragWrap:function(){var t=this._worldWidth,i=Math.round(t/2),e=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-i+e)%t+i-e,s=(n+i+e)%t-i-e,r=Math.abs(o+e)i.getMaxZoom()&&1=this.min.x&&e.x<=this.max.x&&i.y>=this.min.y&&e.y<=this.max.y},intersects:function(t){t=O(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>=i.x&&n.x<=e.x,r=o.y>=i.y&&n.y<=e.y;return s&&r},overlaps:function(t){t=O(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>i.x&&n.xi.y&&n.y=n.lat&&e.lat<=o.lat&&i.lng>=n.lng&&e.lng<=o.lng},intersects:function(t){t=N(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>=i.lat&&n.lat<=e.lat,r=o.lng>=i.lng&&n.lng<=e.lng;return s&&r},overlaps:function(t){t=N(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>i.lat&&n.lati.lng&&n.lng';var i=t.firstChild;return i.style.behavior="url(#default#VML)",i&&"object"==typeof i.adj}catch(t){return!1}}();function kt(t){return 0<=navigator.userAgent.toLowerCase().indexOf(t)}var Bt={ie:tt,ielt9:it,edge:et,webkit:nt,android:ot,android23:st,androidStock:at,opera:ht,chrome:ut,gecko:lt,safari:ct,phantom:_t,opera12:dt,win:pt,ie3d:mt,webkit3d:ft,gecko3d:gt,any3d:vt,mobile:yt,mobileWebkit:xt,mobileWebkit3d:wt,msPointer:Pt,pointer:Lt,touch:bt,mobileOpera:Tt,mobileGecko:Mt,retina:zt,passiveEvents:Ct,canvas:St,svg:Zt,vml:Et},At=Pt?"MSPointerDown":"pointerdown",It=Pt?"MSPointerMove":"pointermove",Ot=Pt?"MSPointerUp":"pointerup",Rt=Pt?"MSPointerCancel":"pointercancel",Nt={},Dt=!1;function jt(t,i,e,n){function o(t){Ut(t,r)}var s,r,a,h,u,l,c,_;function d(t){t.pointerType===(t.MSPOINTER_TYPE_MOUSE||"mouse")&&0===t.buttons||Ut(t,h)}return"touchstart"===i?(u=t,l=e,c=n,_=p(function(t){t.MSPOINTER_TYPE_TOUCH&&t.pointerType===t.MSPOINTER_TYPE_TOUCH&&Ri(t),Ut(t,l)}),u["_leaflet_touchstart"+c]=_,u.addEventListener(At,_,!1),Dt||(document.addEventListener(At,Wt,!0),document.addEventListener(It,Ht,!0),document.addEventListener(Ot,Ft,!0),document.addEventListener(Rt,Ft,!0),Dt=!0)):"touchmove"===i?(h=e,(a=t)["_leaflet_touchmove"+n]=d,a.addEventListener(It,d,!1)):"touchend"===i&&(r=e,(s=t)["_leaflet_touchend"+n]=o,s.addEventListener(Ot,o,!1),s.addEventListener(Rt,o,!1)),this}function Wt(t){Nt[t.pointerId]=t}function Ht(t){Nt[t.pointerId]&&(Nt[t.pointerId]=t)}function Ft(t){delete Nt[t.pointerId]}function Ut(t,i){for(var e in t.touches=[],Nt)t.touches.push(Nt[e]);t.changedTouches=[t],i(t)}var Vt=Pt?"MSPointerDown":Lt?"pointerdown":"touchstart",qt=Pt?"MSPointerUp":Lt?"pointerup":"touchend",Gt="_leaflet_";var Kt,Yt,Xt,Jt,$t,Qt,ti=fi(["transform","webkitTransform","OTransform","MozTransform","msTransform"]),ii=fi(["webkitTransition","transition","OTransition","MozTransition","msTransition"]),ei="webkitTransition"===ii||"OTransition"===ii?ii+"End":"transitionend";function ni(t){return"string"==typeof t?document.getElementById(t):t}function oi(t,i){var e,n=t.style[i]||t.currentStyle&&t.currentStyle[i];return n&&"auto"!==n||!document.defaultView||(n=(e=document.defaultView.getComputedStyle(t,null))?e[i]:null),"auto"===n?null:n}function si(t,i,e){var n=document.createElement(t);return n.className=i||"",e&&e.appendChild(n),n}function ri(t){var i=t.parentNode;i&&i.removeChild(t)}function ai(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function hi(t){var i=t.parentNode;i&&i.lastChild!==t&&i.appendChild(t)}function ui(t){var i=t.parentNode;i&&i.firstChild!==t&&i.insertBefore(t,i.firstChild)}function li(t,i){if(void 0!==t.classList)return t.classList.contains(i);var e=pi(t);return 0this.options.maxZoom)?this.setZoom(t):this},panInsideBounds:function(t,i){this._enforcingBounds=!0;var e=this.getCenter(),n=this._limitCenter(e,this._zoom,N(t));return e.equals(n)||this.panTo(n,i),this._enforcingBounds=!1,this},panInside:function(t,i){var e,n,o=A((i=i||{}).paddingTopLeft||i.padding||[0,0]),s=A(i.paddingBottomRight||i.padding||[0,0]),r=this.getCenter(),a=this.project(r),h=this.project(t),u=this.getPixelBounds(),l=u.getSize().divideBy(2),c=O([u.min.add(o),u.max.subtract(s)]);return c.contains(h)||(this._enforcingBounds=!0,e=a.subtract(h),n=A(h.x+e.x,h.y+e.y),(h.xc.max.x)&&(n.x=a.x-e.x,0c.max.y)&&(n.y=a.y-e.y,0=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,i){for(var e,n=[],o="mouseout"===i||"mouseover"===i,s=t.target||t.srcElement,r=!1;s;){if((e=this._targets[m(s)])&&("click"===i||"preclick"===i)&&!t._simulated&&this._draggableMoved(e)){r=!0;break}if(e&&e.listens(i,!0)){if(o&&!Vi(s,t))break;if(n.push(e),o)break}if(s===this._container)break;s=s.parentNode}return n.length||r||o||!Vi(s,t)||(n=[this]),n},_handleDOMEvent:function(t){var i;this._loaded&&!Ui(t)&&("mousedown"!==(i=t.type)&&"keypress"!==i&&"keyup"!==i&&"keydown"!==i||Pi(t.target||t.srcElement),this._fireDOMEvent(t,i))},_mouseEvents:["click","dblclick","mouseover","mouseout","contextmenu"],_fireDOMEvent:function(t,i,e){var n;if("click"===t.type&&((n=h({},t)).type="preclick",this._fireDOMEvent(n,n.type,e)),!t._stopped&&(e=(e||[]).concat(this._findEventTargets(t,i))).length){var o=e[0];"contextmenu"===i&&o.listens(i,!0)&&Ri(t);var s,r={originalEvent:t};"keypress"!==t.type&&"keydown"!==t.type&&"keyup"!==t.type&&(s=o.getLatLng&&(!o._radius||o._radius<=10),r.containerPoint=s?this.latLngToContainerPoint(o.getLatLng()):this.mouseEventToContainerPoint(t),r.layerPoint=this.containerPointToLayerPoint(r.containerPoint),r.latlng=s?o.getLatLng():this.layerPointToLatLng(r.layerPoint));for(var a=0;athis.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(i),o=this._getCenterOffset(t)._divideBy(1-1/n);return!(!0!==e.animate&&!this.getSize().contains(o))&&(M(function(){this._moveStart(!0,!1)._animateZoom(t,i,!0)},this),!0)},_animateZoom:function(t,i,e,n){this._mapPane&&(e&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=i,ci(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:i,noUpdate:n}),setTimeout(p(this._onZoomTransitionEnd,this),250))},_onZoomTransitionEnd:function(){this._animatingZoom&&(this._mapPane&&_i(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom),M(function(){this._moveEnd(!0)},this))}});function Yi(t){return new Xi(t)}var Xi=S.extend({options:{position:"topright"},initialize:function(t){c(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var i=this._map;return i&&i.removeControl(this),this.options.position=t,i&&i.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var i=this._container=this.onAdd(t),e=this.getPosition(),n=t._controlCorners[e];return ci(i,"leaflet-control"),-1!==e.indexOf("bottom")?n.insertBefore(i,n.firstChild):n.appendChild(i),this._map.on("unload",this.remove,this),this},remove:function(){return this._map&&(ri(this._container),this.onRemove&&this.onRemove(this._map),this._map.off("unload",this.remove,this),this._map=null),this},_refocusOnMap:function(t){this._map&&t&&0",n=document.createElement("div");return n.innerHTML=e,n.firstChild},_addItem:function(t){var i,e=document.createElement("label"),n=this._map.hasLayer(t.layer);t.overlay?((i=document.createElement("input")).type="checkbox",i.className="leaflet-control-layers-selector",i.defaultChecked=n):i=this._createRadioElement("leaflet-base-layers_"+m(this),n),this._layerControlInputs.push(i),i.layerId=m(t.layer),zi(i,"click",this._onInputClick,this);var o=document.createElement("span");o.innerHTML=" "+t.name;var s=document.createElement("div");return e.appendChild(s),s.appendChild(i),s.appendChild(o),(t.overlay?this._overlaysList:this._baseLayersList).appendChild(e),this._checkDisabledLayers(),e},_onInputClick:function(){var t,i,e=this._layerControlInputs,n=[],o=[];this._handlingClick=!0;for(var s=e.length-1;0<=s;s--)t=e[s],i=this._getLayer(t.layerId).layer,t.checked?n.push(i):t.checked||o.push(i);for(s=0;si.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expand:function(){return this.expand()},_collapse:function(){return this.collapse()}}),$i=Xi.extend({options:{position:"topleft",zoomInText:"+",zoomInTitle:"Zoom in",zoomOutText:"−",zoomOutTitle:"Zoom out"},onAdd:function(t){var i="leaflet-control-zoom",e=si("div",i+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,i+"-in",e,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,i+"-out",e,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),e},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,i,e,n,o){var s=si("a",e,n);return s.innerHTML=t,s.href="#",s.title=i,s.setAttribute("role","button"),s.setAttribute("aria-label",i),Oi(s),zi(s,"click",Ni),zi(s,"click",o,this),zi(s,"click",this._refocusOnMap,this),s},_updateDisabled:function(){var t=this._map,i="leaflet-disabled";_i(this._zoomInButton,i),_i(this._zoomOutButton,i),!this._disabled&&t._zoom!==t.getMinZoom()||ci(this._zoomOutButton,i),!this._disabled&&t._zoom!==t.getMaxZoom()||ci(this._zoomInButton,i)}});Ki.mergeOptions({zoomControl:!0}),Ki.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new $i,this.addControl(this.zoomControl))});var Qi=Xi.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var i="leaflet-control-scale",e=si("div",i),n=this.options;return this._addScales(n,i+"-line",e),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),e},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,i,e){t.metric&&(this._mScale=si("div",i,e)),t.imperial&&(this._iScale=si("div",i,e))},_update:function(){var t=this._map,i=t.getSize().y/2,e=t.distance(t.containerPointToLatLng([0,i]),t.containerPointToLatLng([this.options.maxWidth,i]));this._updateScales(e)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var i=this._getRoundNum(t),e=i<1e3?i+" m":i/1e3+" km";this._updateScale(this._mScale,e,i/t)},_updateImperial:function(t){var i,e,n,o=3.2808399*t;5280Leaflet'},initialize:function(t){c(this,t),this._attributions={}},onAdd:function(t){for(var i in(t.attributionControl=this)._container=si("div","leaflet-control-attribution"),Oi(this._container),t._layers)t._layers[i].getAttribution&&this.addAttribution(t._layers[i].getAttribution());return this._update(),this._container},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t&&(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update()),this},removeAttribution:function(t){return t&&this._attributions[t]&&(this._attributions[t]--,this._update()),this},_update:function(){if(this._map){var t=[];for(var i in this._attributions)this._attributions[i]&&t.push(i);var e=[];this.options.prefix&&e.push(this.options.prefix),t.length&&e.push(t.join(", ")),this._container.innerHTML=e.join(" | ")}}});Ki.mergeOptions({attributionControl:!0}),Ki.addInitHook(function(){this.options.attributionControl&&(new te).addTo(this)});Xi.Layers=Ji,Xi.Zoom=$i,Xi.Scale=Qi,Xi.Attribution=te,Yi.layers=function(t,i,e){return new Ji(t,i,e)},Yi.zoom=function(t){return new $i(t)},Yi.scale=function(t){return new Qi(t)},Yi.attribution=function(t){return new te(t)};var ie=S.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled||(this._enabled=!0,this.addHooks()),this},disable:function(){return this._enabled&&(this._enabled=!1,this.removeHooks()),this},enabled:function(){return!!this._enabled}});ie.addTo=function(t,i){return t.addHandler(i,this),this};var ee,ne={Events:Z},oe=bt?"touchstart mousedown":"mousedown",se={mousedown:"mouseup",touchstart:"touchend",pointerdown:"touchend",MSPointerDown:"touchend"},re={mousedown:"mousemove",touchstart:"touchmove",pointerdown:"touchmove",MSPointerDown:"touchmove"},ae=E.extend({options:{clickTolerance:3},initialize:function(t,i,e,n){c(this,n),this._element=t,this._dragStartTarget=i||t,this._preventOutline=e},enable:function(){this._enabled||(zi(this._dragStartTarget,oe,this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(ae._dragging===this&&this.finishDrag(),Si(this._dragStartTarget,oe,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){var i,e;!t._simulated&&this._enabled&&(this._moved=!1,li(this._element,"leaflet-zoom-anim")||ae._dragging||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||((ae._dragging=this)._preventOutline&&Pi(this._element),xi(),Xt(),this._moving||(this.fire("down"),i=t.touches?t.touches[0]:t,e=bi(this._element),this._startPoint=new k(i.clientX,i.clientY),this._parentScale=Ti(e),zi(document,re[t.type],this._onMove,this),zi(document,se[t.type],this._onUp,this))))},_onMove:function(t){var i,e;!t._simulated&&this._enabled&&(t.touches&&1i&&(e.push(t[n]),o=n);oi.max.x&&(e|=2),t.yi.max.y&&(e|=8),e}function de(t,i,e,n){var o,s=i.x,r=i.y,a=e.x-s,h=e.y-r,u=a*a+h*h;return 0this._layersMaxZoom&&this.setZoom(this._layersMaxZoom),void 0===this.options.minZoom&&this._layersMinZoom&&this.getZoom()t.y!=n.y>t.y&&t.x<(n.x-e.x)*(t.y-e.y)/(n.y-e.y)+e.x&&(u=!u);return u||Oe.prototype._containsPoint.call(this,t,!0)}});var Ne=Ce.extend({initialize:function(t,i){c(this,i),this._layers={},t&&this.addData(t)},addData:function(t){var i,e,n,o=g(t)?t:t.features;if(o){for(i=0,e=o.length;iu.x&&(l=s.x+n-u.x+h.x),s.x-l-a.x<0&&(l=s.x-a.x),s.y+e+h.y>u.y&&(c=s.y+e-u.y+h.y),s.y-c-a.y<0&&(c=s.y-a.y),(l||c)&&t.fire("autopanstart").panBy([l,c]))},_onCloseButtonClick:function(t){this._close(),Ni(t)},_getAnchor:function(){return A(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}});Ki.mergeOptions({closePopupOnClick:!0}),Ki.include({openPopup:function(t,i,e){return t instanceof tn||(t=new tn(e).setContent(t)),i&&t.setLatLng(i),this.hasLayer(t)?this:(this._popup&&this._popup.options.autoClose&&this.closePopup(),this._popup=t,this.addLayer(t))},closePopup:function(t){return t&&t!==this._popup||(t=this._popup,this._popup=null),t&&this.removeLayer(t),this}}),Me.include({bindPopup:function(t,i){return t instanceof tn?(c(t,i),(this._popup=t)._source=this):(this._popup&&!i||(this._popup=new tn(i,this)),this._popup.setContent(t)),this._popupHandlersAdded||(this.on({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t,i){return this._popup&&this._map&&(i=this._popup._prepareOpen(this,t,i),this._map.openPopup(this._popup,i)),this},closePopup:function(){return this._popup&&this._popup._close(),this},togglePopup:function(t){return this._popup&&(this._popup._map?this.closePopup():this.openPopup(t)),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var i=t.layer||t.target;this._popup&&this._map&&(Ni(t),i instanceof Be?this.openPopup(t.layer||t.target,t.latlng):this._map.hasLayer(this._popup)&&this._popup._source===i?this.closePopup():this.openPopup(i,t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)},_onKeyPress:function(t){13===t.originalEvent.keyCode&&this._openPopup(t)}});var en=Qe.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,interactive:!1,opacity:.9},onAdd:function(t){Qe.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&this._source.fire("tooltipopen",{tooltip:this},!0)},onRemove:function(t){Qe.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&this._source.fire("tooltipclose",{tooltip:this},!0)},getEvents:function(){var t=Qe.prototype.getEvents.call(this);return bt&&!this.options.permanent&&(t.preclick=this._close),t},_close:function(){this._map&&this._map.closeTooltip(this)},_initLayout:function(){var t="leaflet-tooltip "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=si("div",t)},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var i,e=this._map,n=this._container,o=e.latLngToContainerPoint(e.getCenter()),s=e.layerPointToContainerPoint(t),r=this.options.direction,a=n.offsetWidth,h=n.offsetHeight,u=A(this.options.offset),l=this._getAnchor(),c="top"===r?(i=a/2,h):"bottom"===r?(i=a/2,0):(i="center"===r?a/2:"right"===r?0:"left"===r?a:s.xthis.options.maxZoom||nthis.options.maxZoom||void 0!==this.options.minZoom&&oe.max.x)||!i.wrapLat&&(t.ye.max.y))return!1}if(!this.options.bounds)return!0;var n=this._tileCoordsToBounds(t);return N(this.options.bounds).overlaps(n)},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToNwSe:function(t){var i=this._map,e=this.getTileSize(),n=t.scaleBy(e),o=n.add(e);return[i.unproject(n,t.z),i.unproject(o,t.z)]},_tileCoordsToBounds:function(t){var i=this._tileCoordsToNwSe(t),e=new R(i[0],i[1]);return this.options.noWrap||(e=this._map.wrapLatLngBounds(e)),e},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var i=t.split(":"),e=new k(+i[0],+i[1]);return e.z=+i[2],e},_removeTile:function(t){var i=this._tiles[t];i&&(ri(i.el),delete this._tiles[t],this.fire("tileunload",{tile:i.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){ci(t,"leaflet-tile");var i=this.getTileSize();t.style.width=i.x+"px",t.style.height=i.y+"px",t.onselectstart=a,t.onmousemove=a,it&&this.options.opacity<1&&mi(t,this.options.opacity),ot&&!st&&(t.style.WebkitBackfaceVisibility="hidden")},_addTile:function(t,i){var e=this._getTilePos(t),n=this._tileCoordsToKey(t),o=this.createTile(this._wrapCoords(t),p(this._tileReady,this,t));this._initTile(o),this.createTile.length<2&&M(p(this._tileReady,this,t,null,o)),vi(o,e),this._tiles[n]={el:o,coords:t,current:!0},i.appendChild(o),this.fire("tileloadstart",{tile:o,coords:t})},_tileReady:function(t,i,e){i&&this.fire("tileerror",{error:i,tile:e,coords:t});var n=this._tileCoordsToKey(t);(e=this._tiles[n])&&(e.loaded=+new Date,this._map._fadeAnimated?(mi(e.el,0),z(this._fadeFrame),this._fadeFrame=M(this._updateOpacity,this)):(e.active=!0,this._pruneTiles()),i||(ci(e.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:e.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),it||!this._map._fadeAnimated?M(this._pruneTiles,this):setTimeout(p(this._pruneTiles,this),250)))},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var i=new k(this._wrapX?o(t.x,this._wrapX):t.x,this._wrapY?o(t.y,this._wrapY):t.y);return i.z=t.z,i},_pxBoundsToTileRange:function(t){var i=this.getTileSize();return new I(t.min.unscaleBy(i).floor(),t.max.unscaleBy(i).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}});var sn=on.extend({options:{minZoom:0,maxZoom:18,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1},initialize:function(t,i){this._url=t,(i=c(this,i)).detectRetina&&zt&&0')}}catch(t){return function(t){return document.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}(),_n={_initContainer:function(){this._container=si("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(hn.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var i=t._container=cn("shape");ci(i,"leaflet-vml-shape "+(this.options.className||"")),i.coordsize="1 1",t._path=cn("path"),i.appendChild(t._path),this._updateStyle(t),this._layers[m(t)]=t},_addPath:function(t){var i=t._container;this._container.appendChild(i),t.options.interactive&&t.addInteractiveTarget(i)},_removePath:function(t){var i=t._container;ri(i),t.removeInteractiveTarget(i),delete this._layers[m(t)]},_updateStyle:function(t){var i=t._stroke,e=t._fill,n=t.options,o=t._container;o.stroked=!!n.stroke,o.filled=!!n.fill,n.stroke?(i=i||(t._stroke=cn("stroke")),o.appendChild(i),i.weight=n.weight+"px",i.color=n.color,i.opacity=n.opacity,n.dashArray?i.dashStyle=g(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):i.dashStyle="",i.endcap=n.lineCap.replace("butt","flat"),i.joinstyle=n.lineJoin):i&&(o.removeChild(i),t._stroke=null),n.fill?(e=e||(t._fill=cn("fill")),o.appendChild(e),e.color=n.fillColor||n.color,e.opacity=n.fillOpacity):e&&(o.removeChild(e),t._fill=null)},_updateCircle:function(t){var i=t._point.round(),e=Math.round(t._radius),n=Math.round(t._radiusY||e);this._setPath(t,t._empty()?"M0 0":"AL "+i.x+","+i.y+" "+e+","+n+" 0,23592600")},_setPath:function(t,i){t._path.v=i},_bringToFront:function(t){hi(t._container)},_bringToBack:function(t){ui(t._container)}},dn=Et?cn:J,pn=hn.extend({getEvents:function(){var t=hn.prototype.getEvents.call(this);return t.zoomstart=this._onZoomStart,t},_initContainer:function(){this._container=dn("svg"),this._container.setAttribute("pointer-events","none"),this._rootGroup=dn("g"),this._container.appendChild(this._rootGroup)},_destroyContainer:function(){ri(this._container),Si(this._container),delete this._container,delete this._rootGroup,delete this._svgSize},_onZoomStart:function(){this._update()},_update:function(){var t,i,e;this._map._animatingZoom&&this._bounds||(hn.prototype._update.call(this),i=(t=this._bounds).getSize(),e=this._container,this._svgSize&&this._svgSize.equals(i)||(this._svgSize=i,e.setAttribute("width",i.x),e.setAttribute("height",i.y)),vi(e,t.min),e.setAttribute("viewBox",[t.min.x,t.min.y,i.x,i.y].join(" ")),this.fire("update"))},_initPath:function(t){var i=t._path=dn("path");t.options.className&&ci(i,t.options.className),t.options.interactive&&ci(i,"leaflet-interactive"),this._updateStyle(t),this._layers[m(t)]=t},_addPath:function(t){this._rootGroup||this._initContainer(),this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){ri(t._path),t.removeInteractiveTarget(t._path),delete this._layers[m(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var i=t._path,e=t.options;i&&(e.stroke?(i.setAttribute("stroke",e.color),i.setAttribute("stroke-opacity",e.opacity),i.setAttribute("stroke-width",e.weight),i.setAttribute("stroke-linecap",e.lineCap),i.setAttribute("stroke-linejoin",e.lineJoin),e.dashArray?i.setAttribute("stroke-dasharray",e.dashArray):i.removeAttribute("stroke-dasharray"),e.dashOffset?i.setAttribute("stroke-dashoffset",e.dashOffset):i.removeAttribute("stroke-dashoffset")):i.setAttribute("stroke","none"),e.fill?(i.setAttribute("fill",e.fillColor||e.color),i.setAttribute("fill-opacity",e.fillOpacity),i.setAttribute("fill-rule",e.fillRule||"evenodd")):i.setAttribute("fill","none"))},_updatePoly:function(t,i){this._setPath(t,$(t._parts,i))},_updateCircle:function(t){var i=t._point,e=Math.max(Math.round(t._radius),1),n="a"+e+","+(Math.max(Math.round(t._radiusY),1)||e)+" 0 1,0 ",o=t._empty()?"M0 0":"M"+(i.x-e)+","+i.y+n+2*e+",0 "+n+2*-e+",0 ";this._setPath(t,o)},_setPath:function(t,i){t._path.setAttribute("d",i)},_bringToFront:function(t){hi(t._path)},_bringToBack:function(t){ui(t._path)}});function mn(t){return Zt||Et?new pn(t):null}Et&&pn.include(_n),Ki.include({getRenderer:function(t){var i=(i=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer)||(this._renderer=this._createRenderer());return this.hasLayer(i)||this.addLayer(i),i},_getPaneRenderer:function(t){if("overlayPane"===t||void 0===t)return!1;var i=this._paneRenderers[t];return void 0===i&&(i=this._createRenderer({pane:t}),this._paneRenderers[t]=i),i},_createRenderer:function(t){return this.options.preferCanvas&&ln(t)||mn(t)}});var fn=Re.extend({initialize:function(t,i){Re.prototype.initialize.call(this,this._boundsToLatLngs(t),i)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return[(t=N(t)).getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}});pn.create=dn,pn.pointsToPath=$,Ne.geometryToLayer=De,Ne.coordsToLatLng=We,Ne.coordsToLatLngs=He,Ne.latLngToCoords=Fe,Ne.latLngsToCoords=Ue,Ne.getFeature=Ve,Ne.asFeature=qe,Ki.mergeOptions({boxZoom:!0});var gn=ie.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._resetStateTimeout=0,t.on("unload",this._destroy,this)},addHooks:function(){zi(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){Si(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_destroy:function(){ri(this._pane),delete this._pane},_resetState:function(){this._resetStateTimeout=0,this._moved=!1},_clearDeferredResetState:function(){0!==this._resetStateTimeout&&(clearTimeout(this._resetStateTimeout),this._resetStateTimeout=0)},_onMouseDown:function(t){if(!t.shiftKey||1!==t.which&&1!==t.button)return!1;this._clearDeferredResetState(),this._resetState(),Xt(),xi(),this._startPoint=this._map.mouseEventToContainerPoint(t),zi(document,{contextmenu:Ni,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=si("div","leaflet-zoom-box",this._container),ci(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var i=new I(this._point,this._startPoint),e=i.getSize();vi(this._box,i.min),this._box.style.width=e.x+"px",this._box.style.height=e.y+"px"},_finish:function(){this._moved&&(ri(this._box),_i(this._container,"leaflet-crosshair")),Jt(),wi(),Si(document,{contextmenu:Ni,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){var i;1!==t.which&&1!==t.button||(this._finish(),this._moved&&(this._clearDeferredResetState(),this._resetStateTimeout=setTimeout(p(this._resetState,this),0),i=new R(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point)),this._map.fitBounds(i).fire("boxzoomend",{boxZoomBounds:i})))},_onKeyDown:function(t){27===t.keyCode&&this._finish()}});Ki.addInitHook("addHandler","boxZoom",gn),Ki.mergeOptions({doubleClickZoom:!0});var vn=ie.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var i=this._map,e=i.getZoom(),n=i.options.zoomDelta,o=t.originalEvent.shiftKey?e-n:e+n;"center"===i.options.doubleClickZoom?i.setZoom(o):i.setZoomAround(t.containerPoint,o)}});Ki.addInitHook("addHandler","doubleClickZoom",vn),Ki.mergeOptions({dragging:!0,inertia:!st,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0});var yn=ie.extend({addHooks:function(){var t;this._draggable||(t=this._map,this._draggable=new ae(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on("predrag",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDragWrap,this),t.on("zoomend",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))),ci(this._map._container,"leaflet-grab leaflet-touch-drag"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){_i(this._map._container,"leaflet-grab"),_i(this._map._container,"leaflet-touch-drag"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDragStart:function(){var t,i=this._map;i._stop(),this._map.options.maxBounds&&this._map.options.maxBoundsViscosity?(t=N(this._map.options.maxBounds),this._offsetLimit=O(this._map.latLngToContainerPoint(t.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(t.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))):this._offsetLimit=null,i.fire("movestart").fire("dragstart"),i.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){var i,e;this._map.options.inertia&&(i=this._lastTime=+new Date,e=this._lastPos=this._draggable._absPos||this._draggable._newPos,this._positions.push(e),this._times.push(i),this._prunePositions(i)),this._map.fire("move",t).fire("drag",t)},_prunePositions:function(t){for(;1i.max.x&&(t.x=this._viscousLimit(t.x,i.max.x)),t.y>i.max.y&&(t.y=this._viscousLimit(t.y,i.max.y)),this._draggable._newPos=this._draggable._startPos.add(t))},_onPreDragWrap:function(){var t=this._worldWidth,i=Math.round(t/2),e=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-i+e)%t+i-e,s=(n+i+e)%t-i-e,r=Math.abs(o+e)i.getMaxZoom()&&1 rl2) then
- (rl1 +. 0.05) /. (rl2 +. 0.05)
- else
- (rl2 +. 0.05) /. (rl1 +. 0.05)
-
-let from_raw color =
- let get_opt = function | Some x -> x | None -> raise (Invalid_argument "Option.get") in
- let div = H.div [| HA.style ("color: " ^ color) |] [| |] in
- let body = Document.query_selector_unsafe "body" in
- let () = Element.append_child body div in
- let rgb = [%raw {| window.getComputedStyle(div).color |}] in
- let () = Element.remove_child body div in
- let xs = Js.String.split ", " (get_opt (Js.String.splitByRe [%re "/[()]/"] rgb).(1)) in
- { r = Js.Float.fromString xs.(0)
- ; g = Js.Float.fromString xs.(1)
- ; b = Js.Float.fromString xs.(2)
- }
diff --git a/src/Lib/CSV.ml b/src/Lib/CSV.ml
deleted file mode 100644
index f0366f7..0000000
--- a/src/Lib/CSV.ml
+++ /dev/null
@@ -1,76 +0,0 @@
-let to_string lines =
- let
- cell_to_string cell =
- if Js.String.includes "\"" cell then
- "\"" ^ (Js.String.replaceByRe [%re "/\"/g"] "\"\"" cell) ^ "\""
- else
- cell
- in let
- line_to_string line =
- line
- |> Js.Array.map cell_to_string
- |> Js.Array.joinWith ","
- in lines
- |> Js.Array.map line_to_string
- |> Js.Array.joinWith "\n"
-
-let parse str =
- let lines = [| |] in
- let current_line = ref [| |] in
- let current_cell = ref "" in
- let in_quote = ref false in
- let i = ref 0 in
- let l = Js.String.length str in
- let () = while !i < l do
- let cc = Js.String.get str !i in
- let nc = Js.String.get str (!i + 1) in
- let () =
- if !in_quote && cc == "\"" && nc == "\"" then
- let () = current_cell := !current_cell ^ cc in
- i := !i + 1
- else if cc == "\"" then
- in_quote := not !in_quote
- else if not !in_quote && cc == "," then
- let _ = Js.Array.push !current_cell !current_line in
- current_cell := ""
- else if not !in_quote && ((cc == "\r" && nc == "\n") || cc == "\n" || cc == "\r") then
- let _ = Js.Array.push !current_cell !current_line in
- let _ = Js.Array.push !current_line lines in
- let _ = current_line := [| |] in
- current_cell := ""
- else
- current_cell := !current_cell ^ cc
- in
- i := !i + 1
- done
- in
- let _ =
- if Js.String.length !current_cell > 0 then
- let _ = Js.Array.push !current_cell !current_line in ()
- else
- ()
- in
- let _ =
- if Js.Array.length !current_line > 0 then
- let _ = Js.Array.push !current_line lines in ()
- else
- ()
- in
- lines
-
-let to_dicts lines =
- let res = [| |] in
- let () =
- if Js.Array.length lines > 0 then
- let header = Js.Array.unsafe_get lines 0 in
- for i = 1 to Js.Array.length lines - 1 do
- let line = Js.Array.unsafe_get lines i in
- let dict = Js.Dict.empty() in
- let () =
- Js.Array.forEachi
- (fun key j -> Js.Dict.set dict key (Js.Array.unsafe_get line j))
- header
- in
- ignore (Js.Array.push dict res)
- done
- in res
diff --git a/src/Lib/ContextMenu.ml b/src/Lib/ContextMenu.ml
deleted file mode 100644
index b9ed7d4..0000000
--- a/src/Lib/ContextMenu.ml
+++ /dev/null
@@ -1,40 +0,0 @@
-let px f =
- Js.Float.toString f ^ "px"
-
-type entry =
- { label: string
- ; action: unit -> unit
- }
-
-let show mouse_event actions =
- let menu =
- H.div
- [| HA.id "g-ContextMenu"
- ; HA.style ("left: " ^ (px (Event.page_x mouse_event)) ^ "; top: " ^ (px (Event.page_y mouse_event)))
- |]
- (Js.Array.map
- (fun entry ->
- H.div
- [| HA.class_ "g-ContextMenu__Entry"
- ; HE.on_click (fun _ -> entry.action ())
- |]
- [| H.text entry.label |])
- actions)
- in
- let () = Element.append_child Document.body menu in
-
- (* Remove on click or context menu *)
- let _ =
- Js.Global.setTimeout
- (fun _ ->
- let rec f = (fun _ ->
- let () = Element.remove_child Document.body menu in
- let () = Element.remove_event_listener Document.body "click" f in
- Element.remove_event_listener Document.body "contextmenu" f)
- in
- let () = Element.add_event_listener Document.body "click" f in
- Element.add_event_listener Document.body "contextmenu" f
- )
- 0
- in
- ()
diff --git a/src/Lib/Dom/Document.ml b/src/Lib/Dom/Document.ml
deleted file mode 100644
index 46f983a..0000000
--- a/src/Lib/Dom/Document.ml
+++ /dev/null
@@ -1,20 +0,0 @@
-external body : Dom.element = "body"
- [@@bs.val] [@@bs.scope "document"]
-
-external create_element : string -> Dom.element = "createElement"
- [@@bs.val] [@@bs.scope "document"]
-
-external create_element_ns : string -> string -> Dom.element = "createElementNS"
- [@@bs.val] [@@bs.scope "document"]
-
-external query_selector : string -> Dom.element Js.Nullable.t = "querySelector"
- [@@bs.val] [@@bs.scope "document"]
-
-let query_selector_unsafe id =
- query_selector id |> Js.Nullable.toOption |> Js.Option.getExn
-
-external create_text_node : string -> Dom.element = "createTextNode"
- [@@bs.val] [@@bs.scope "document"]
-
-external location : Location.location = "location"
- [@@bs.val] [@@bs.scope "document"]
diff --git a/src/Lib/Dom/Element.ml b/src/Lib/Dom/Element.ml
deleted file mode 100644
index feb6003..0000000
--- a/src/Lib/Dom/Element.ml
+++ /dev/null
@@ -1,51 +0,0 @@
-external set_value : Dom.element -> string -> unit = "value"
- [@@bs.set]
-
-external value : Dom.element -> string = "value"
- [@@bs.get]
-
-external set_attribute : Dom.element -> string -> string -> unit = "setAttribute"
- [@@bs.send]
-
-external set_class_name : Dom.element -> string -> unit = "className"
- [@@bs.set]
-
-external add_event_listener : Dom.element -> string -> (Dom.event -> unit) -> unit
- = "addEventListener"
- [@@bs.send]
-
-external remove_event_listener : Dom.element -> string -> (Dom.event -> unit) -> unit
- = "removeEventListener"
- [@@bs.send]
-
-external append_child : Dom.element -> Dom.element -> unit = "appendChild"
- [@@bs.send]
-
-external first_child : Dom.element -> Dom.element Js.Nullable.t = "firstChild"
- [@@bs.get]
-
-external remove_child : Dom.element -> Dom.element -> unit = "removeChild"
- [@@bs.send]
-
-external click : Dom.element -> unit = "click"
- [@@bs.send]
-
-let remove_first_child element =
- match Js.toOption (first_child element) with
- | Some child ->
- let () = remove_child element child in
- true
- | _ -> false
-
-let rec remove_children element =
- if remove_first_child element then remove_children element else ()
-
-let mount_on base element =
- let () = remove_children base in
- append_child base element
-
-external files : Dom.element -> string Js.Array.t = "files"
- [@@bs.get]
-
-external focus : Dom.element -> unit = "focus"
- [@@bs.send]
diff --git a/src/Lib/Dom/Event.ml b/src/Lib/Dom/Event.ml
deleted file mode 100644
index 5a9790f..0000000
--- a/src/Lib/Dom/Event.ml
+++ /dev/null
@@ -1,17 +0,0 @@
-external prevent_default : Dom.event -> unit = "preventDefault"
- [@@bs.send]
-
-external stop_propagation : Dom.event -> unit = "stopPropagation"
- [@@bs.send]
-
-external target : Dom.event -> Dom.element = "target"
- [@@bs.get]
-
-external related_target : Dom.event -> Dom.element Js.Nullable.t = "relatedTarget"
- [@@bs.get]
-
-external page_x : Dom.mouseEvent -> float = "pageX"
- [@@bs.get]
-
-external page_y : Dom.mouseEvent -> float = "pageY"
- [@@bs.get]
diff --git a/src/Lib/Dom/H.ml b/src/Lib/Dom/H.ml
deleted file mode 100644
index 7213daf..0000000
--- a/src/Lib/Dom/H.ml
+++ /dev/null
@@ -1,65 +0,0 @@
-(* Element creation *)
-
-type attribute =
- | TextAttr of string * string
- | EventAttr of string * (Dom.event -> unit)
-
-let h tag attributes children =
- let element =
- if tag == "svg" || tag == "path" then
- Document.create_element_ns "http://www.w3.org/2000/svg" tag
- else Document.create_element tag
- in
- let () =
- Js.Array.forEach
- (fun attr ->
- match attr with
- | TextAttr (name, value) ->
- Element.set_attribute element name value
-
- | EventAttr (name, eventListener) ->
- Element.add_event_listener element name eventListener)
- attributes
- in
- let () =
- Js.Array.forEach
- (fun child -> Element.append_child element child)
- children
- in
- element
-
-(* Node creation *)
-
-let text = Document.create_text_node
-
-let div = h "div"
-
-let span = h "span"
-
-let header = h "header"
-
-let button = h "button"
-
-let section = h "section"
-
-let svg = h "svg"
-
-let path = h "path"
-
-let form = h "form"
-
-let label = h "label"
-
-let input = h "input"
-
-let textarea = h "textarea"
-
-let i = h "i"
-
-let a = h "a"
-
-let h1 = h "h1"
-
-let h2 = h "h2"
-
-let h3 = h "h3"
diff --git a/src/Lib/Dom/HA.ml b/src/Lib/Dom/HA.ml
deleted file mode 100644
index ce02f2a..0000000
--- a/src/Lib/Dom/HA.ml
+++ /dev/null
@@ -1,43 +0,0 @@
-let concat xs ys =
- let partition_class =
- Js.Array.reduce
- (fun (class_acc, rest_acc) z ->
- match z with
- | H.TextAttr ("class", c) -> (class_acc ^ " " ^ c, rest_acc)
- | _ -> (class_acc, Js.Array.concat [| z |] rest_acc)
- )
- ("", [| |])
- in
- let (xs_class, xs_rest) = partition_class xs in
- let (ys_class, ys_rest) = partition_class ys in
- let rest = Js.Array.concat xs_rest ys_rest in
- if xs_class == "" && ys_class == "" then
- rest
- else
- Js.Array.concat [| H.TextAttr ("class", xs_class ^ " " ^ ys_class) |] rest
-
-(* Attribute creation *)
-
-let id v = H.TextAttr ("id", v)
-
-let class_ v = H.TextAttr ("class", v)
-
-let viewBox v = H.TextAttr ("viewBox", v)
-
-let d v = H.TextAttr ("d", v)
-
-let type_ v = H.TextAttr ("type", v)
-
-let min_ v = H.TextAttr ("min", v)
-
-let value v = H.TextAttr ("value", v)
-
-let for_ v = H.TextAttr ("for", v)
-
-let style v = H.TextAttr ("style", v)
-
-let href v = H.TextAttr ("href", v)
-
-let autocomplete v = H.TextAttr ("autocomplete", v)
-
-let download v = H.TextAttr ("download", v)
diff --git a/src/Lib/Dom/HE.ml b/src/Lib/Dom/HE.ml
deleted file mode 100644
index 03d2386..0000000
--- a/src/Lib/Dom/HE.ml
+++ /dev/null
@@ -1,13 +0,0 @@
-(* Event listeners *)
-
-let on_click f = H.EventAttr ("click", f)
-
-let on_input f = H.EventAttr ("input", f)
-
-let on_submit f = H.EventAttr ("submit", f)
-
-let on_blur f = H.EventAttr ("blur", f)
-
-let on_change f = H.EventAttr ("change", f)
-
-let on_focus f = H.EventAttr ("focus", f)
diff --git a/src/Lib/Dom/History.ml b/src/Lib/Dom/History.ml
deleted file mode 100644
index ce7a877..0000000
--- a/src/Lib/Dom/History.ml
+++ /dev/null
@@ -1,2 +0,0 @@
-external push_state : string -> string -> string -> unit -> unit = "pushState"
- [@@bs.val] [@@bs.scope "history"]
diff --git a/src/Lib/Dom/Location.ml b/src/Lib/Dom/Location.ml
deleted file mode 100644
index 2c58705..0000000
--- a/src/Lib/Dom/Location.ml
+++ /dev/null
@@ -1,7 +0,0 @@
-external set : Dom.element -> string -> unit = "location"
- [@@bs.set]
-
-type location
-
-external hash : location -> string = "hash"
- [@@bs.get]
diff --git a/src/Lib/Dom/Window.ml b/src/Lib/Dom/Window.ml
deleted file mode 100644
index 3abc921..0000000
--- a/src/Lib/Dom/Window.ml
+++ /dev/null
@@ -1,2 +0,0 @@
-external window : Dom.element = "window"
- [@@bs.val]
diff --git a/src/Lib/File.ml b/src/Lib/File.ml
deleted file mode 100644
index d3597e7..0000000
--- a/src/Lib/File.ml
+++ /dev/null
@@ -1,21 +0,0 @@
-let download filename content =
- let a =
- H.a
- [| HA.href ("data:text/plain;charset=utf-8," ^ URI.encode content)
- ; HA.download filename
- ; HA.style "display:none"
- |]
- [| |]
- in
- let () = Element.append_child Document.body a in
- let () = Element.click a in
- Element.remove_child Document.body a
-
-external reader : unit -> Dom.element = "FileReader"
- [@@bs.new]
-
-external read_as_text : Dom.element -> string -> unit = "readAsText"
- [@@bs.send]
-
-external result : Dom.element -> string = "result"
- [@@bs.get]
diff --git a/src/Lib/FontAwesome.ml b/src/Lib/FontAwesome.ml
deleted file mode 100644
index daaf954..0000000
--- a/src/Lib/FontAwesome.ml
+++ /dev/null
@@ -1,788 +0,0 @@
-let icons =
- [| "500px"
- ; "address-book"
- ; "address-book-o"
- ; "address-card"
- ; "address-card-o"
- ; "adjust"
- ; "adn"
- ; "align-center"
- ; "align-justify"
- ; "align-left"
- ; "align-right"
- ; "amazon"
- ; "ambulance"
- ; "american-sign-language-interpreting"
- ; "anchor"
- ; "android"
- ; "angellist"
- ; "angle-double-down"
- ; "angle-double-left"
- ; "angle-double-right"
- ; "angle-double-up"
- ; "angle-down"
- ; "angle-left"
- ; "angle-right"
- ; "angle-up"
- ; "apple"
- ; "archive"
- ; "area-chart"
- ; "arrow-circle-down"
- ; "arrow-circle-left"
- ; "arrow-circle-o-down"
- ; "arrow-circle-o-left"
- ; "arrow-circle-o-right"
- ; "arrow-circle-o-up"
- ; "arrow-circle-right"
- ; "arrow-circle-up"
- ; "arrow-down"
- ; "arrow-left"
- ; "arrow-right"
- ; "arrow-up"
- ; "arrows"
- ; "arrows-alt"
- ; "arrows-h"
- ; "arrows-v"
- ; "asl-interpreting"
- ; "assistive-listening-systems"
- ; "asterisk"
- ; "at"
- ; "audio-description"
- ; "automobile"
- ; "backward"
- ; "balance-scale"
- ; "ban"
- ; "bandcamp"
- ; "bank"
- ; "bar-chart"
- ; "bar-chart-o"
- ; "barcode"
- ; "bars"
- ; "bath"
- ; "bathtub"
- ; "battery"
- ; "battery-0"
- ; "battery-1"
- ; "battery-2"
- ; "battery-3"
- ; "battery-4"
- ; "battery-empty"
- ; "battery-full"
- ; "battery-half"
- ; "battery-quarter"
- ; "battery-three-quarters"
- ; "bed"
- ; "beer"
- ; "behance"
- ; "behance-square"
- ; "bell"
- ; "bell-o"
- ; "bell-slash"
- ; "bell-slash-o"
- ; "bicycle"
- ; "binoculars"
- ; "birthday-cake"
- ; "bitbucket"
- ; "bitbucket-square"
- ; "bitcoin"
- ; "black-tie"
- ; "blind"
- ; "bluetooth"
- ; "bluetooth-b"
- ; "bold"
- ; "bolt"
- ; "bomb"
- ; "book"
- ; "bookmark"
- ; "bookmark-o"
- ; "braille"
- ; "briefcase"
- ; "btc"
- ; "bug"
- ; "building"
- ; "building-o"
- ; "bullhorn"
- ; "bullseye"
- ; "bus"
- ; "buysellads"
- ; "cab"
- ; "calculator"
- ; "calendar"
- ; "calendar-check-o"
- ; "calendar-minus-o"
- ; "calendar-o"
- ; "calendar-plus-o"
- ; "calendar-times-o"
- ; "camera"
- ; "camera-retro"
- ; "car"
- ; "caret-down"
- ; "caret-left"
- ; "caret-right"
- ; "caret-square-o-down"
- ; "caret-square-o-left"
- ; "caret-square-o-right"
- ; "caret-square-o-up"
- ; "caret-up"
- ; "cart-arrow-down"
- ; "cart-plus"
- ; "cc"
- ; "cc-amex"
- ; "cc-diners-club"
- ; "cc-discover"
- ; "cc-jcb"
- ; "cc-mastercard"
- ; "cc-paypal"
- ; "cc-stripe"
- ; "cc-visa"
- ; "certificate"
- ; "chain"
- ; "chain-broken"
- ; "check"
- ; "check-circle"
- ; "check-circle-o"
- ; "check-square"
- ; "check-square-o"
- ; "chevron-circle-down"
- ; "chevron-circle-left"
- ; "chevron-circle-right"
- ; "chevron-circle-up"
- ; "chevron-down"
- ; "chevron-left"
- ; "chevron-right"
- ; "chevron-up"
- ; "child"
- ; "chrome"
- ; "circle"
- ; "circle-o"
- ; "circle-o-notch"
- ; "circle-thin"
- ; "clipboard"
- ; "clock-o"
- ; "clone"
- ; "close"
- ; "cloud"
- ; "cloud-download"
- ; "cloud-upload"
- ; "cny"
- ; "code"
- ; "code-fork"
- ; "codepen"
- ; "codiepie"
- ; "coffee"
- ; "cog"
- ; "cogs"
- ; "columns"
- ; "comment"
- ; "comment-o"
- ; "commenting"
- ; "commenting-o"
- ; "comments"
- ; "comments-o"
- ; "compass"
- ; "compress"
- ; "connectdevelop"
- ; "contao"
- ; "copy"
- ; "copyright"
- ; "creative-commons"
- ; "credit-card"
- ; "credit-card-alt"
- ; "crop"
- ; "crosshairs"
- ; "css3"
- ; "cube"
- ; "cubes"
- ; "cut"
- ; "cutlery"
- ; "dashboard"
- ; "dashcube"
- ; "database"
- ; "deaf"
- ; "deafness"
- ; "dedent"
- ; "delicious"
- ; "desktop"
- ; "deviantart"
- ; "diamond"
- ; "digg"
- ; "dollar"
- ; "dot-circle-o"
- ; "download"
- ; "dribbble"
- ; "drivers-license"
- ; "drivers-license-o"
- ; "dropbox"
- ; "drupal"
- ; "edge"
- ; "edit"
- ; "eercast"
- ; "eject"
- ; "ellipsis-h"
- ; "ellipsis-v"
- ; "empire"
- ; "envelope"
- ; "envelope-o"
- ; "envelope-open"
- ; "envelope-open-o"
- ; "envelope-square"
- ; "envira"
- ; "eraser"
- ; "etsy"
- ; "eur"
- ; "euro"
- ; "exchange"
- ; "exclamation"
- ; "exclamation-circle"
- ; "exclamation-triangle"
- ; "expand"
- ; "expeditedssl"
- ; "external-link"
- ; "external-link-square"
- ; "eye"
- ; "eye-slash"
- ; "eyedropper"
- ; "fa"
- ; "facebook"
- ; "facebook-f"
- ; "facebook-official"
- ; "facebook-square"
- ; "fast-backward"
- ; "fast-forward"
- ; "fax"
- ; "feed"
- ; "female"
- ; "fighter-jet"
- ; "file"
- ; "file-archive-o"
- ; "file-audio-o"
- ; "file-code-o"
- ; "file-excel-o"
- ; "file-image-o"
- ; "file-movie-o"
- ; "file-o"
- ; "file-pdf-o"
- ; "file-photo-o"
- ; "file-picture-o"
- ; "file-powerpoint-o"
- ; "file-sound-o"
- ; "file-text"
- ; "file-text-o"
- ; "file-video-o"
- ; "file-word-o"
- ; "file-zip-o"
- ; "files-o"
- ; "film"
- ; "filter"
- ; "fire"
- ; "fire-extinguisher"
- ; "firefox"
- ; "first-order"
- ; "flag"
- ; "flag-checkered"
- ; "flag-o"
- ; "flash"
- ; "flask"
- ; "flickr"
- ; "floppy-o"
- ; "folder"
- ; "folder-o"
- ; "folder-open"
- ; "folder-open-o"
- ; "font"
- ; "font-awesome"
- ; "fonticons"
- ; "fort-awesome"
- ; "forumbee"
- ; "forward"
- ; "foursquare"
- ; "free-code-camp"
- ; "frown-o"
- ; "futbol-o"
- ; "gamepad"
- ; "gavel"
- ; "gbp"
- ; "ge"
- ; "gear"
- ; "gears"
- ; "genderless"
- ; "get-pocket"
- ; "gg"
- ; "gg-circle"
- ; "gift"
- ; "git"
- ; "git-square"
- ; "github"
- ; "github-alt"
- ; "github-square"
- ; "gitlab"
- ; "gittip"
- ; "glass"
- ; "glide"
- ; "glide-g"
- ; "globe"
- ; "google"
- ; "google-plus"
- ; "google-plus-circle"
- ; "google-plus-official"
- ; "google-plus-square"
- ; "google-wallet"
- ; "graduation-cap"
- ; "gratipay"
- ; "grav"
- ; "group"
- ; "h-square"
- ; "hacker-news"
- ; "hand-grab-o"
- ; "hand-lizard-o"
- ; "hand-o-down"
- ; "hand-o-left"
- ; "hand-o-right"
- ; "hand-o-up"
- ; "hand-paper-o"
- ; "hand-peace-o"
- ; "hand-pointer-o"
- ; "hand-rock-o"
- ; "hand-scissors-o"
- ; "hand-spock-o"
- ; "hand-stop-o"
- ; "handshake-o"
- ; "hard-of-hearing"
- ; "hashtag"
- ; "hdd-o"
- ; "header"
- ; "headphones"
- ; "heart"
- ; "heart-o"
- ; "heartbeat"
- ; "history"
- ; "home"
- ; "hospital-o"
- ; "hotel"
- ; "hourglass"
- ; "hourglass-1"
- ; "hourglass-2"
- ; "hourglass-3"
- ; "hourglass-end"
- ; "hourglass-half"
- ; "hourglass-o"
- ; "hourglass-start"
- ; "houzz"
- ; "html5"
- ; "i-cursor"
- ; "id-badge"
- ; "id-card"
- ; "id-card-o"
- ; "ils"
- ; "image"
- ; "imdb"
- ; "inbox"
- ; "indent"
- ; "industry"
- ; "info"
- ; "info-circle"
- ; "inr"
- ; "instagram"
- ; "institution"
- ; "internet-explorer"
- ; "intersex"
- ; "ioxhost"
- ; "italic"
- ; "joomla"
- ; "jpy"
- ; "jsfiddle"
- ; "key"
- ; "keyboard-o"
- ; "krw"
- ; "language"
- ; "laptop"
- ; "lastfm"
- ; "lastfm-square"
- ; "leaf"
- ; "leanpub"
- ; "legal"
- ; "lemon-o"
- ; "level-down"
- ; "level-up"
- ; "life-bouy"
- ; "life-buoy"
- ; "life-ring"
- ; "life-saver"
- ; "lightbulb-o"
- ; "line-chart"
- ; "link"
- ; "linkedin"
- ; "linkedin-square"
- ; "linode"
- ; "linux"
- ; "list"
- ; "list-alt"
- ; "list-ol"
- ; "list-ul"
- ; "location-arrow"
- ; "lock"
- ; "long-arrow-down"
- ; "long-arrow-left"
- ; "long-arrow-right"
- ; "long-arrow-up"
- ; "low-vision"
- ; "magic"
- ; "magnet"
- ; "mail-forward"
- ; "mail-reply"
- ; "mail-reply-all"
- ; "male"
- ; "map"
- ; "map-marker"
- ; "map-o"
- ; "map-pin"
- ; "map-signs"
- ; "mars"
- ; "mars-double"
- ; "mars-stroke"
- ; "mars-stroke-h"
- ; "mars-stroke-v"
- ; "maxcdn"
- ; "meanpath"
- ; "medium"
- ; "medkit"
- ; "meetup"
- ; "meh-o"
- ; "mercury"
- ; "microchip"
- ; "microphone"
- ; "microphone-slash"
- ; "minus"
- ; "minus-circle"
- ; "minus-square"
- ; "minus-square-o"
- ; "mixcloud"
- ; "mobile"
- ; "mobile-phone"
- ; "modx"
- ; "money"
- ; "moon-o"
- ; "mortar-board"
- ; "motorcycle"
- ; "mouse-pointer"
- ; "music"
- ; "navicon"
- ; "neuter"
- ; "newspaper-o"
- ; "object-group"
- ; "object-ungroup"
- ; "odnoklassniki"
- ; "odnoklassniki-square"
- ; "opencart"
- ; "openid"
- ; "opera"
- ; "optin-monster"
- ; "outdent"
- ; "pagelines"
- ; "paint-brush"
- ; "paper-plane"
- ; "paper-plane-o"
- ; "paperclip"
- ; "paragraph"
- ; "paste"
- ; "pause"
- ; "pause-circle"
- ; "pause-circle-o"
- ; "paw"
- ; "paypal"
- ; "pencil"
- ; "pencil-square"
- ; "pencil-square-o"
- ; "percent"
- ; "phone"
- ; "phone-square"
- ; "photo"
- ; "picture-o"
- ; "pie-chart"
- ; "pied-piper"
- ; "pied-piper-alt"
- ; "pied-piper-pp"
- ; "pinterest"
- ; "pinterest-p"
- ; "pinterest-square"
- ; "plane"
- ; "play"
- ; "play-circle"
- ; "play-circle-o"
- ; "plug"
- ; "plus"
- ; "plus-circle"
- ; "plus-square"
- ; "plus-square-o"
- ; "podcast"
- ; "power-off"
- ; "print"
- ; "product-hunt"
- ; "puzzle-piece"
- ; "qq"
- ; "qrcode"
- ; "question"
- ; "question-circle"
- ; "question-circle-o"
- ; "quora"
- ; "quote-left"
- ; "quote-right"
- ; "ra"
- ; "random"
- ; "ravelry"
- ; "rebel"
- ; "recycle"
- ; "reddit"
- ; "reddit-alien"
- ; "reddit-square"
- ; "refresh"
- ; "registered"
- ; "remove"
- ; "renren"
- ; "reorder"
- ; "repeat"
- ; "reply"
- ; "reply-all"
- ; "resistance"
- ; "retweet"
- ; "rmb"
- ; "road"
- ; "rocket"
- ; "rotate-left"
- ; "rotate-right"
- ; "rouble"
- ; "rss"
- ; "rss-square"
- ; "rub"
- ; "ruble"
- ; "rupee"
- ; "s15"
- ; "safari"
- ; "save"
- ; "scissors"
- ; "scribd"
- ; "search"
- ; "search-minus"
- ; "search-plus"
- ; "sellsy"
- ; "send"
- ; "send-o"
- ; "server"
- ; "share"
- ; "share-alt"
- ; "share-alt-square"
- ; "share-square"
- ; "share-square-o"
- ; "shekel"
- ; "sheqel"
- ; "shield"
- ; "ship"
- ; "shirtsinbulk"
- ; "shopping-bag"
- ; "shopping-basket"
- ; "shopping-cart"
- ; "shower"
- ; "sign-in"
- ; "sign-language"
- ; "sign-out"
- ; "signal"
- ; "signing"
- ; "simplybuilt"
- ; "sitemap"
- ; "skyatlas"
- ; "skype"
- ; "slack"
- ; "sliders"
- ; "slideshare"
- ; "smile-o"
- ; "snapchat"
- ; "snapchat-ghost"
- ; "snapchat-square"
- ; "snowflake-o"
- ; "soccer-ball-o"
- ; "sort"
- ; "sort-alpha-asc"
- ; "sort-alpha-desc"
- ; "sort-amount-asc"
- ; "sort-amount-desc"
- ; "sort-asc"
- ; "sort-desc"
- ; "sort-down"
- ; "sort-numeric-asc"
- ; "sort-numeric-desc"
- ; "sort-up"
- ; "soundcloud"
- ; "space-shuttle"
- ; "spinner"
- ; "spoon"
- ; "spotify"
- ; "square"
- ; "square-o"
- ; "stack-exchange"
- ; "stack-overflow"
- ; "star"
- ; "star-half"
- ; "star-half-empty"
- ; "star-half-full"
- ; "star-half-o"
- ; "star-o"
- ; "steam"
- ; "steam-square"
- ; "step-backward"
- ; "step-forward"
- ; "stethoscope"
- ; "sticky-note"
- ; "sticky-note-o"
- ; "stop"
- ; "stop-circle"
- ; "stop-circle-o"
- ; "street-view"
- ; "strikethrough"
- ; "stumbleupon"
- ; "stumbleupon-circle"
- ; "subscript"
- ; "subway"
- ; "suitcase"
- ; "sun-o"
- ; "superpowers"
- ; "superscript"
- ; "support"
- ; "table"
- ; "tablet"
- ; "tachometer"
- ; "tag"
- ; "tags"
- ; "tasks"
- ; "taxi"
- ; "telegram"
- ; "television"
- ; "tencent-weibo"
- ; "terminal"
- ; "text-height"
- ; "text-width"
- ; "th"
- ; "th-large"
- ; "th-list"
- ; "themeisle"
- ; "thermometer"
- ; "thermometer-0"
- ; "thermometer-1"
- ; "thermometer-2"
- ; "thermometer-3"
- ; "thermometer-4"
- ; "thermometer-empty"
- ; "thermometer-full"
- ; "thermometer-half"
- ; "thermometer-quarter"
- ; "thermometer-three-quarters"
- ; "thumb-tack"
- ; "thumbs-down"
- ; "thumbs-o-down"
- ; "thumbs-o-up"
- ; "thumbs-up"
- ; "ticket"
- ; "times"
- ; "times-circle"
- ; "times-circle-o"
- ; "times-rectangle"
- ; "times-rectangle-o"
- ; "tint"
- ; "toggle-down"
- ; "toggle-left"
- ; "toggle-off"
- ; "toggle-on"
- ; "toggle-right"
- ; "toggle-up"
- ; "trademark"
- ; "train"
- ; "transgender"
- ; "transgender-alt"
- ; "trash"
- ; "trash-o"
- ; "tree"
- ; "trello"
- ; "tripadvisor"
- ; "trophy"
- ; "truck"
- ; "try"
- ; "tty"
- ; "tumblr"
- ; "tumblr-square"
- ; "turkish-lira"
- ; "tv"
- ; "twitch"
- ; "twitter"
- ; "twitter-square"
- ; "umbrella"
- ; "underline"
- ; "undo"
- ; "universal-access"
- ; "university"
- ; "unlink"
- ; "unlock"
- ; "unlock-alt"
- ; "unsorted"
- ; "upload"
- ; "usb"
- ; "usd"
- ; "user"
- ; "user-circle"
- ; "user-circle-o"
- ; "user-md"
- ; "user-o"
- ; "user-plus"
- ; "user-secret"
- ; "user-times"
- ; "users"
- ; "vcard"
- ; "vcard-o"
- ; "venus"
- ; "venus-double"
- ; "venus-mars"
- ; "viacoin"
- ; "viadeo"
- ; "viadeo-square"
- ; "video-camera"
- ; "vimeo"
- ; "vimeo-square"
- ; "vine"
- ; "vk"
- ; "volume-control-phone"
- ; "volume-down"
- ; "volume-off"
- ; "volume-up"
- ; "warning"
- ; "wechat"
- ; "weibo"
- ; "weixin"
- ; "whatsapp"
- ; "wheelchair"
- ; "wheelchair-alt"
- ; "wifi"
- ; "wikipedia-w"
- ; "window-close"
- ; "window-close-o"
- ; "window-maximize"
- ; "window-minimize"
- ; "window-restore"
- ; "windows"
- ; "won"
- ; "wordpress"
- ; "wpbeginner"
- ; "wpexplorer"
- ; "wpforms"
- ; "wrench"
- ; "xing"
- ; "xing-square"
- ; "y-combinator"
- ; "y-combinator-square"
- ; "yahoo"
- ; "yc"
- ; "yc-square"
- ; "yelp"
- ; "yen"
- ; "yoast"
- ; "youtube"
- ; "youtube-play"
- ; "youtube-square"
- |]
diff --git a/src/Lib/Fun.ml b/src/Lib/Fun.ml
deleted file mode 100644
index bf1eb38..0000000
--- a/src/Lib/Fun.ml
+++ /dev/null
@@ -1,2 +0,0 @@
-let flip f b a =
- f a b
diff --git a/src/Lib/Leaflet.ml b/src/Lib/Leaflet.ml
deleted file mode 100644
index 282b5b0..0000000
--- a/src/Lib/Leaflet.ml
+++ /dev/null
@@ -1,89 +0,0 @@
-type layer
-
-type map_options =
- { attributionControl : bool
- }
-
-external map : string -> map_options -> layer = "map"
- [@@bs.val] [@@bs.scope "L"]
-
-external setView : layer -> float array -> int -> unit = "setView"
- [@@bs.send]
-
-type event
-
-external on : layer -> string -> (event -> unit) -> unit = "on"
- [@@bs.send]
-
-type lat_lng =
- { lat : float;
- lng : float;
- }
-
-external original_event : event -> Dom.mouseEvent = "originalEvent"
- [@@bs.get]
-
-external lat_lng : event -> lat_lng = "latlng"
- [@@bs.get]
-
-external target : event -> layer = "target"
- [@@bs.get]
-
-external get_lat_lng : layer -> unit -> lat_lng = "getLatLng"
- [@@bs.send]
-
-external title_layer : string -> layer = "tileLayer"
- [@@bs.val] [@@bs.scope "L"]
-
-external add_layer : layer -> layer -> unit = "addLayer"
- [@@bs.send]
-
-external clear_layers : layer -> unit = "clearLayers"
- [@@bs.send]
-
-external remove : layer -> unit = "remove"
- [@@bs.send]
-
-external get_layers : layer -> unit -> layer array = "getLayers"
- [@@bs.send]
-
-(* Fit bounds *)
-
-external feature_group : layer array -> layer = "featureGroup"
- [@@bs.val] [@@bs.scope "L"]
-
-type bounds
-
-external get_bounds : layer -> unit -> bounds = "getBounds"
- [@@bs.send]
-
-type fit_bounds_options =
- { padding: float array
- }
-
-external fit_bounds : layer -> bounds -> fit_bounds_options -> unit = "fitBounds"
- [@@bs.send]
-
-(* Icon *)
-
-type icon
-
-type div_icon_input =
- { className : string
- ; popupAnchor : float array
- ; html : Dom.element
- }
-
-external div_icon : div_icon_input -> icon = "divIcon"
- [@@bs.val] [@@bs.scope "L"]
-
-(* Marker *)
-
-type markerInput =
- { title : string
- ; icon : icon
- ; draggable : bool
- }
-
-external marker : lat_lng -> markerInput -> layer = "marker"
- [@@bs.val] [@@bs.scope "L"]
diff --git a/src/Lib/Modal.ml b/src/Lib/Modal.ml
deleted file mode 100644
index 5db88cd..0000000
--- a/src/Lib/Modal.ml
+++ /dev/null
@@ -1,25 +0,0 @@
-let hide () =
- let modal = Document.query_selector_unsafe "#g-Modal" in
- Element.remove_child Document.body modal
-
-let show content =
- let view =
- H.div
- [| HA.id "g-Modal" |]
- [| H.div
- [| HA.class_ "g-Modal__Curtain"
- ; HE.on_click (fun _ -> hide ())
- |]
- [| |]
- ; H.div
- [| HA.class_ "g-Modal__Window" |]
- [| Button.raw
- [| HA.class_ "g-Modal__Close"
- ; HE.on_click (fun _ -> hide ())
- |]
- [| H.div [| HA.class_ "fa fa-close" |] [| |] |]
- ; content
- |]
- |]
- in
- Element.append_child Document.body view
diff --git a/src/Lib/Option.ml b/src/Lib/Option.ml
deleted file mode 100644
index 1158b96..0000000
--- a/src/Lib/Option.ml
+++ /dev/null
@@ -1,9 +0,0 @@
-let withDefault default opt =
- match opt with
- | Some v -> v
- | None -> default
-
-let map f opt =
- match opt with
- | Some v -> Some (f v)
- | None -> None
diff --git a/src/Lib/String.ml b/src/Lib/String.ml
deleted file mode 100644
index be16d0e..0000000
--- a/src/Lib/String.ml
+++ /dev/null
@@ -1,35 +0,0 @@
-let format_float precision f =
- let str = Js.Float.toString f in
- match Js.String.split "." str with
- | [| a ; b |] -> a ^ "." ^ (Js.String.substring ~from:0 ~to_:precision b)
- | _ -> str
-
-external btoa : string -> string = "btoa"
- [@@bs.val] [@@bs.scope "window"]
-
-external atob : string -> string = "atob"
- [@@bs.val] [@@bs.scope "window"]
-
-external unescape : string -> string = "unescape"
- [@@bs.val]
-
-external escape : string -> string = "escape"
- [@@bs.val]
-
-external encodeURIComponent : string -> string = "encodeURIComponent"
- [@@bs.val]
-
-external decodeURIComponent : string -> string = "decodeURIComponent"
- [@@bs.val]
-
-let encode str =
- str
- |> encodeURIComponent
- |> unescape
- |> btoa
-
-let decode str =
- str
- |> atob
- |> escape
- |> decodeURIComponent
diff --git a/src/Lib/URI.ml b/src/Lib/URI.ml
deleted file mode 100644
index 705bc7b..0000000
--- a/src/Lib/URI.ml
+++ /dev/null
@@ -1,2 +0,0 @@
-external encode : string -> string = "encodeURIComponent"
- [@@bs.val]
diff --git a/src/Main.ml b/src/Main.ml
deleted file mode 100644
index 9216b35..0000000
--- a/src/Main.ml
+++ /dev/null
@@ -1,3 +0,0 @@
-let () =
- let body = Document.query_selector_unsafe "body" in
- Element.append_child body (Map.render ())
diff --git a/src/State.ml b/src/State.ml
deleted file mode 100644
index c1cb99d..0000000
--- a/src/State.ml
+++ /dev/null
@@ -1,119 +0,0 @@
-type marker_state =
- { pos : Leaflet.lat_lng
- ; name : string
- ; color : string
- ; icon : string
- }
-
-let remove state pos =
- Js.Array.filter (fun m -> m.pos != pos) state
-
-let update state previousPos marker =
- Js.Array.concat [| marker |] (remove state previousPos)
-
-let last_added state =
- if Js.Array.length state > 0 then
- Some state.(0)
- else
- None
-
-(* URL Serialization *)
-
-let sep = "|"
-
-let marker_to_string marker =
- [| String.format_float 6 marker.pos.lat
- ; String.format_float 6 marker.pos.lng
- ; marker.name
- ; marker.color
- ; marker.icon
- |]
- |> Js.Array.joinWith sep
-
-let to_url_string state =
- state
- |> Js.Array.map marker_to_string
- |> Js.Array.joinWith sep
- |> String.encode
-
-let from_url_string str =
- let (_, _, res) = Js.Array.reduce
- (fun (acc_str, acc_marker, acc_state) c ->
- let length = Js.Array.length acc_marker in
- if c != sep then
- (acc_str ^ c, acc_marker, acc_state)
- else if c == sep && length < 4 then
- ("", Js.Array.concat [| acc_str |] acc_marker, acc_state)
- else
- let marker =
- { pos =
- { lat = Js.Float.fromString acc_marker.(0)
- ; lng = Js.Float.fromString acc_marker.(1)
- }
- ; name = acc_marker.(2)
- ; color = acc_marker.(3)
- ; icon = acc_str
- }
- in ("", [| |], Js.Array.concat acc_state [| marker |])
- )
- ("", [| |], [| |])
- (Js.Array.from (Js.String.castToArrayLike ((String.decode str) ^ sep)))
- in res
-
-(* Colors *)
-
-let default_color = "#3f92cf"
-
-let colors =
- Js.Array.reduce
- (fun colors marker ->
- if Js.Array.indexOf marker.color colors == -1 then
- Js.Array.concat [| marker.color |] colors
- else
- colors)
- [| |]
-
-(* CSV Serialization *)
-
-let lat_key = "lat"
-let lng_key = "lng"
-let name_key = "name"
-let color_key = "color"
-let icon_key = "icon"
-
-let to_csv_string state =
- let to_csv_line marker =
- [| Js.Float.toString marker.pos.lat
- ; Js.Float.toString marker.pos.lng
- ; marker.name
- ; marker.color
- ; marker.icon
- |]
- in let
- header =
- [| lat_key; lng_key; name_key; color_key; icon_key |]
- in
- state
- |> Js.Array.map to_csv_line
- |> Fun.flip Js.Array.concat [| header |]
- |> CSV.to_string
-
-let from_dicts dicts =
- Js.Array.map
- (fun dict ->
- (* let get key default = Js.Dict.get dict key |> Option.withDefault default in *)
- { pos =
- { lat =
- Js.Dict.get dict lat_key
- |> Option.map Js.Float.fromString
- |> Option.withDefault 0.0
- ; lng =
- Js.Dict.get dict lng_key
- |> Option.map Js.Float.fromString
- |> Option.withDefault 0.0
- }
- ; name = Js.Dict.get dict name_key |> Option.withDefault ""
- ; color = Js.Dict.get dict color_key |> Option.withDefault default_color
- ; icon = Js.Dict.get dict icon_key |> Option.withDefault ""
- })
- dicts
diff --git a/src/View/Button.ml b/src/View/Button.ml
deleted file mode 100644
index b4641d2..0000000
--- a/src/View/Button.ml
+++ /dev/null
@@ -1,19 +0,0 @@
-let raw attrs content =
- H.button
- (HA.concat [| HA.class_ "g-Button__Raw" |] attrs)
- content
-
-let text attrs content =
- H.button
- (HA.concat [| HA.class_ "g-Button__Text" |] attrs)
- content
-
-let action attrs content =
- H.button
- (HA.concat [| HA.class_ "g-Button__Action" |] attrs)
- content
-
-let cancel attrs content =
- H.button
- (HA.concat [| HA.class_ "g-Button__Cancel" |] attrs)
- content
diff --git a/src/View/Form.ml b/src/View/Form.ml
deleted file mode 100644
index cec49d6..0000000
--- a/src/View/Form.ml
+++ /dev/null
@@ -1,65 +0,0 @@
-let input id label attrs =
- H.div
- [| HA.class_ "g-Form__Field" |]
- [| H.div
- [| HA.class_ "g-Form__Label" |]
- [| H.label
- [| HA.for_ id |]
- [| H.text label |]
- |]
- ; H.input
- (HA.concat attrs [| HA.id id |])
- [| |]
- |]
-
-let color_input default_colors id label init_value on_input =
- let
- input =
- H.input
- [| HA.id id
- ; HE.on_input (fun e -> on_input (Element.value (Event.target e)))
- ; HA.value init_value
- ; HA.type_ "color"
- |]
- [| |]
- in
- H.div
- [| HA.class_ "g-Form__Field" |]
- [| H.div
- [| HA.class_ "g-Form__Label" |]
- [| H.label
- [| HA.for_ id |]
- [| H.text label |]
- |]
- ; Layout.line
- [| |]
- (default_colors
- |> Js.Array.map (fun color ->
- Button.raw
- [| HA.class_ "g-Form__DefaultColor"
- ; HA.style ("background-color: " ^ color)
- ; HE.on_click (fun _ ->
- let () = Element.set_value input color in
- on_input color)
- ; HA.type_ "button"
- |]
- [| |])
- |> Fun.flip Js.Array.concat [| input |])
- |]
-
-let textarea id label init_value on_input =
- H.div
- [| HA.class_ "g-Form__Field" |]
- [| H.div
- [| HA.class_ "g-Form__Label" |]
- [| H.label
- [| HA.for_ id |]
- [| H.text label |]
- |]
- ; H.textarea
- [| HA.id id
- ; HA.class_ "g-Form__Textarea"
- ; HE.on_input (fun e -> on_input (Element.value (Event.target e)))
- |]
- [| H.text init_value |]
- |]
diff --git a/src/View/Form/Autocomplete.ml b/src/View/Form/Autocomplete.ml
deleted file mode 100644
index 98e4b43..0000000
--- a/src/View/Form/Autocomplete.ml
+++ /dev/null
@@ -1,80 +0,0 @@
-let search s xs =
- Js.Array.filter (Js.String.includes s) xs
-
-let render_completion render_entry on_select entries =
- H.div
- [| HA.class_ "g-Autocomplete__Completion" |]
- (entries
- |> Js.Array.map (fun c ->
- Button.raw
- [| HA.class_ "g-Autocomplete__Entry"
- ; HA.type_ "button"
- ; HE.on_click (fun e ->
- let () = Event.stop_propagation e in
- let () = Event.prevent_default e in
- on_select c)
- |]
- (render_entry c)))
-
-let create attrs id values render_entry on_input =
-
- let completion =
- H.div [| |] [| |]
- in
-
- let update_completion target value =
- let entries = search value values in
- Element.mount_on completion (render_completion
- render_entry
- (fun selected ->
- let () = Element.set_value target selected in
- let () = Element.remove_children completion in
- on_input selected)
- entries)
- in
-
- let hide_completion () =
- Element.mount_on completion (H.text "")
- in
-
- let
- input =
- H.input
- (HA.concat
- attrs
- [| HA.id id
- ; HA.class_ "g-Autocomplete__Input"
- ; HA.autocomplete "off"
- ; HE.on_focus (fun e ->
- let target = Event.target e in
- let value = Element.value target in
- update_completion target value)
- ; HE.on_input (fun e ->
- let target = Event.target e in
- let value = Element.value target in
- let () = update_completion target value in
- on_input value)
- |])
- [| |]
- in
-
- let () =
- Element.add_event_listener input "blur" (fun e ->
- if Js.isNullable (Event.related_target e) then
- hide_completion ())
- in
-
- H.div
- [| HA.class_ "g-Autocomplete" |]
- [| input
- ; completion
- ; Button.raw
- [| HA.class_ "g-Autocomplete__Clear fa fa-close"
- ; HA.type_ "button"
- ; HE.on_click (fun _ ->
- let () = on_input "" in
- let () = Element.set_value input "" in
- Element.focus input)
- |]
- [| |]
- |]
diff --git a/src/View/Layout.ml b/src/View/Layout.ml
deleted file mode 100644
index db1e234..0000000
--- a/src/View/Layout.ml
+++ /dev/null
@@ -1,9 +0,0 @@
-let section attrs content =
- H.div
- (HA.concat attrs [| HA.class_ "g-Layout__Section" |])
- content
-
-let line attrs content =
- H.div
- (HA.concat attrs [| HA.class_ "g-Layout__Line" |])
- content
diff --git a/src/View/Map.ml b/src/View/Map.ml
deleted file mode 100644
index 6e2611e..0000000
--- a/src/View/Map.ml
+++ /dev/null
@@ -1,131 +0,0 @@
-let state_from_hash () =
- let hash = Js.String.sliceToEnd ~from:1 (Location.hash Document.location) in
- State.from_url_string hash
-
-let rec reload_from_hash state map markers focus =
- let update_state new_state =
- let () = History.push_state "" "" ("#" ^ State.to_url_string new_state) () in
- reload_from_hash state map markers false
- in
-
- let on_remove pos =
- update_state (State.remove !state pos) in
-
- let on_update previousPos pos name color icon =
- update_state (State.update !state previousPos { pos = pos; name = name; color = color; icon = icon }) in
-
- let () =
- if Js.Array.length (Leaflet.get_layers markers ()) > 0 then
- Leaflet.clear_layers markers
- else
- ()
- in
- let () = state := state_from_hash () in
- let colors = State.colors !state in
- let () =
- Js.Array.forEach
- (fun (m: State.marker_state) -> Leaflet.add_layer markers (Marker.create on_remove on_update colors m.pos m.name m.color m.icon))
- !state
- in
- if focus then
- if Js.Array.length (Leaflet.get_layers markers ()) > 0 then
- Leaflet.fit_bounds map (Leaflet.get_bounds markers ()) { padding = [| 50.; 50. |] }
- else
- Leaflet.setView map [| 51.505; -0.09 |] 2
- else
- ()
-
-let mapView state map markers =
- H.div
- [| HA.class_ "g-Layout__Page" |]
- [| H.div
- [| HA.class_ "g-Layout__Header" |]
- [| H.a
- [| HA.class_ "g-Layout__Home"
- ; HA.href "#"
- |]
- [| H.text "Map" |]
- ; Layout.line
- [| HA.class_ "g-Layout__HeaderImportExport" |]
- [| H.input
- [| HA.id "g-Header__ImportInput"
- ; HA.type_ "file"
- ; HE.on_change (fun e ->
- match !map with
- | Some map ->
- let reader = File.reader () in
- let () = Element.add_event_listener reader "load" (fun _ ->
- let str = File.result reader in
- let new_state = State.from_dicts (CSV.to_dicts (CSV.parse str)) in
- let () = History.push_state "" "" ("#" ^ State.to_url_string new_state) () in
- reload_from_hash state map markers true)
- in
- File.read_as_text reader (
- Js.Array.unsafe_get (Element.files (Event.target e)) 0)
- | _ ->
- ())
- |]
- [| |]
- ; H.label
- [| HA.for_ "g-Header__ImportInput"
- ; HA.class_ "g-Button__Text"
- |]
- [| H.text "Import" |]
- ; Button.text
- [| HE.on_click (fun _ -> File.download "map.csv" (State.to_csv_string !state)) |]
- [| H.text "Export" |]
- |]
- |]
- ; H.div
- [| HA.class_ "g-Map" |]
- [| H.div
- [| HA.id "g-Map__Content" |]
- [||]
- |]
- |]
-
-let install_map state map_ref markers =
- let map = Leaflet.map "g-Map__Content" { attributionControl = false } in
- let () = map_ref := Some map in
- let title_layer = Leaflet.title_layer "http://{s}.tile.osm.org/{z}/{x}/{y}.png" in
- let () = Leaflet.add_layer map markers in
- let () = Leaflet.add_layer map title_layer in
-
- (* Init markers from url *)
- let () = reload_from_hash state map markers true in
-
- (* Reload the map if the URL changes *)
- let () = Element.add_event_listener Window.window "popstate" (fun _ ->
- reload_from_hash state map markers true)
- in
-
- let add_marker pos name color icon =
- let new_marker = { State.pos = pos; name = name; color = color; icon = icon } in
- let new_state = State.update !state pos new_marker in
- let () = History.push_state "" "" ("#" ^ State.to_url_string new_state) () in
- reload_from_hash state map markers false
- in
-
- (* Context menu *)
- Leaflet.on map "contextmenu" (fun event ->
- ContextMenu.show
- (Leaflet.original_event event)
- [| { label = "Add a marker"
- ; action = (fun _ ->
- let pos = Leaflet.lat_lng event in
- let marker =
- match State.last_added !state with
- | Some m -> { m with pos = pos; name = "" }
- | _ -> { pos = pos; name = ""; color = "#3f92cf"; icon = "" }
- in
- let colors = State.colors !state in
- Modal.show (Marker.form (add_marker pos) colors marker.name marker.color marker.icon))
- }
- |])
-
-let render () =
- let state = ref (state_from_hash ()) in
- let map = ref None in
- let markers = Leaflet.feature_group [| |] in
- let _ = Js.Global.setTimeout (fun _ -> install_map state map markers) 0 in
- mapView state map markers
diff --git a/src/View/Map/Icon.ml b/src/View/Map/Icon.ml
deleted file mode 100644
index 8737f43..0000000
--- a/src/View/Map/Icon.ml
+++ /dev/null
@@ -1,32 +0,0 @@
-let create name color =
- let c = Color.from_raw color in
- let crBlack = Color.contrast_ratio { r = 0.; g = 0.; b = 0. } c in
- let crWhite = Color.contrast_ratio { r = 255.; g = 255.; b = 255. } c in
- let textCol = if crBlack > crWhite then "black" else "white" in
- Leaflet.div_icon
- { className = ""
- ; popupAnchor = [| 0.; -34. |]
- ; html =
- H.div
- [| HA.class_ "g-Marker" |]
- [| H.div
- [| HA.class_ "g-Marker__Round"
- ; HA.style ("background-color: " ^ color)
- |]
- [| |]
- ; H.div [| HA.class_ "g-Marker__PeakBorder" |] [| |]
- ; H.div
- [| HA.class_ "g-Marker__PeakInner"
- ; HA.style ("border-top-color: " ^ color)
- |]
- [| |]
- ; H.div
- [| HA.class_ "g-Marker__Icon" |]
- [| H.i
- [| HA.class_ ("fa fa-" ^ name)
- ; HA.style ("color: " ^ textCol)
- |]
- [| |]
- |]
- |]
- }
diff --git a/src/View/Map/Marker.ml b/src/View/Map/Marker.ml
deleted file mode 100644
index 1c0c0d6..0000000
--- a/src/View/Map/Marker.ml
+++ /dev/null
@@ -1,105 +0,0 @@
-let form on_validate colors init_name init_color init_icon =
- let name = ref init_name in
- let color = ref init_color in
- let icon = ref init_icon in
- let on_validate () =
- let () = on_validate !name !color !icon in
- Modal.hide ()
- in
- H.div
- [| |]
- [| Layout.section
- [| |]
- [| H.form
- [| HA.class_ "g-MarkerForm"
- ; HE.on_submit (fun e ->
- let () = Event.prevent_default e in
- on_validate ())
- |]
- [| Layout.section
- [| |]
- [| Form.input
- "g-MarkerForm__Name"
- "Name"
- [| HE.on_input (fun e -> name := (Element.value (Event.target e)))
- ; HA.value init_name
- |]
- ; Form.color_input colors "g-MarkerForm__Color" "Color" init_color (fun newColor -> color := newColor)
- ; H.div
- [| HA.class_ "g-Form__Field" |]
- [| H.div
- [| HA.class_ "g-Form__Label" |]
- [| H.label
- [| HA.for_ "g-MarkerForm__IconInput" |]
- [| H.text "Icon" |]
- |]
- ; let dom_icon = H.div [| HA.class_ ("fa fa-" ^ !icon) |] [| |] in
- Layout.line
- [| HA.class_ "g-MarkerForm__AutocompleteAndIcon" |]
- [| Autocomplete.create
- [| HA.value init_icon
- ; HA.class_ "g-MarkerForm__Autocomplete"
- |]
- "g-MarkerForm__IconInput"
- FontAwesome.icons
- (fun icon ->
- [| H.div
- [| HA.class_ ("g-MarkerForm__IconEntry fa fa-" ^ icon) |]
- [| |]
- ; H.text icon
- |])
- (fun newIcon ->
- let () = icon := newIcon in
- Element.set_class_name dom_icon ("fa fa-" ^ newIcon))
- ; H.div [| HA.class_ "g-MarkerForm__Icon" |] [| dom_icon |]
- |]
- |]
- |]
- ; Layout.line
- [| |]
- [| Button.action
- [| HE.on_click (fun _ -> on_validate ()) |]
- [| H.text "Save" |]
- ; Button.cancel
- [| HE.on_click (fun _ -> Modal.hide ())
- ; HA.type_ "button"
- |]
- [| H.text "Cancel" |]
- |]
- |]
- |]
- |]
-
-
-let create on_remove on_update colors pos init_name init_color init_icon =
- let marker =
- Leaflet.marker pos
- { title = init_name
- ; icon = Icon.create init_icon init_color
- ; draggable = true
- }
- in
-
- (* Context menu *)
- let () = Leaflet.on marker "contextmenu" (fun event ->
- ContextMenu.show
- (Leaflet.original_event event)
- [| { label = "Modify"
- ; action = fun _ ->
- Modal.show (form (on_update pos pos) colors init_name init_color init_icon)
- }
- ; { label = "Remove"
- ; action = fun _ -> on_remove pos
- }
- |])
- in
-
- (* Move the cursor on drag *)
- let () = Leaflet.on marker "dragend" (fun e ->
- let newPos = Leaflet.get_lat_lng (Leaflet.target e) () in
- on_update pos newPos init_name init_color init_icon) in
-
- let () = Leaflet.on marker "dblclick" (fun _ ->
- Modal.show (form (on_update pos pos) colors init_name init_color init_icon)) in
-
- marker
diff --git a/src/lib/autoComplete.ts b/src/lib/autoComplete.ts
new file mode 100644
index 0000000..769f617
--- /dev/null
+++ b/src/lib/autoComplete.ts
@@ -0,0 +1,114 @@
+import { h, Children, concatClassName } from 'lib/h'
+import * as Button from 'lib/button'
+
+export function create(
+ attrs: object,
+ id: string,
+ values: string[],
+ renderEntry: (entry: string) => Element,
+ onInput: (value: string) => void
+): Element {
+ const completion = h('div', {})
+
+ const updateCompletion = (target: EventTarget, value: string) => {
+ const entries = search(value, values)
+ mountOn(
+ completion,
+ renderCompletion(
+ renderEntry,
+ selected => {
+ (target as HTMLInputElement).value = selected
+ completion.remove
+ removeChildren(completion)
+ onInput(selected)
+ },
+ entries
+ )
+ )
+ }
+
+ const input = h('input',
+ concatClassName(
+ { ...attrs,
+ id,
+ autocomplete: 'off',
+ onfocus: (e: Event) => {
+ if (e.target !== null) {
+ const target = e.target as HTMLInputElement
+ updateCompletion(target, target.value)
+ }
+ },
+ oninput: (e: Event) => {
+ if (e.target !== null) {
+ const target = e.target as HTMLInputElement
+ updateCompletion(target, target.value)
+ onInput(target.value)
+ }
+ }
+ },
+ 'g-AutoComplete__Input'
+ )
+ ) as HTMLInputElement
+
+ input.addEventListener('blur', (e: MouseEvent) => {
+ if (e.relatedTarget === null) {
+ removeChildren(completion)
+ }
+ })
+
+ return h('div',
+ { className: 'g-AutoComplete' },
+ input,
+ completion,
+ Button.raw(
+ { className: 'g-AutoComplete__Clear fa fa-close',
+ type: 'button',
+ onclick: () => {
+ onInput('')
+ input.value = ''
+ input.focus()
+ }
+ }
+ )
+ )
+}
+
+function renderCompletion(
+ renderEntry: (entry: string) => Element,
+ onSelect: (entry: string) => void,
+ entries: string[]
+): Element {
+ return h('div',
+ { className: 'g-AutoComplete__Completion' },
+ ...entries.map(c =>
+ Button.raw(
+ { className: 'g-AutoComplete__Entry',
+ type: 'button',
+ onclick: (e: Event) => {
+ e.stopPropagation()
+ e.preventDefault()
+ onSelect(c)
+ }
+ },
+ renderEntry(c)
+ )
+ )
+ )
+}
+
+function search(s: string, xs: string[]): string[] {
+ return xs.filter(x => x.includes(s))
+}
+
+function mountOn(base: Element, ...children: Element[]) {
+ removeChildren(base)
+ children.forEach(child => base.appendChild(child))
+}
+
+function removeChildren(base: Element) {
+ const firstChild = base.firstChild
+ if (firstChild !== null) {
+ base.removeChild(firstChild)
+ removeChildren(base)
+ }
+}
diff --git a/src/lib/button.ts b/src/lib/button.ts
new file mode 100644
index 0000000..794df35
--- /dev/null
+++ b/src/lib/button.ts
@@ -0,0 +1,29 @@
+import { h, Children, concatClassName } from 'lib/h'
+
+export function raw(attrs: object, ...children: Children): Element {
+ return h('button',
+ concatClassName(attrs, 'g-Button__Raw'),
+ ...children
+ )
+}
+
+export function text(attrs: object, ...children: Children): Element {
+ return h('button',
+ concatClassName(attrs, 'g-Button__Text'),
+ ...children
+ )
+}
+
+export function action(attrs: object, ...children: Children): Element {
+ return h('button',
+ concatClassName(attrs, 'g-Button__Action'),
+ ...children
+ )
+}
+
+export function cancel(attrs: object, ...children: Children): Element {
+ return h('button',
+ concatClassName(attrs, 'g-Button__Cancel'),
+ ...children
+ )
+}
diff --git a/src/lib/contextMenu.ts b/src/lib/contextMenu.ts
new file mode 100644
index 0000000..6edd567
--- /dev/null
+++ b/src/lib/contextMenu.ts
@@ -0,0 +1,35 @@
+import { h } from 'lib/h'
+
+interface Action {
+ label: string,
+ action: () => void
+}
+
+export function show(event: MouseEvent, actions: Action[]) {
+ const menu = h('div',
+ { id: 'g-ContextMenu',
+ style: `left: ${event.pageX.toString()}px; top: ${event.pageY.toString()}px`
+ },
+ ...actions.map(({ label, action }) =>
+ h('div',
+ { className: 'g-ContextMenu__Entry',
+ onclick: () => action()
+ },
+ label
+ )
+ )
+ )
+
+ document.body.appendChild(menu)
+
+ // Remove on click or context menu
+ setTimeout(() => {
+ const f = () => {
+ document.body.removeChild(menu)
+ document.body.removeEventListener('click', f)
+ document.body.removeEventListener('contextmenu', f)
+ }
+ document.body.addEventListener('click', f)
+ document.body.addEventListener('contextmenu', f)
+ }, 0)
+}
diff --git a/src/lib/fontAwesome.ts b/src/lib/fontAwesome.ts
new file mode 100644
index 0000000..896fa52
--- /dev/null
+++ b/src/lib/fontAwesome.ts
@@ -0,0 +1,788 @@
+export const icons: string [] = [
+ "500px",
+ "address-book",
+ "address-book-o",
+ "address-card",
+ "address-card-o",
+ "adjust",
+ "adn",
+ "align-center",
+ "align-justify",
+ "align-left",
+ "align-right",
+ "amazon",
+ "ambulance",
+ "american-sign-language-interpreting",
+ "anchor",
+ "android",
+ "angellist",
+ "angle-double-down",
+ "angle-double-left",
+ "angle-double-right",
+ "angle-double-up",
+ "angle-down",
+ "angle-left",
+ "angle-right",
+ "angle-up",
+ "apple",
+ "archive",
+ "area-chart",
+ "arrow-circle-down",
+ "arrow-circle-left",
+ "arrow-circle-o-down",
+ "arrow-circle-o-left",
+ "arrow-circle-o-right",
+ "arrow-circle-o-up",
+ "arrow-circle-right",
+ "arrow-circle-up",
+ "arrow-down",
+ "arrow-left",
+ "arrow-right",
+ "arrow-up",
+ "arrows",
+ "arrows-alt",
+ "arrows-h",
+ "arrows-v",
+ "asl-interpreting",
+ "assistive-listening-systems",
+ "asterisk",
+ "at",
+ "audio-description",
+ "automobile",
+ "backward",
+ "balance-scale",
+ "ban",
+ "bandcamp",
+ "bank",
+ "bar-chart",
+ "bar-chart-o",
+ "barcode",
+ "bars",
+ "bath",
+ "bathtub",
+ "battery",
+ "battery-0",
+ "battery-1",
+ "battery-2",
+ "battery-3",
+ "battery-4",
+ "battery-empty",
+ "battery-full",
+ "battery-half",
+ "battery-quarter",
+ "battery-three-quarters",
+ "bed",
+ "beer",
+ "behance",
+ "behance-square",
+ "bell",
+ "bell-o",
+ "bell-slash",
+ "bell-slash-o",
+ "bicycle",
+ "binoculars",
+ "birthday-cake",
+ "bitbucket",
+ "bitbucket-square",
+ "bitcoin",
+ "black-tie",
+ "blind",
+ "bluetooth",
+ "bluetooth-b",
+ "bold",
+ "bolt",
+ "bomb",
+ "book",
+ "bookmark",
+ "bookmark-o",
+ "braille",
+ "briefcase",
+ "btc",
+ "bug",
+ "building",
+ "building-o",
+ "bullhorn",
+ "bullseye",
+ "bus",
+ "buysellads",
+ "cab",
+ "calculator",
+ "calendar",
+ "calendar-check-o",
+ "calendar-minus-o",
+ "calendar-o",
+ "calendar-plus-o",
+ "calendar-times-o",
+ "camera",
+ "camera-retro",
+ "car",
+ "caret-down",
+ "caret-left",
+ "caret-right",
+ "caret-square-o-down",
+ "caret-square-o-left",
+ "caret-square-o-right",
+ "caret-square-o-up",
+ "caret-up",
+ "cart-arrow-down",
+ "cart-plus",
+ "cc",
+ "cc-amex",
+ "cc-diners-club",
+ "cc-discover",
+ "cc-jcb",
+ "cc-mastercard",
+ "cc-paypal",
+ "cc-stripe",
+ "cc-visa",
+ "certificate",
+ "chain",
+ "chain-broken",
+ "check",
+ "check-circle",
+ "check-circle-o",
+ "check-square",
+ "check-square-o",
+ "chevron-circle-down",
+ "chevron-circle-left",
+ "chevron-circle-right",
+ "chevron-circle-up",
+ "chevron-down",
+ "chevron-left",
+ "chevron-right",
+ "chevron-up",
+ "child",
+ "chrome",
+ "circle",
+ "circle-o",
+ "circle-o-notch",
+ "circle-thin",
+ "clipboard",
+ "clock-o",
+ "clone",
+ "close",
+ "cloud",
+ "cloud-download",
+ "cloud-upload",
+ "cny",
+ "code",
+ "code-fork",
+ "codepen",
+ "codiepie",
+ "coffee",
+ "cog",
+ "cogs",
+ "columns",
+ "comment",
+ "comment-o",
+ "commenting",
+ "commenting-o",
+ "comments",
+ "comments-o",
+ "compass",
+ "compress",
+ "connectdevelop",
+ "contao",
+ "copy",
+ "copyright",
+ "creative-commons",
+ "credit-card",
+ "credit-card-alt",
+ "crop",
+ "crosshairs",
+ "css3",
+ "cube",
+ "cubes",
+ "cut",
+ "cutlery",
+ "dashboard",
+ "dashcube",
+ "database",
+ "deaf",
+ "deafness",
+ "dedent",
+ "delicious",
+ "desktop",
+ "deviantart",
+ "diamond",
+ "digg",
+ "dollar",
+ "dot-circle-o",
+ "download",
+ "dribbble",
+ "drivers-license",
+ "drivers-license-o",
+ "dropbox",
+ "drupal",
+ "edge",
+ "edit",
+ "eercast",
+ "eject",
+ "ellipsis-h",
+ "ellipsis-v",
+ "empire",
+ "envelope",
+ "envelope-o",
+ "envelope-open",
+ "envelope-open-o",
+ "envelope-square",
+ "envira",
+ "eraser",
+ "etsy",
+ "eur",
+ "euro",
+ "exchange",
+ "exclamation",
+ "exclamation-circle",
+ "exclamation-triangle",
+ "expand",
+ "expeditedssl",
+ "external-link",
+ "external-link-square",
+ "eye",
+ "eye-slash",
+ "eyedropper",
+ "fa",
+ "facebook",
+ "facebook-f",
+ "facebook-official",
+ "facebook-square",
+ "fast-backward",
+ "fast-forward",
+ "fax",
+ "feed",
+ "female",
+ "fighter-jet",
+ "file",
+ "file-archive-o",
+ "file-audio-o",
+ "file-code-o",
+ "file-excel-o",
+ "file-image-o",
+ "file-movie-o",
+ "file-o",
+ "file-pdf-o",
+ "file-photo-o",
+ "file-picture-o",
+ "file-powerpoint-o",
+ "file-sound-o",
+ "file-text",
+ "file-text-o",
+ "file-video-o",
+ "file-word-o",
+ "file-zip-o",
+ "files-o",
+ "film",
+ "filter",
+ "fire",
+ "fire-extinguisher",
+ "firefox",
+ "first-order",
+ "flag",
+ "flag-checkered",
+ "flag-o",
+ "flash",
+ "flask",
+ "flickr",
+ "floppy-o",
+ "folder",
+ "folder-o",
+ "folder-open",
+ "folder-open-o",
+ "font",
+ "font-awesome",
+ "fonticons",
+ "fort-awesome",
+ "forumbee",
+ "forward",
+ "foursquare",
+ "free-code-camp",
+ "frown-o",
+ "futbol-o",
+ "gamepad",
+ "gavel",
+ "gbp",
+ "ge",
+ "gear",
+ "gears",
+ "genderless",
+ "get-pocket",
+ "gg",
+ "gg-circle",
+ "gift",
+ "git",
+ "git-square",
+ "github",
+ "github-alt",
+ "github-square",
+ "gitlab",
+ "gittip",
+ "glass",
+ "glide",
+ "glide-g",
+ "globe",
+ "google",
+ "google-plus",
+ "google-plus-circle",
+ "google-plus-official",
+ "google-plus-square",
+ "google-wallet",
+ "graduation-cap",
+ "gratipay",
+ "grav",
+ "group",
+ "h-square",
+ "hacker-news",
+ "hand-grab-o",
+ "hand-lizard-o",
+ "hand-o-down",
+ "hand-o-left",
+ "hand-o-right",
+ "hand-o-up",
+ "hand-paper-o",
+ "hand-peace-o",
+ "hand-pointer-o",
+ "hand-rock-o",
+ "hand-scissors-o",
+ "hand-spock-o",
+ "hand-stop-o",
+ "handshake-o",
+ "hard-of-hearing",
+ "hashtag",
+ "hdd-o",
+ "header",
+ "headphones",
+ "heart",
+ "heart-o",
+ "heartbeat",
+ "history",
+ "home",
+ "hospital-o",
+ "hotel",
+ "hourglass",
+ "hourglass-1",
+ "hourglass-2",
+ "hourglass-3",
+ "hourglass-end",
+ "hourglass-half",
+ "hourglass-o",
+ "hourglass-start",
+ "houzz",
+ "html5",
+ "i-cursor",
+ "id-badge",
+ "id-card",
+ "id-card-o",
+ "ils",
+ "image",
+ "imdb",
+ "inbox",
+ "indent",
+ "industry",
+ "info",
+ "info-circle",
+ "inr",
+ "instagram",
+ "institution",
+ "internet-explorer",
+ "intersex",
+ "ioxhost",
+ "italic",
+ "joomla",
+ "jpy",
+ "jsfiddle",
+ "key",
+ "keyboard-o",
+ "krw",
+ "language",
+ "laptop",
+ "lastfm",
+ "lastfm-square",
+ "leaf",
+ "leanpub",
+ "legal",
+ "lemon-o",
+ "level-down",
+ "level-up",
+ "life-bouy",
+ "life-buoy",
+ "life-ring",
+ "life-saver",
+ "lightbulb-o",
+ "line-chart",
+ "link",
+ "linkedin",
+ "linkedin-square",
+ "linode",
+ "linux",
+ "list",
+ "list-alt",
+ "list-ol",
+ "list-ul",
+ "location-arrow",
+ "lock",
+ "long-arrow-down",
+ "long-arrow-left",
+ "long-arrow-right",
+ "long-arrow-up",
+ "low-vision",
+ "magic",
+ "magnet",
+ "mail-forward",
+ "mail-reply",
+ "mail-reply-all",
+ "male",
+ "map",
+ "map-marker",
+ "map-o",
+ "map-pin",
+ "map-signs",
+ "mars",
+ "mars-double",
+ "mars-stroke",
+ "mars-stroke-h",
+ "mars-stroke-v",
+ "maxcdn",
+ "meanpath",
+ "medium",
+ "medkit",
+ "meetup",
+ "meh-o",
+ "mercury",
+ "microchip",
+ "microphone",
+ "microphone-slash",
+ "minus",
+ "minus-circle",
+ "minus-square",
+ "minus-square-o",
+ "mixcloud",
+ "mobile",
+ "mobile-phone",
+ "modx",
+ "money",
+ "moon-o",
+ "mortar-board",
+ "motorcycle",
+ "mouse-pointer",
+ "music",
+ "navicon",
+ "neuter",
+ "newspaper-o",
+ "object-group",
+ "object-ungroup",
+ "odnoklassniki",
+ "odnoklassniki-square",
+ "opencart",
+ "openid",
+ "opera",
+ "optin-monster",
+ "outdent",
+ "pagelines",
+ "paint-brush",
+ "paper-plane",
+ "paper-plane-o",
+ "paperclip",
+ "paragraph",
+ "paste",
+ "pause",
+ "pause-circle",
+ "pause-circle-o",
+ "paw",
+ "paypal",
+ "pencil",
+ "pencil-square",
+ "pencil-square-o",
+ "percent",
+ "phone",
+ "phone-square",
+ "photo",
+ "picture-o",
+ "pie-chart",
+ "pied-piper",
+ "pied-piper-alt",
+ "pied-piper-pp",
+ "pinterest",
+ "pinterest-p",
+ "pinterest-square",
+ "plane",
+ "play",
+ "play-circle",
+ "play-circle-o",
+ "plug",
+ "plus",
+ "plus-circle",
+ "plus-square",
+ "plus-square-o",
+ "podcast",
+ "power-off",
+ "print",
+ "product-hunt",
+ "puzzle-piece",
+ "qq",
+ "qrcode",
+ "question",
+ "question-circle",
+ "question-circle-o",
+ "quora",
+ "quote-left",
+ "quote-right",
+ "ra",
+ "random",
+ "ravelry",
+ "rebel",
+ "recycle",
+ "reddit",
+ "reddit-alien",
+ "reddit-square",
+ "refresh",
+ "registered",
+ "remove",
+ "renren",
+ "reorder",
+ "repeat",
+ "reply",
+ "reply-all",
+ "resistance",
+ "retweet",
+ "rmb",
+ "road",
+ "rocket",
+ "rotate-left",
+ "rotate-right",
+ "rouble",
+ "rss",
+ "rss-square",
+ "rub",
+ "ruble",
+ "rupee",
+ "s15",
+ "safari",
+ "save",
+ "scissors",
+ "scribd",
+ "search",
+ "search-minus",
+ "search-plus",
+ "sellsy",
+ "send",
+ "send-o",
+ "server",
+ "share",
+ "share-alt",
+ "share-alt-square",
+ "share-square",
+ "share-square-o",
+ "shekel",
+ "sheqel",
+ "shield",
+ "ship",
+ "shirtsinbulk",
+ "shopping-bag",
+ "shopping-basket",
+ "shopping-cart",
+ "shower",
+ "sign-in",
+ "sign-language",
+ "sign-out",
+ "signal",
+ "signing",
+ "simplybuilt",
+ "sitemap",
+ "skyatlas",
+ "skype",
+ "slack",
+ "sliders",
+ "slideshare",
+ "smile-o",
+ "snapchat",
+ "snapchat-ghost",
+ "snapchat-square",
+ "snowflake-o",
+ "soccer-ball-o",
+ "sort",
+ "sort-alpha-asc",
+ "sort-alpha-desc",
+ "sort-amount-asc",
+ "sort-amount-desc",
+ "sort-asc",
+ "sort-desc",
+ "sort-down",
+ "sort-numeric-asc",
+ "sort-numeric-desc",
+ "sort-up",
+ "soundcloud",
+ "space-shuttle",
+ "spinner",
+ "spoon",
+ "spotify",
+ "square",
+ "square-o",
+ "stack-exchange",
+ "stack-overflow",
+ "star",
+ "star-half",
+ "star-half-empty",
+ "star-half-full",
+ "star-half-o",
+ "star-o",
+ "steam",
+ "steam-square",
+ "step-backward",
+ "step-forward",
+ "stethoscope",
+ "sticky-note",
+ "sticky-note-o",
+ "stop",
+ "stop-circle",
+ "stop-circle-o",
+ "street-view",
+ "strikethrough",
+ "stumbleupon",
+ "stumbleupon-circle",
+ "subscript",
+ "subway",
+ "suitcase",
+ "sun-o",
+ "superpowers",
+ "superscript",
+ "support",
+ "table",
+ "tablet",
+ "tachometer",
+ "tag",
+ "tags",
+ "tasks",
+ "taxi",
+ "telegram",
+ "television",
+ "tencent-weibo",
+ "terminal",
+ "text-height",
+ "text-width",
+ "th",
+ "th-large",
+ "th-list",
+ "themeisle",
+ "thermometer",
+ "thermometer-0",
+ "thermometer-1",
+ "thermometer-2",
+ "thermometer-3",
+ "thermometer-4",
+ "thermometer-empty",
+ "thermometer-full",
+ "thermometer-half",
+ "thermometer-quarter",
+ "thermometer-three-quarters",
+ "thumb-tack",
+ "thumbs-down",
+ "thumbs-o-down",
+ "thumbs-o-up",
+ "thumbs-up",
+ "ticket",
+ "times",
+ "times-circle",
+ "times-circle-o",
+ "times-rectangle",
+ "times-rectangle-o",
+ "tint",
+ "toggle-down",
+ "toggle-left",
+ "toggle-off",
+ "toggle-on",
+ "toggle-right",
+ "toggle-up",
+ "trademark",
+ "train",
+ "transgender",
+ "transgender-alt",
+ "trash",
+ "trash-o",
+ "tree",
+ "trello",
+ "tripadvisor",
+ "trophy",
+ "truck",
+ "try",
+ "tty",
+ "tumblr",
+ "tumblr-square",
+ "turkish-lira",
+ "tv",
+ "twitch",
+ "twitter",
+ "twitter-square",
+ "umbrella",
+ "underline",
+ "undo",
+ "universal-access",
+ "university",
+ "unlink",
+ "unlock",
+ "unlock-alt",
+ "unsorted",
+ "upload",
+ "usb",
+ "usd",
+ "user",
+ "user-circle",
+ "user-circle-o",
+ "user-md",
+ "user-o",
+ "user-plus",
+ "user-secret",
+ "user-times",
+ "users",
+ "vcard",
+ "vcard-o",
+ "venus",
+ "venus-double",
+ "venus-mars",
+ "viacoin",
+ "viadeo",
+ "viadeo-square",
+ "video-camera",
+ "vimeo",
+ "vimeo-square",
+ "vine",
+ "vk",
+ "volume-control-phone",
+ "volume-down",
+ "volume-off",
+ "volume-up",
+ "warning",
+ "wechat",
+ "weibo",
+ "weixin",
+ "whatsapp",
+ "wheelchair",
+ "wheelchair-alt",
+ "wifi",
+ "wikipedia-w",
+ "window-close",
+ "window-close-o",
+ "window-maximize",
+ "window-minimize",
+ "window-restore",
+ "windows",
+ "won",
+ "wordpress",
+ "wpbeginner",
+ "wpexplorer",
+ "wpforms",
+ "wrench",
+ "xing",
+ "xing-square",
+ "y-combinator",
+ "y-combinator-square",
+ "yahoo",
+ "yc",
+ "yc-square",
+ "yelp",
+ "yen",
+ "yoast",
+ "youtube",
+ "youtube-play",
+ "youtube-square"
+]
diff --git a/src/lib/form.ts b/src/lib/form.ts
new file mode 100644
index 0000000..a1f8cfd
--- /dev/null
+++ b/src/lib/form.ts
@@ -0,0 +1,80 @@
+import { h } from 'lib/h'
+import * as Layout from 'lib/layout'
+import * as Button from 'lib/button'
+
+export function input(id: string, label: string, attrs: object): Element {
+ return h('div',
+ { className: 'g-Form__Field' },
+ h('div',
+ { className: 'g-Form__Label' },
+ h('label', { for: id }, label)
+ ),
+ h('input', { id: id, ...attrs })
+ )
+}
+
+export function colorInput(
+ defaultColors: string[],
+ id: string,
+ label: string,
+ initValue: string,
+ onInput: (value: string) => void
+): Element {
+ const input = h('input',
+ { id,
+ value: initValue,
+ type: 'color',
+ oninput: (e: Event) => {
+ if (e.target !== null) {
+ onInput((e.target as HTMLInputElement).value)
+ }
+ }
+ }
+ ) as HTMLInputElement
+ return h('div',
+ { className: 'g-Form__Field' },
+ h('div',
+ { className: 'g-Form__Label' },
+ h('label', { for: id }, label)
+ ),
+ Layout.line(
+ {},
+ ...(defaultColors.map(color =>
+ Button.raw({ className: 'g-Form__DefaultColor',
+ style: `background-color: ${color}`,
+ type: 'button',
+ onclick: () => {
+ input.value = color
+ onInput(color)
+ }
+ })
+ ).concat(input))
+ )
+ )
+}
+
+export function textarea(
+ id: string,
+ label: string,
+ initValue: string,
+ onInput: (value: string) => void
+): Element {
+ return h('div',
+ { className: 'g-Form__Field' },
+ h('div',
+ { className: 'g-Form__Label' },
+ h('label', { for: id }, label)
+ ),
+ h('textarea',
+ { id,
+ className: 'g-Form__Textarea',
+ oninput: (e: Event) => {
+ if (e.target !== null) {
+ onInput((e.target as HTMLTextAreaElement).value)
+ }
+ }
+ },
+ initValue
+ )
+ )
+}
diff --git a/src/lib/h.ts b/src/lib/h.ts
new file mode 100644
index 0000000..1e49f2f
--- /dev/null
+++ b/src/lib/h.ts
@@ -0,0 +1,41 @@
+type Child = Element | Text | string | number
+
+export type Children = Child[]
+
+export function h(
+ tagName: string,
+ attrs: object,
+ ...children: Children
+): Element {
+ const isSvg = tagName === 'svg' || tagName === 'path'
+
+ let elem = isSvg
+ ? document.createElementNS('http://www.w3.org/2000/svg', tagName)
+ : document.createElement(tagName)
+
+ if (isSvg) {
+ Object.entries(attrs).forEach(([key, value]) => {
+ elem.setAttribute(key, value)
+ })
+ } else {
+ elem = Object.assign(elem, attrs)
+ }
+
+ for (const child of children) {
+ if (typeof child === 'number')
+ elem.append(child.toString())
+ else
+ elem.append(child)
+ // if (Array.isArray(child))
+ // elem.append(...child)
+ // else
+ // elem.append(child)
+ }
+
+ return elem
+}
+
+export function concatClassName(attrs: any, className: string): object {
+ const existingClassName = 'className' in attrs ? attrs['className'] : undefined
+ return { ...attrs, className: `${className} ${existingClassName}` }
+}
diff --git a/src/lib/layout.ts b/src/lib/layout.ts
new file mode 100644
index 0000000..1e38bfd
--- /dev/null
+++ b/src/lib/layout.ts
@@ -0,0 +1,15 @@
+import { h, Children, concatClassName } from 'lib/h'
+
+export function section(attrs: object, ...children: Children): Element {
+ return h('div',
+ concatClassName(attrs, 'g-Layout__Section'),
+ ...children
+ )
+}
+
+export function line(attrs: object, ...children: Children): Element {
+ return h('div',
+ concatClassName(attrs, 'g-Layout__Line'),
+ ...children
+ )
+}
diff --git a/src/lib/modal.ts b/src/lib/modal.ts
new file mode 100644
index 0000000..4f8c675
--- /dev/null
+++ b/src/lib/modal.ts
@@ -0,0 +1,28 @@
+import { h } from 'lib/h'
+import * as Button from 'lib/button'
+
+export function show(content: Element) {
+ document.body.appendChild(h('div',
+ { id: 'g-Modal' },
+ h('div',
+ { className: 'g-Modal__Curtain',
+ onclick: () => hide()
+ }
+ ),
+ h('div',
+ { className: 'g-Modal__Window' },
+ Button.raw(
+ { className: 'g-Modal__Close',
+ onclick: () => hide()
+ },
+ h('div', { className: 'fa fa-close' })
+ ),
+ content
+ )
+ ))
+}
+
+export function hide() {
+ const modal = document.querySelector('#g-Modal')
+ modal && document.body.removeChild(modal)
+}
diff --git a/src/main.ts b/src/main.ts
new file mode 100644
index 0000000..36b1143
--- /dev/null
+++ b/src/main.ts
@@ -0,0 +1,3 @@
+import * as Map from 'map'
+
+document.body.appendChild(Map.view())
diff --git a/src/map.ts b/src/map.ts
new file mode 100644
index 0000000..cc1df17
--- /dev/null
+++ b/src/map.ts
@@ -0,0 +1,126 @@
+import { h } from 'lib/h'
+import * as Button from 'lib/button'
+import * as ContextMenu from 'lib/contextMenu'
+import * as Layout from 'lib/layout'
+import * as Modal from 'lib/modal'
+import * as Marker from 'marker'
+const L = window.L
+
+let map
+
+export function view() {
+ // let state = ref (state_from_hash ()) in
+ // let map = ref None in
+ // let markers = Leaflet.feature_group [| |] in
+ window.setTimeout(() => map = getMap(), 0)
+ return element()
+}
+
+function element(): Element {
+ return h('div',
+ { className: 'g-Layout__Page' },
+ h('div',
+ { className: 'g-Layout__Header' },
+ h('a',
+ { className: 'g-Layout__Home',
+ href: '#'
+ },
+ 'Map'
+ ),
+ Layout.line(
+ { className: 'g-Layout__HeaderImportExport' },
+ h('input',
+ { id: 'g-Header__ImportInput',
+ type: 'file',
+ onchange: () => {
+ // match !map with
+ // | Some map ->
+ // let reader = File.reader () in
+ // let () = Element.add_event_listener reader 'load' (fun _ ->
+ // let str = File.result reader in
+ // let new_state = State.from_dicts (CSV.to_dicts (CSV.parse str)) in
+ // let () = History.push_state '' '' ('#' ^ State.to_url_string new_state) () in
+ // reload_from_hash state map markers true)
+ // in
+ // File.read_as_text reader (
+ // Js.Array.unsafe_get (Element.files (Event.target e)) 0)
+ // | _ ->
+ // ())
+ }
+ }
+ ),
+ h('label',
+ { for: 'g-Header__ImportInput',
+ className: 'g-Button__Text'
+ },
+ 'Import'
+ ),
+ Button.text({}, 'Export')
+ // { onclick: () => File.download 'map.csv' (State.to_csv_string !state)) |]
+ )
+ )
+ , h('div',
+ { className: 'g-Map' },
+ h('div', { id: 'g-Map__Content' })
+ )
+ )
+}
+
+function getMap(): object {
+
+ const map = L.map('g-Map__Content', {
+ center: [51.505, -0.09],
+ zoom: 13,
+ attributionControl: false
+ })
+
+ // map.addLayer(markers)
+ map.addLayer(L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png'))
+
+ // (* Init markers from url *)
+ // let () = reload_from_hash state map markers true in
+
+ // (* Reload the map if the URL changes *)
+ // let () = Element.add_event_listener Window.window 'popstate' (fun _ ->
+ // reload_from_hash state map markers true)
+ // in
+
+ // Context menu
+ map.addEventListener('contextmenu', e => {
+ ContextMenu.show(
+ e.originalEvent,
+ [ { label: 'Add a marker',
+ action: () => {
+ const pos = e.latlng
+ const marker = { pos, name: '', color: '#3F92CF', icon: '' }
+ const colors: string[] = []
+
+ const add_marker = (name: string, color: string, icon: string) => {
+ console.log('adding marker…')
+ // let new_marker = { State.pos = pos; name = name; color = color; icon = icon } in
+ // let new_state = State.update !state pos new_marker in
+ // let () = History.push_state '' '' ('#' ^ State.to_url_string new_state) () in
+ // reload_from_hash state map markers false
+ }
+
+ // let marker =
+ // match State.last_added !state with
+ // | Some m -> { m with pos = pos; name = '' }
+ // | _ -> { pos = pos; name = ''; color = '#3f92cf'; icon = '' }
+ // in
+ // let colors = State.colors !state in
+ Modal.show(Marker.form(
+ add_marker,
+ colors,
+ marker.name,
+ marker.color,
+ marker.icon
+ ))
+ }
+ }
+ ]
+ )
+ })
+
+ return map
+}
diff --git a/src/marker.ts b/src/marker.ts
new file mode 100644
index 0000000..67b9649
--- /dev/null
+++ b/src/marker.ts
@@ -0,0 +1,125 @@
+import { h } from 'lib/h'
+import * as Button from 'lib/button'
+import * as Form from 'lib/form'
+import * as Layout from 'lib/layout'
+import * as Modal from 'lib/modal'
+import * as FontAwesome from 'lib/fontAwesome'
+import * as AutoComplete from 'lib/autoComplete'
+
+export function form(
+ onValidate: (name: string, color: string, icon: string) => void,
+ colors: string[],
+ name: string,
+ color: string,
+ icon: string
+): Element {
+ const onSubmit = () => {
+ onValidate(name, color, icon)
+ Modal.hide()
+ }
+ const domIcon = h('div', { className: `fa fa-${icon}` })
+ return h('div',
+ {},
+ Layout.section(
+ {},
+ h('form',
+ { className: 'g-MarkerForm',
+ onsubmit: (e: Event) => {
+ e.preventDefault()
+ onSubmit()
+ }
+ },
+ Layout.section(
+ {},
+ Form.input(
+ 'g-MarkerForm__Name',
+ 'Name',
+ { oninput: (e: Event) => {
+ if (e.target !== null) {
+ name = (e.target as HTMLInputElement).value
+ }
+ },
+ value: name
+ }
+ ),
+ Form.colorInput(
+ colors,
+ 'g-MarkerForm__Color',
+ 'Color',
+ color,
+ newColor => color = newColor
+ ),
+ h('div',
+ { className: 'g-Form__Field' },
+ h('div',
+ { className: 'g-Form__Label' },
+ h('label', { for: 'g-MarkerForm__IconInput' }, 'Icon')
+ ),
+ Layout.line(
+ { className: 'g-MarkerForm__AutoCompleteAndIcon' },
+ AutoComplete.create(
+ { value: icon,
+ className: 'g-MarkerForm__AutoComplete'
+ },
+ 'g-MarkerForm__IconInput',
+ FontAwesome.icons,
+ icon => h('div',
+ {},
+ h('div', { className: `g-MarkerForm__IconEntry fa fa-${icon}` }),
+ icon
+ ),
+ newIcon => {
+ icon = newIcon
+ domIcon.className = `fa fa-${icon}`
+ }),
+ h('div', { className: 'g-MarkerForm__Icon' }, domIcon)
+ )
+ )
+ )
+ ),
+ Layout.line(
+ {},
+ Button.action({ onclick: () => onSubmit() }, 'Save'),
+ Button.cancel(
+ { onclick: () => Modal.hide(),
+ type: 'button'
+ },
+ 'Cancel'
+ )
+ )
+ )
+ )
+}
+
+// let create on_remove on_update colors pos init_name init_color init_icon =
+// let marker =
+// Leaflet.marker pos
+// { title = init_name
+// ; icon = Icon.create init_icon init_color
+// ; draggable = true
+// }
+// in
+//
+// (* Context menu *)
+// let () = Leaflet.on marker 'contextmenu' (fun event ->
+// ContextMenu.show
+// (Leaflet.original_event event)
+// [| { label = 'Modify'
+// ; action = fun _ ->
+// Modal.show (form (on_update pos pos) colors init_name init_color init_icon)
+// }
+// ; { label = 'Remove'
+// ; action = fun _ -> on_remove pos
+// }
+// |])
+// in
+//
+// (* Move the cursor on drag *)
+// let () = Leaflet.on marker 'dragend' (fun e ->
+// let newPos = Leaflet.get_lat_lng (Leaflet.target e) () in
+// on_update pos newPos init_name init_color init_icon) in
+//
+// let () = Leaflet.on marker 'dblclick' (fun _ ->
+// Modal.show (form (on_update pos pos) colors init_name init_color init_icon)) in
+//
+// marker
diff --git a/src/types/leaflet.d.ts b/src/types/leaflet.d.ts
new file mode 100644
index 0000000..39ddf5a
--- /dev/null
+++ b/src/types/leaflet.d.ts
@@ -0,0 +1,28 @@
+export as namespace L
+
+export function map(element: string, options?: MapOptions): Map
+
+export interface MapOptions {
+ center: number[],
+ zoom: number,
+ attributionControl: boolean,
+}
+
+export interface Map {
+ addLayer: (layer: Layer) => void,
+ addEventListener: (name: string, fn: (e: MapEvent) => void) => void,
+}
+
+interface MapEvent {
+ originalEvent: MouseEvent,
+ latlng: {lat: number, lng: number},
+}
+
+export interface Pos {
+ lat: number,
+ lng: number,
+}
+
+export function tileLayer(url: string): Layer
+
+export interface Layer {}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..5cbbec5
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,13 @@
+{
+ "compilerOptions": {
+ "module": "amd",
+ "target": "ES2017",
+ "baseUrl": "src",
+ "noImplicitAny": true,
+ "strictNullChecks": true,
+ "removeComments": true,
+ "preserveConstEnums": true,
+ "outFile": "public/main.js"
+ },
+ "include": ["src/**/*"]
+}
--
cgit v1.2.3