new: yew-based front-end
This commit is contained in:
		
							parent
							
								
									abadb2ec7d
								
							
						
					
					
						commit
						d64938e8e5
					
				
					 20 changed files with 680 additions and 6263 deletions
				
			
		
							
								
								
									
										70
									
								
								.github/workflows/ci.yml
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										70
									
								
								.github/workflows/ci.yml
									
										
									
									
										vendored
									
									
								
							|  | @ -1,70 +0,0 @@ | ||||||
| name: ci |  | ||||||
| 
 |  | ||||||
| on: |  | ||||||
|   push: |  | ||||||
|     branches: [ main ] |  | ||||||
|   pull_request: |  | ||||||
|     branches: [ main ] |  | ||||||
| 
 |  | ||||||
| env: |  | ||||||
|   CARGO_TERM_COLOR: always |  | ||||||
| 
 |  | ||||||
| jobs: |  | ||||||
|   test: |  | ||||||
|     runs-on: ubuntu-latest |  | ||||||
|     steps: |  | ||||||
|     - uses: actions/checkout@v2 |  | ||||||
| 
 |  | ||||||
|     - uses: actions/cache@v2 |  | ||||||
|       with: |  | ||||||
|         path: | |  | ||||||
|           ~/.cargo/registry |  | ||||||
|           ~/.cargo/git |  | ||||||
|           target |  | ||||||
|         key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} |  | ||||||
| 
 |  | ||||||
|     - name: lint |  | ||||||
|       run: cargo fmt -- --check |  | ||||||
| 
 |  | ||||||
|     - name: install wasm-pack |  | ||||||
|       run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh |  | ||||||
| 
 |  | ||||||
|     - run: cargo check |  | ||||||
| 
 |  | ||||||
|     - run: cargo test |  | ||||||
| 
 |  | ||||||
|     - run: wasm-pack test --headless --firefox |  | ||||||
| 
 |  | ||||||
|     - run: wasm-pack test --headless --chrome |  | ||||||
| 
 |  | ||||||
|   build: |  | ||||||
|     runs-on: ubuntu-latest |  | ||||||
|     needs: test |  | ||||||
|     steps: |  | ||||||
|     - uses: actions/checkout@v2 |  | ||||||
| 
 |  | ||||||
|     - uses: actions/cache@v2 |  | ||||||
|       with: |  | ||||||
|         path: | |  | ||||||
|           ~/.cargo/registry |  | ||||||
|           ~/.cargo/git |  | ||||||
|           target |  | ||||||
|         key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} |  | ||||||
| 
 |  | ||||||
|     - name: install wasm-pack |  | ||||||
|       run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh |  | ||||||
| 
 |  | ||||||
|     - name: build |  | ||||||
|       run: | |  | ||||||
|         wasm-pack build |  | ||||||
|         cd www |  | ||||||
|         npm install |  | ||||||
|         npm run build |  | ||||||
| 
 |  | ||||||
|     - name: deploy |  | ||||||
|       uses: peaceiris/actions-gh-pages@v3 |  | ||||||
|       if: github.ref == 'refs/heads/main' |  | ||||||
|       with: |  | ||||||
|         github_token: ${{ secrets.GITHUB_TOKEN }} |  | ||||||
|         publish_dir: www/dist |  | ||||||
|         cname: gpx.thermokar.st |  | ||||||
							
								
								
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -1,5 +1,6 @@ | ||||||
| /target | /target | ||||||
| **/*.rs.bk | **/*.rs.bk | ||||||
| bin/ | bin/ | ||||||
|  | dist/ | ||||||
| pkg/ | pkg/ | ||||||
| wasm-pack.log | wasm-pack.log | ||||||
|  |  | ||||||
							
								
								
									
										316
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										316
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							|  | @ -1,5 +1,7 @@ | ||||||
| # This file is automatically @generated by Cargo. | # This file is automatically @generated by Cargo. | ||||||
| # It is not intended for manual editing. | # It is not intended for manual editing. | ||||||
|  | version = 3 | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "addr2line" | name = "addr2line" | ||||||
| version = "0.14.0" | version = "0.14.0" | ||||||
|  | @ -41,6 +43,12 @@ dependencies = [ | ||||||
|  "rustc-demangle", |  "rustc-demangle", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "boolinator" | ||||||
|  | version = "2.4.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "bumpalo" | name = "bumpalo" | ||||||
| version = "3.4.0" | version = "3.4.0" | ||||||
|  | @ -106,6 +114,113 @@ version = "0.23.0" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" | checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "gloo" | ||||||
|  | version = "0.4.2" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "23947965eee55e3e97a5cd142dd4c10631cc349b48cecca0ed230fd296f568cd" | ||||||
|  | dependencies = [ | ||||||
|  |  "gloo-console", | ||||||
|  |  "gloo-dialogs", | ||||||
|  |  "gloo-events", | ||||||
|  |  "gloo-file", | ||||||
|  |  "gloo-render", | ||||||
|  |  "gloo-storage", | ||||||
|  |  "gloo-timers", | ||||||
|  |  "gloo-utils", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "gloo-console" | ||||||
|  | version = "0.2.1" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "3907f786f65bbb4f419e918b0c5674175ef1c231ecda93b2dbd65fd1e8882637" | ||||||
|  | dependencies = [ | ||||||
|  |  "js-sys", | ||||||
|  |  "serde", | ||||||
|  |  "wasm-bindgen", | ||||||
|  |  "web-sys", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "gloo-dialogs" | ||||||
|  | version = "0.1.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "4ffb557a2ea2ed283f1334423d303a336fad55fb8572d51ae488f828b1464b40" | ||||||
|  | dependencies = [ | ||||||
|  |  "wasm-bindgen", | ||||||
|  |  "web-sys", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "gloo-events" | ||||||
|  | version = "0.1.1" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "088514ec8ef284891c762c88a66b639b3a730134714692ee31829765c5bc814f" | ||||||
|  | dependencies = [ | ||||||
|  |  "wasm-bindgen", | ||||||
|  |  "web-sys", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "gloo-file" | ||||||
|  | version = "0.2.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "d31ba1f51868ae10a0b665c6dccd5ed967486e7c17055d1c889596ee983be493" | ||||||
|  | dependencies = [ | ||||||
|  |  "gloo-events", | ||||||
|  |  "js-sys", | ||||||
|  |  "wasm-bindgen", | ||||||
|  |  "web-sys", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "gloo-render" | ||||||
|  | version = "0.1.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "5b4cda6e149df3bb4a3c6a343873903e5bcc2448a9877d61bb8274806ad67f6e" | ||||||
|  | dependencies = [ | ||||||
|  |  "wasm-bindgen", | ||||||
|  |  "web-sys", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "gloo-storage" | ||||||
|  | version = "0.2.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "1b5057761927af1b1929d02b1f49cf83553dd347a473ee7c8bb08420f2673ffc" | ||||||
|  | dependencies = [ | ||||||
|  |  "gloo-utils", | ||||||
|  |  "js-sys", | ||||||
|  |  "serde", | ||||||
|  |  "serde_json", | ||||||
|  |  "thiserror", | ||||||
|  |  "wasm-bindgen", | ||||||
|  |  "web-sys", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "gloo-timers" | ||||||
|  | version = "0.2.1" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f" | ||||||
|  | dependencies = [ | ||||||
|  |  "js-sys", | ||||||
|  |  "wasm-bindgen", | ||||||
|  |  "web-sys", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "gloo-utils" | ||||||
|  | version = "0.1.1" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "3d77d28d9a6f7c384d9e40293fa11f05558bf928a993208e12528ee6633cb415" | ||||||
|  | dependencies = [ | ||||||
|  |  "js-sys", | ||||||
|  |  "wasm-bindgen", | ||||||
|  |  "web-sys", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "gpx" | name = "gpx" | ||||||
| version = "0.8.1" | version = "0.8.1" | ||||||
|  | @ -124,12 +239,37 @@ name = "gpx-web-utils" | ||||||
| version = "0.0.1" | version = "0.0.1" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "console_error_panic_hook", |  "console_error_panic_hook", | ||||||
|  |  "gloo-file", | ||||||
|  "gpx", |  "gpx", | ||||||
|  "js-sys", |  "js-sys", | ||||||
|  "wasm-bindgen", |  "wasm-bindgen", | ||||||
|  "wasm-bindgen-test", |  "web-sys", | ||||||
|  |  "wee_alloc", | ||||||
|  |  "yew", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "hashbrown" | ||||||
|  | version = "0.11.2" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "indexmap" | ||||||
|  | version = "1.7.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" | ||||||
|  | dependencies = [ | ||||||
|  |  "autocfg", | ||||||
|  |  "hashbrown", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "itoa" | ||||||
|  | version = "0.4.8" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "js-sys" | name = "js-sys" | ||||||
| version = "0.3.45" | version = "0.3.45" | ||||||
|  | @ -160,6 +300,12 @@ dependencies = [ | ||||||
|  "cfg-if 0.1.10", |  "cfg-if 0.1.10", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "memory_units" | ||||||
|  | version = "0.4.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "miniz_oxide" | name = "miniz_oxide" | ||||||
| version = "0.4.3" | version = "0.4.3" | ||||||
|  | @ -195,6 +341,30 @@ version = "0.22.0" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" | checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "proc-macro-error" | ||||||
|  | version = "1.0.4" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" | ||||||
|  | dependencies = [ | ||||||
|  |  "proc-macro-error-attr", | ||||||
|  |  "proc-macro2", | ||||||
|  |  "quote", | ||||||
|  |  "syn", | ||||||
|  |  "version_check", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "proc-macro-error-attr" | ||||||
|  | version = "1.0.4" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" | ||||||
|  | dependencies = [ | ||||||
|  |  "proc-macro2", | ||||||
|  |  "quote", | ||||||
|  |  "version_check", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "proc-macro2" | name = "proc-macro2" | ||||||
| version = "1.0.24" | version = "1.0.24" | ||||||
|  | @ -220,10 +390,53 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" | checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "scoped-tls" | name = "ryu" | ||||||
| version = "1.0.0" | version = "1.0.5" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "scoped-tls-hkt" | ||||||
|  | version = "0.1.2" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "c2e9d7eaddb227e8fbaaa71136ae0e1e913ca159b86c7da82f3e8f0044ad3a63" | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "serde" | ||||||
|  | version = "1.0.118" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" | ||||||
|  | dependencies = [ | ||||||
|  |  "serde_derive", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "serde_derive" | ||||||
|  | version = "1.0.118" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" | ||||||
|  | dependencies = [ | ||||||
|  |  "proc-macro2", | ||||||
|  |  "quote", | ||||||
|  |  "syn", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "serde_json" | ||||||
|  | version = "1.0.72" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527" | ||||||
|  | dependencies = [ | ||||||
|  |  "itoa", | ||||||
|  |  "ryu", | ||||||
|  |  "serde", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "slab" | ||||||
|  | version = "0.4.5" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "syn" | name = "syn" | ||||||
|  | @ -236,6 +449,26 @@ dependencies = [ | ||||||
|  "unicode-xid", |  "unicode-xid", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "thiserror" | ||||||
|  | version = "1.0.30" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" | ||||||
|  | dependencies = [ | ||||||
|  |  "thiserror-impl", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "thiserror-impl" | ||||||
|  | version = "1.0.30" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" | ||||||
|  | dependencies = [ | ||||||
|  |  "proc-macro2", | ||||||
|  |  "quote", | ||||||
|  |  "syn", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "time" | name = "time" | ||||||
| version = "0.1.44" | version = "0.1.44" | ||||||
|  | @ -253,6 +486,12 @@ version = "0.2.1" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" | checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "version_check" | ||||||
|  | version = "0.9.3" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "wasi" | name = "wasi" | ||||||
| version = "0.10.0+wasi-snapshot-preview1" | version = "0.10.0+wasi-snapshot-preview1" | ||||||
|  | @ -266,6 +505,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "1ac64ead5ea5f05873d7c12b545865ca2b8d28adfc50a49b84770a3a97265d42" | checksum = "1ac64ead5ea5f05873d7c12b545865ca2b8d28adfc50a49b84770a3a97265d42" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "cfg-if 0.1.10", |  "cfg-if 0.1.10", | ||||||
|  |  "serde", | ||||||
|  |  "serde_json", | ||||||
|  "wasm-bindgen-macro", |  "wasm-bindgen-macro", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | @ -325,30 +566,6 @@ version = "0.2.68" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307" | checksum = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307" | ||||||
| 
 | 
 | ||||||
| [[package]] |  | ||||||
| name = "wasm-bindgen-test" |  | ||||||
| version = "0.3.18" |  | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" |  | ||||||
| checksum = "34d1cdc8b98a557f24733d50a1199c4b0635e465eecba9c45b214544da197f64" |  | ||||||
| dependencies = [ |  | ||||||
|  "console_error_panic_hook", |  | ||||||
|  "js-sys", |  | ||||||
|  "scoped-tls", |  | ||||||
|  "wasm-bindgen", |  | ||||||
|  "wasm-bindgen-futures", |  | ||||||
|  "wasm-bindgen-test-macro", |  | ||||||
| ] |  | ||||||
| 
 |  | ||||||
| [[package]] |  | ||||||
| name = "wasm-bindgen-test-macro" |  | ||||||
| version = "0.3.18" |  | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" |  | ||||||
| checksum = "e8fb9c67be7439ee8ab1b7db502a49c05e51e2835b66796c705134d9b8e1a585" |  | ||||||
| dependencies = [ |  | ||||||
|  "proc-macro2", |  | ||||||
|  "quote", |  | ||||||
| ] |  | ||||||
| 
 |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "web-sys" | name = "web-sys" | ||||||
| version = "0.3.45" | version = "0.3.45" | ||||||
|  | @ -359,6 +576,18 @@ dependencies = [ | ||||||
|  "wasm-bindgen", |  "wasm-bindgen", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "wee_alloc" | ||||||
|  | version = "0.4.5" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" | ||||||
|  | dependencies = [ | ||||||
|  |  "cfg-if 0.1.10", | ||||||
|  |  "libc", | ||||||
|  |  "memory_units", | ||||||
|  |  "winapi", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "winapi" | name = "winapi" | ||||||
| version = "0.3.9" | version = "0.3.9" | ||||||
|  | @ -386,3 +615,34 @@ name = "xml-rs" | ||||||
| version = "0.8.3" | version = "0.8.3" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a" | checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a" | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "yew" | ||||||
|  | version = "0.18.0" | ||||||
|  | source = "git+https://github.com/yewstack/yew.git#996bf5b41ac30d7ada14fdc2f419de7659e94613" | ||||||
|  | dependencies = [ | ||||||
|  |  "console_error_panic_hook", | ||||||
|  |  "gloo", | ||||||
|  |  "gloo-utils", | ||||||
|  |  "indexmap", | ||||||
|  |  "js-sys", | ||||||
|  |  "scoped-tls-hkt", | ||||||
|  |  "slab", | ||||||
|  |  "wasm-bindgen", | ||||||
|  |  "wasm-bindgen-futures", | ||||||
|  |  "web-sys", | ||||||
|  |  "yew-macro", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "yew-macro" | ||||||
|  | version = "0.18.0" | ||||||
|  | source = "git+https://github.com/yewstack/yew.git#996bf5b41ac30d7ada14fdc2f419de7659e94613" | ||||||
|  | dependencies = [ | ||||||
|  |  "boolinator", | ||||||
|  |  "lazy_static", | ||||||
|  |  "proc-macro-error", | ||||||
|  |  "proc-macro2", | ||||||
|  |  "quote", | ||||||
|  |  "syn", | ||||||
|  | ] | ||||||
|  |  | ||||||
							
								
								
									
										24
									
								
								Cargo.toml
									
										
									
									
									
								
							
							
						
						
									
										24
									
								
								Cargo.toml
									
										
									
									
									
								
							|  | @ -4,25 +4,25 @@ version = "0.0.1" | ||||||
| authors = ["Matthew Dillon <matthewrdillon@gmail.com>"] | authors = ["Matthew Dillon <matthewrdillon@gmail.com>"] | ||||||
| edition = "2018" | edition = "2018" | ||||||
| description = "just some gpx-related tools that i want to use" | description = "just some gpx-related tools that i want to use" | ||||||
| repository = "https://github.com/thermokarst/gpx-web-utils" | repository = "git://pingo.thermokar.st/gpx-web-utils" | ||||||
| license = "MIT" | license = "MIT" | ||||||
| 
 | 
 | ||||||
| [lib] |  | ||||||
| crate-type = ["cdylib", "rlib"] |  | ||||||
| 
 |  | ||||||
| [features] |  | ||||||
| default = ["console_error_panic_hook"] |  | ||||||
| 
 |  | ||||||
| [dependencies] | [dependencies] | ||||||
| wasm-bindgen = "0.2.63" | wasm-bindgen = "0.2" | ||||||
| js-sys = "0.3.45" | js-sys = "0.3" | ||||||
| gpx = "0.8.1" | gpx = "0.8.1" | ||||||
|  | # TODO: still waiting on a public release | ||||||
|  | # yew = "0.19" | ||||||
|  | yew = { git = "https://github.com/yewstack/yew.git" } | ||||||
|  | gloo-file = "0.2" | ||||||
|  | wee_alloc = "0.4" | ||||||
| 
 | 
 | ||||||
| console_error_panic_hook = { version = "0.1.6", optional = true } | console_error_panic_hook = { version = "0.1.6", optional = true } | ||||||
| 
 | 
 | ||||||
| [dev-dependencies] |  | ||||||
| wasm-bindgen-test = "0.3.13" |  | ||||||
| 
 |  | ||||||
| [profile.release] | [profile.release] | ||||||
| opt-level = 3 | opt-level = 3 | ||||||
| lto = true | lto = true | ||||||
|  | 
 | ||||||
|  | [dependencies.web-sys] | ||||||
|  | version = "0.3" | ||||||
|  | features = ["File", "Blob", "Element", "MouseEvent", "EventTarget", "Url", "Event"] | ||||||
|  |  | ||||||
							
								
								
									
										24
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										24
									
								
								README.md
									
										
									
									
									
								
							|  | @ -1,11 +1,21 @@ | ||||||
| # gpx-web-utils | # gpx-web-utils | ||||||
| 
 | 
 | ||||||
|  | ## development | ||||||
| 
 | 
 | ||||||
| ## quickstart | ```bash | ||||||
|  | cargo install --locked trunk | ||||||
|  | cargo install wasm-bindgen-cli | ||||||
|  | rustup target add wasm32-unknown-unknown | ||||||
|  | trunk serve | ||||||
|  | ``` | ||||||
| 
 | 
 | ||||||
| 1. install [wasm-pack](https://rustwasm.github.io/wasm-pack/installer/) | ## deployment | ||||||
| 2. `wasm-pack build` | 
 | ||||||
| 3. `cd www` | ```bash | ||||||
| 4. `npm install` | trunk build --release | ||||||
| 5. `npm run start` | git switch deploy | ||||||
|  | rm index-* | ||||||
|  | cp dist/* . | ||||||
|  | git commit -am 'foo' | ||||||
|  | git push <DOKKU INSTANCE> deploy | ||||||
|  | ``` | ||||||
|  |  | ||||||
							
								
								
									
										25
									
								
								index.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								index.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | ||||||
|  | <!DOCTYPE html> | ||||||
|  | <html> | ||||||
|  |   <head> | ||||||
|  |     <meta charset="utf-8" /> | ||||||
|  |     <title>gpx.thermokar.st</title> | ||||||
|  |     <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||||
|  |     <style> | ||||||
|  |       body { | ||||||
|  |         max-width: 35em; | ||||||
|  |         margin: 0 auto; | ||||||
|  |         line-height: 1.5; | ||||||
|  |         font-family: sans-serif; | ||||||
|  |         font-size: large; | ||||||
|  |       } | ||||||
|  |     </style> | ||||||
|  |   </head> | ||||||
|  |   <body> | ||||||
|  |     <noscript> | ||||||
|  |       <mark> | ||||||
|  |         This page contains webassembly and javascript content, please enable | ||||||
|  |         javascript in your browser to use this tool. | ||||||
|  |       </mark> | ||||||
|  |     </noscript> | ||||||
|  |   </body> | ||||||
|  | </html> | ||||||
							
								
								
									
										81
									
								
								src/app.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/app.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,81 @@ | ||||||
|  | use super::loader::Loader; | ||||||
|  | 
 | ||||||
|  | use web_sys::Node; | ||||||
|  | use yew::virtual_dom::VNode; | ||||||
|  | use yew::{function_component, html, Html}; | ||||||
|  | 
 | ||||||
|  | #[function_component(App)] | ||||||
|  | pub fn app() -> Html { | ||||||
|  |     html! { | ||||||
|  |         <> | ||||||
|  |             <h1> | ||||||
|  |                 <a href="/"> | ||||||
|  |                     { "gpx.thermokar.st" } | ||||||
|  |                 </a> | ||||||
|  |             </h1> | ||||||
|  | 
 | ||||||
|  |             <p> | ||||||
|  |                 { "a client-side tool for merging " } | ||||||
|  |                 <a href="https://www.topografix.com/gpx.asp"> | ||||||
|  |                     { "gpx files" } | ||||||
|  |                 </a> | ||||||
|  |             </p> | ||||||
|  | 
 | ||||||
|  |             <Loader /> | ||||||
|  | 
 | ||||||
|  |             <hr/> | ||||||
|  | 
 | ||||||
|  |             <Footer /> | ||||||
|  |         </> | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[function_component(Footer)] | ||||||
|  | fn footer() -> Html { | ||||||
|  |     let notes = Vec::from([ | ||||||
|  |         // note 1
 | ||||||
|  |         "this has only been tested on GPX files produced by \ | ||||||
|  |         <a href=\"https://strava.com\" target=\"_blank\">strava</a> and \ | ||||||
|  |         <a href=\"https://garmin.com\" target=\"_blank\">garmin</a>", | ||||||
|  |         // note 2
 | ||||||
|  |         "all third-party extension info \ | ||||||
|  |         <a href=\"https://github.com/georust/gpx/issues/8\" target=\"_blank\">\ | ||||||
|  |         is stripped</a>",
 | ||||||
|  |         // note 3
 | ||||||
|  |         "if the app breaks, try refreshing the page", | ||||||
|  |         "source (public access): git://pingo.thermokar.st/gpx-web-utils", | ||||||
|  |         // note 4
 | ||||||
|  |         "source (mirror): \ | ||||||
|  |         <a href=\"https://github.com/thermokarst/gpx-web-utils\" target=\"_blank\">\ | ||||||
|  |         https://github.com/thermokarst/gpx-web-utils</a>",
 | ||||||
|  |     ]); | ||||||
|  | 
 | ||||||
|  |     html! { | ||||||
|  |         <div> | ||||||
|  |             <ul> | ||||||
|  |                 { for notes.iter().map(|n| inner_html_enabled_li(n)) } | ||||||
|  |             </ul> | ||||||
|  | 
 | ||||||
|  |             <span> | ||||||
|  |                 <small> | ||||||
|  |                     { "\u{000A9} matthew ryan dillon, 2021" } | ||||||
|  |                 </small> | ||||||
|  |             </span> | ||||||
|  |         </div> | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn inner_html_enabled_li(data: &str) -> Html { | ||||||
|  |     let li = web_sys::window() | ||||||
|  |         .unwrap() | ||||||
|  |         .document() | ||||||
|  |         .unwrap() | ||||||
|  |         .create_element("li") | ||||||
|  |         .unwrap(); | ||||||
|  | 
 | ||||||
|  |     li.set_inner_html(data); | ||||||
|  | 
 | ||||||
|  |     let node = Node::from(li); | ||||||
|  | 
 | ||||||
|  |     VNode::VRef(node) | ||||||
|  | } | ||||||
							
								
								
									
										88
									
								
								src/gpx.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								src/gpx.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,88 @@ | ||||||
|  | use std::error::Error; | ||||||
|  | use wasm_bindgen::prelude::*; | ||||||
|  | use web_sys::{Blob, MouseEvent, Url}; | ||||||
|  | 
 | ||||||
|  | fn join_gpx_files(files: &[String]) -> Result<gpx::Gpx, Box<dyn Error>> { | ||||||
|  |     let mut merged_gpx: gpx::Gpx = Default::default(); | ||||||
|  |     let mut merged_track: gpx::Track = gpx::Track::new(); | ||||||
|  | 
 | ||||||
|  |     for file in files.iter() { | ||||||
|  |         let buffer = std::io::BufReader::new(file.as_bytes()); | ||||||
|  |         let mut parsed_gpx: gpx::Gpx = gpx::read(buffer)?; | ||||||
|  | 
 | ||||||
|  |         // consolidate all track segements into one single track.
 | ||||||
|  |         for track in parsed_gpx.tracks { | ||||||
|  |             for segment in track.segments { | ||||||
|  |                 merged_track.segments.push(segment); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         merged_gpx.waypoints.append(&mut parsed_gpx.waypoints); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     merged_gpx.tracks.push(merged_track); | ||||||
|  | 
 | ||||||
|  |     let link = gpx::Link { | ||||||
|  |         href: String::from("https://gpx.thermokar.st"), | ||||||
|  |         ..Default::default() | ||||||
|  |     }; | ||||||
|  |     let author = gpx::Person { | ||||||
|  |         link: Some(link), | ||||||
|  |         ..Default::default() | ||||||
|  |     }; | ||||||
|  |     let metadata = gpx::Metadata { | ||||||
|  |         name: Some(String::from("merged")), | ||||||
|  |         author: Some(author), | ||||||
|  |         ..Default::default() | ||||||
|  |     }; | ||||||
|  |     merged_gpx.metadata = Some(metadata); | ||||||
|  |     merged_gpx.version = gpx::GpxVersion::Gpx11; | ||||||
|  | 
 | ||||||
|  |     Ok(merged_gpx) | ||||||
|  | } | ||||||
|  | fn write_gpx_to_buffer(gpx: gpx::Gpx) -> Result<js_sys::Array, Box<dyn Error>> { | ||||||
|  |     let mut buffer = Vec::new(); | ||||||
|  |     gpx::write(&gpx, &mut buffer)?; | ||||||
|  | 
 | ||||||
|  |     let uint8arr = js_sys::Uint8Array::new(&unsafe { js_sys::Uint8Array::view(&buffer) }.into()); | ||||||
|  |     let array = js_sys::Array::new(); | ||||||
|  |     array.push(&uint8arr.buffer()); | ||||||
|  | 
 | ||||||
|  |     Ok(array) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn merge(files: &[String]) -> Result<Blob, Box<dyn Error>> { | ||||||
|  |     let merged: gpx::Gpx = join_gpx_files(files)?; | ||||||
|  |     let out_vec = write_gpx_to_buffer(merged)?; | ||||||
|  |     let result = Blob::new_with_u8_array_sequence(&out_vec).map_err(|e| e.as_string().unwrap())?; | ||||||
|  | 
 | ||||||
|  |     Ok(result) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn download(merged: Blob) -> Result<(), Box<dyn Error>> { | ||||||
|  |     let window = web_sys::window().ok_or("no global `window` exists")?; | ||||||
|  |     let document = window | ||||||
|  |         .document() | ||||||
|  |         .ok_or("should have a document on window")?; | ||||||
|  | 
 | ||||||
|  |     let err_handler = |e: JsValue| e.as_string().unwrap(); | ||||||
|  |     let anchor_element = document.create_element("a").map_err(err_handler)?; | ||||||
|  |     let url = Url::create_object_url_with_blob(&merged).map_err(err_handler)?; | ||||||
|  | 
 | ||||||
|  |     anchor_element | ||||||
|  |         .set_attribute("href", &url) | ||||||
|  |         .map_err(err_handler)?; | ||||||
|  |     anchor_element | ||||||
|  |         .set_attribute("download", "merged.gpx") | ||||||
|  |         .map_err(err_handler)?; | ||||||
|  | 
 | ||||||
|  |     let event = MouseEvent::new("click").map_err(err_handler)?; | ||||||
|  |     anchor_element.dispatch_event(&event).map_err(err_handler)?; | ||||||
|  | 
 | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[wasm_bindgen] | ||||||
|  | extern "C" { | ||||||
|  |     pub fn alert(s: &str); | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								src/lib.rs
									
										
									
									
									
								
							
							
						
						
									
										17
									
								
								src/lib.rs
									
										
									
									
									
								
							|  | @ -1,17 +0,0 @@ | ||||||
| mod utils; |  | ||||||
| 
 |  | ||||||
| use wasm_bindgen::prelude::*; |  | ||||||
| 
 |  | ||||||
| #[cfg(feature = "wee_alloc")] |  | ||||||
| #[global_allocator] |  | ||||||
| static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; |  | ||||||
| 
 |  | ||||||
| #[wasm_bindgen] |  | ||||||
| pub fn merge(files: js_sys::Array) -> wasm_bindgen::JsValue { |  | ||||||
|     utils::set_panic_hook(); |  | ||||||
|     let files: Vec<String> = utils::translate_js_to_rust(files); |  | ||||||
|     let merged: gpx::Gpx = utils::join_gpx_files(files); |  | ||||||
|     let out_vec: Vec<u8> = utils::write_gpx_to_buffer(merged); |  | ||||||
| 
 |  | ||||||
|     JsValue::from_str(&String::from_utf8(out_vec).unwrap()) |  | ||||||
| } |  | ||||||
							
								
								
									
										155
									
								
								src/loader.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								src/loader.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,155 @@ | ||||||
|  | use std::collections::HashMap; | ||||||
|  | 
 | ||||||
|  | use gloo_file::callbacks::FileReader; | ||||||
|  | use gloo_file::File; | ||||||
|  | use web_sys::{Blob, Event, HtmlInputElement}; | ||||||
|  | use yew::{html, html::TargetCast, Component, Context, Html}; | ||||||
|  | 
 | ||||||
|  | use super::gpx; | ||||||
|  | 
 | ||||||
|  | pub enum Msg { | ||||||
|  |     FileLoaded(String, String), | ||||||
|  |     StartLoad(Vec<File>), | ||||||
|  |     FilesLoaded, | ||||||
|  |     Download(Blob), | ||||||
|  |     Reset, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct Loader { | ||||||
|  |     readers: HashMap<String, FileReader>, | ||||||
|  |     files: Vec<String>, | ||||||
|  |     count: usize, | ||||||
|  |     is_loading: bool, | ||||||
|  |     // This field is to handle resetting the native HTML widget's state on error
 | ||||||
|  |     field_value: &'static str, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Component for Loader { | ||||||
|  |     type Message = Msg; | ||||||
|  |     type Properties = (); | ||||||
|  | 
 | ||||||
|  |     fn create(_ctx: &Context<Self>) -> Self { | ||||||
|  |         Self { | ||||||
|  |             readers: HashMap::default(), | ||||||
|  |             files: vec![], | ||||||
|  |             count: 0, | ||||||
|  |             is_loading: false, | ||||||
|  |             field_value: "", | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool { | ||||||
|  |         match msg { | ||||||
|  |             Msg::FileLoaded(filename, data) => { | ||||||
|  |                 self.files.push(data); | ||||||
|  |                 self.readers.remove(&filename); | ||||||
|  |                 if self.files.len() == self.count { | ||||||
|  |                     ctx.link().send_message(Msg::FilesLoaded); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 true | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             Msg::StartLoad(files) => { | ||||||
|  |                 self.count = files.len(); | ||||||
|  |                 if self.count < 2 { | ||||||
|  |                     gpx::alert("must load two or more files"); | ||||||
|  |                     ctx.link().send_message(Msg::Reset); | ||||||
|  |                     return true; | ||||||
|  |                 } | ||||||
|  |                 self.is_loading = true; | ||||||
|  | 
 | ||||||
|  |                 for file in files.into_iter() { | ||||||
|  |                     let file_name = file.name(); | ||||||
|  |                     let task = { | ||||||
|  |                         let file_name = file_name.clone(); | ||||||
|  |                         let link = ctx.link().clone(); | ||||||
|  | 
 | ||||||
|  |                         gloo_file::callbacks::read_as_text(&file, move |res| { | ||||||
|  |                             link.send_message(Msg::FileLoaded( | ||||||
|  |                                 file_name, | ||||||
|  |                                 res.unwrap_or_else(|e| e.to_string()), | ||||||
|  |                             )) | ||||||
|  |                         }) | ||||||
|  |                     }; | ||||||
|  |                     self.readers.insert(file_name, task); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 true | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             Msg::FilesLoaded => { | ||||||
|  |                 let link = ctx.link(); | ||||||
|  | 
 | ||||||
|  |                 let merged = match gpx::merge(&self.files) { | ||||||
|  |                     Ok(result) => result, | ||||||
|  |                     Err(err) => { | ||||||
|  |                         gpx::alert(&err.to_string()); | ||||||
|  |                         link.send_message(Msg::Reset); | ||||||
|  |                         return true; | ||||||
|  |                     } | ||||||
|  |                 }; | ||||||
|  | 
 | ||||||
|  |                 link.send_message(Msg::Download(merged)); | ||||||
|  | 
 | ||||||
|  |                 true | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             Msg::Download(merged) => { | ||||||
|  |                 let link = ctx.link(); | ||||||
|  | 
 | ||||||
|  |                 match gpx::download(merged) { | ||||||
|  |                     Ok(_) => (), | ||||||
|  |                     Err(err) => { | ||||||
|  |                         gpx::alert(&err.to_string()); | ||||||
|  |                         link.send_message(Msg::Reset); | ||||||
|  |                         return true; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 link.send_message(Msg::Reset); | ||||||
|  | 
 | ||||||
|  |                 true | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             Msg::Reset => { | ||||||
|  |                 self.readers = HashMap::default(); | ||||||
|  |                 self.files = vec![]; | ||||||
|  |                 self.count = 0; | ||||||
|  |                 self.is_loading = false; | ||||||
|  |                 self.field_value = ""; | ||||||
|  | 
 | ||||||
|  |                 true | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn view(&self, ctx: &Context<Self>) -> Html { | ||||||
|  |         let cb = move |e: Event| { | ||||||
|  |             let mut result = Vec::new(); | ||||||
|  |             let input: HtmlInputElement = e.target_unchecked_into(); | ||||||
|  | 
 | ||||||
|  |             if let Some(files) = input.files() { | ||||||
|  |                 let files = js_sys::try_iter(&files) | ||||||
|  |                     .unwrap() | ||||||
|  |                     .unwrap() | ||||||
|  |                     .map(|v| web_sys::File::from(v.unwrap())) | ||||||
|  |                     .map(File::from); | ||||||
|  |                 result.extend(files); | ||||||
|  |             } | ||||||
|  |             Msg::StartLoad(result) | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         html! { | ||||||
|  |             if self.is_loading { | ||||||
|  |                 <span><strong>{"processing..."}</strong></span> | ||||||
|  |             } else { | ||||||
|  |                 <input | ||||||
|  |                     type="file" | ||||||
|  |                     value={self.field_value} | ||||||
|  |                     multiple=true | ||||||
|  |                     onchange={ctx.link().callback(cb)} | ||||||
|  |                 /> | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								src/main.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/main.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | ||||||
|  | extern crate wee_alloc; | ||||||
|  | 
 | ||||||
|  | mod app; | ||||||
|  | mod gpx; | ||||||
|  | mod loader; | ||||||
|  | 
 | ||||||
|  | // Use `wee_alloc` as the global allocator.
 | ||||||
|  | #[global_allocator] | ||||||
|  | static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; | ||||||
|  | 
 | ||||||
|  | fn main() { | ||||||
|  |     yew::start_app::<app::App>(); | ||||||
|  | } | ||||||
							
								
								
									
										55
									
								
								src/utils.rs
									
										
									
									
									
								
							
							
						
						
									
										55
									
								
								src/utils.rs
									
										
									
									
									
								
							|  | @ -1,55 +0,0 @@ | ||||||
| pub fn set_panic_hook() { |  | ||||||
|     #[cfg(feature = "console_error_panic_hook")] |  | ||||||
|     console_error_panic_hook::set_once(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| pub fn translate_js_to_rust(files: js_sys::Array) -> Vec<String> { |  | ||||||
|     // https://github.com/rustwasm/wasm-bindgen/issues/111
 |  | ||||||
|     files.iter().map(|f| f.as_string().unwrap()).collect() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| pub fn join_gpx_files(files: Vec<String>) -> gpx::Gpx { |  | ||||||
|     let mut merged_gpx: gpx::Gpx = Default::default(); |  | ||||||
|     let mut merged_track: gpx::Track = gpx::Track::new(); |  | ||||||
| 
 |  | ||||||
|     for file in files.iter() { |  | ||||||
|         let buffer = std::io::BufReader::new(file.as_bytes()); |  | ||||||
|         let mut parsed_gpx: gpx::Gpx = gpx::read(buffer).expect("invalid gpx"); |  | ||||||
| 
 |  | ||||||
|         // consolidate all track segements into one single track.
 |  | ||||||
|         for track in parsed_gpx.tracks { |  | ||||||
|             for segment in track.segments { |  | ||||||
|                 merged_track.segments.push(segment); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         merged_gpx.waypoints.append(&mut parsed_gpx.waypoints); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     merged_gpx.tracks.push(merged_track); |  | ||||||
| 
 |  | ||||||
|     let link = gpx::Link { |  | ||||||
|         href: String::from("https://gpx.thermokar.st"), |  | ||||||
|         ..Default::default() |  | ||||||
|     }; |  | ||||||
|     let author = gpx::Person { |  | ||||||
|         link: Some(link), |  | ||||||
|         ..Default::default() |  | ||||||
|     }; |  | ||||||
|     let metadata = gpx::Metadata { |  | ||||||
|         name: Some(String::from("merged")), |  | ||||||
|         author: Some(author), |  | ||||||
|         ..Default::default() |  | ||||||
|     }; |  | ||||||
|     merged_gpx.metadata = Some(metadata); |  | ||||||
|     merged_gpx.version = gpx::GpxVersion::Gpx11; |  | ||||||
| 
 |  | ||||||
|     merged_gpx |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| pub fn write_gpx_to_buffer(gpx: gpx::Gpx) -> Vec<u8> { |  | ||||||
|     let mut buffer = Vec::new(); |  | ||||||
|     gpx::write(&gpx, &mut buffer).unwrap(); |  | ||||||
| 
 |  | ||||||
|     buffer |  | ||||||
| } |  | ||||||
							
								
								
									
										93
									
								
								tests/web.rs
									
										
									
									
									
								
							
							
						
						
									
										93
									
								
								tests/web.rs
									
										
									
									
									
								
							|  | @ -1,93 +0,0 @@ | ||||||
| //! Test suite for the Web and headless browsers.
 |  | ||||||
| 
 |  | ||||||
| #![cfg(target_arch = "wasm32")] |  | ||||||
| 
 |  | ||||||
| extern crate wasm_bindgen_test; |  | ||||||
| use wasm_bindgen_test::*; |  | ||||||
| 
 |  | ||||||
| wasm_bindgen_test_configure!(run_in_browser); |  | ||||||
| 
 |  | ||||||
| #[wasm_bindgen_test] |  | ||||||
| fn basic_merge() { |  | ||||||
|     // arrange
 |  | ||||||
|     let array: js_sys::Array = js_sys::Array::new(); |  | ||||||
|     let file1 = wasm_bindgen::JsValue::from_str( |  | ||||||
|         "<?xml version='1.0' encoding='utf-8'?>
 |  | ||||||
|          <gpx version='1.0' encoding='UTF-8'> |  | ||||||
|            <trk> |  | ||||||
|              <name>file1 tracks</name> |  | ||||||
|              <type>1</type> |  | ||||||
|              <trkseg> |  | ||||||
|                <trkpt lat='35.466388' lon='-111.640076'> |  | ||||||
|                  <ele>2152.8</ele> |  | ||||||
|                  <time>2020-09-27T15:39:27+00:00</time> |  | ||||||
|                </trkpt> |  | ||||||
|              </trkseg> |  | ||||||
|            </trk> |  | ||||||
|          </gpx>",
 |  | ||||||
|     ); |  | ||||||
|     let file2 = wasm_bindgen::JsValue::from_str( |  | ||||||
|         "<?xml version='1.0' encoding='utf-8'?>
 |  | ||||||
|          <gpx version='1.0' encoding='UTF-8'> |  | ||||||
|            <trk> |  | ||||||
|              <name>file2 tracks</name> |  | ||||||
|              <type>1</type> |  | ||||||
|              <trkseg> |  | ||||||
|                <trkpt lat='35.339854' lon='-111.737165'> |  | ||||||
|                  <ele>2556.8</ele> |  | ||||||
|                  <time>2020-09-26T19:07:14+00:00</time> |  | ||||||
|                </trkpt> |  | ||||||
|              </trkseg> |  | ||||||
|            </trk> |  | ||||||
|          </gpx>",
 |  | ||||||
|     ); |  | ||||||
|     array.push(&file1); |  | ||||||
|     array.push(&file2); |  | ||||||
| 
 |  | ||||||
|     let exp = wasm_bindgen::JsValue::from_str( |  | ||||||
|         "<?xml version=\"1.0\" encoding=\"utf-8\"?>
 |  | ||||||
| <gpx version=\"1.1\" creator=\"https://github.com/georust/gpx\">
 |  | ||||||
|   <metadata> |  | ||||||
|     <name>merged</name> |  | ||||||
|     <author> |  | ||||||
|       <link href=\"https://gpx.thermokar.st\" />
 |  | ||||||
|     </author> |  | ||||||
|   </metadata> |  | ||||||
|   <trk> |  | ||||||
|     <name>file1 tracks</name> |  | ||||||
|     <type>1</type> |  | ||||||
|     <trkseg> |  | ||||||
|       <trkpt lat=\"35.466388\" lon=\"-111.640076\">
 |  | ||||||
|         <ele>2152.8</ele> |  | ||||||
|         <time>2020-09-27T15:39:27+00:00</time> |  | ||||||
|       </trkpt> |  | ||||||
|     </trkseg> |  | ||||||
|   </trk> |  | ||||||
|   <trk> |  | ||||||
|     <name>file2 tracks</name> |  | ||||||
|     <type>1</type> |  | ||||||
|     <trkseg> |  | ||||||
|       <trkpt lat=\"35.339854\" lon=\"-111.737165\">
 |  | ||||||
|         <ele>2556.8</ele> |  | ||||||
|         <time>2020-09-26T19:07:14+00:00</time> |  | ||||||
|       </trkpt> |  | ||||||
|     </trkseg> |  | ||||||
|   </trk> |  | ||||||
|   <rte /> |  | ||||||
| </gpx>",
 |  | ||||||
|     ); |  | ||||||
| 
 |  | ||||||
|     // act
 |  | ||||||
|     let obs = gpx_web_utils::merge(array); |  | ||||||
| 
 |  | ||||||
|     // assert
 |  | ||||||
|     assert_eq!(obs, exp); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // TODO: https://github.com/rustwasm/wasm-bindgen/issues/2286
 |  | ||||||
| // #[wasm_bindgen_test]
 |  | ||||||
| // #[should_panic]
 |  | ||||||
| // fn invalid_inputs() {
 |  | ||||||
| //     let array: js_sys::Array = js_sys::Array::new_with_length(10);
 |  | ||||||
| //     let obs = gpx_web_utils::merge(array);
 |  | ||||||
| // }
 |  | ||||||
							
								
								
									
										2
									
								
								www/.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								www/.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -1,2 +0,0 @@ | ||||||
| node_modules |  | ||||||
| dist |  | ||||||
							
								
								
									
										5
									
								
								www/bootstrap.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								www/bootstrap.js
									
										
									
									
										vendored
									
									
								
							|  | @ -1,5 +0,0 @@ | ||||||
| // A dependency graph that contains any wasm must all be imported
 |  | ||||||
| // asynchronously. This `bootstrap.js` file does the single async import, so
 |  | ||||||
| // that no one else needs to worry about it again.
 |  | ||||||
| import("./index.js") |  | ||||||
|   .catch(e => console.error("Error importing `index.js`:", e)); |  | ||||||
|  | @ -1,46 +0,0 @@ | ||||||
| <!DOCTYPE html> |  | ||||||
| <html> |  | ||||||
|   <head> |  | ||||||
|     <meta charset="utf-8"> |  | ||||||
|     <title>gpx.thermokar.st</title> |  | ||||||
|     <meta name="viewport" content="width=device-width, initial-scale=1"> |  | ||||||
|     <style> |  | ||||||
|       body { |  | ||||||
|         max-width: 35em; |  | ||||||
|         margin: 0 auto; |  | ||||||
|         line-height: 1.5; |  | ||||||
|         font-family: sans-serif; |  | ||||||
|         font-size: large; |  | ||||||
|       } |  | ||||||
|     </style> |  | ||||||
|   </head> |  | ||||||
|   <body> |  | ||||||
|     <h1> |  | ||||||
|       <a href="https://gpx.thermokar.st">gpx.thermokar.st</a> |  | ||||||
|     </h1> |  | ||||||
|     <noscript> |  | ||||||
|       <mark> |  | ||||||
|         This page contains webassembly and javascript content, please enable |  | ||||||
|         javascript in your browser. |  | ||||||
|       </mark> |  | ||||||
|     </noscript> |  | ||||||
|     <p> |  | ||||||
|       This client-side tool is for merging |  | ||||||
|       <a href="https://www.topografix.com/gpx.asp">GPX files</a>. |  | ||||||
|       Please note, this has only been tested on GPX files produced by |  | ||||||
|       <a href="https://www.garmin.com">Garmin</a> and |  | ||||||
|       <a href="https://www.strava.com">Strava</a> - your mileage may vary. |  | ||||||
|     </p> |  | ||||||
|     <form> |  | ||||||
|       <input id="gpxInput" type="file" multiple accept="text/gpx,.gpx"> |  | ||||||
|     </form> |  | ||||||
|     <hr> |  | ||||||
|     <p> |  | ||||||
|       <small> |  | ||||||
|          <a href="https://github.com/thermokarst/gpx-web-utils"> |  | ||||||
|           https://github.com/thermokarst/gpx-web-utils</a> |  | ||||||
|       </small> |  | ||||||
|     </p> |  | ||||||
|     <script src="./bootstrap.js"></script> |  | ||||||
|   </body> |  | ||||||
| </html> |  | ||||||
							
								
								
									
										37
									
								
								www/index.js
									
										
									
									
									
								
							
							
						
						
									
										37
									
								
								www/index.js
									
										
									
									
									
								
							|  | @ -1,37 +0,0 @@ | ||||||
| import * as gpx from "gpx-web-utils"; |  | ||||||
| 
 |  | ||||||
| const inputElement = document.getElementById("gpxInput"); |  | ||||||
| const loadingElement = document.createElement("span"); |  | ||||||
| 
 |  | ||||||
| loadingElement.innerHTML = "<strong>processing...</strong>"; |  | ||||||
| inputElement.value = ""; |  | ||||||
| inputElement.addEventListener("change", readFiles, false); |  | ||||||
| 
 |  | ||||||
| function readFiles() { |  | ||||||
|   if (inputElement.files.length < 2) { alert("open two or more files"); return; } |  | ||||||
| 
 |  | ||||||
|   inputElement.replaceWith(loadingElement); |  | ||||||
|   const files = Array.from(inputElement.files); |  | ||||||
|   const promises = files.map(f => f.text()); |  | ||||||
| 
 |  | ||||||
|   Promise.all(promises).then(gpxes => { |  | ||||||
|     try { |  | ||||||
|       const merged = gpx.merge(gpxes); |  | ||||||
|       writeOutput(merged); |  | ||||||
|     } catch { |  | ||||||
|       alert("there was a problem, please check the console."); |  | ||||||
|     } finally { |  | ||||||
|       inputElement.value = ""; |  | ||||||
|       loadingElement.replaceWith(inputElement); |  | ||||||
|     } |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function writeOutput(file) { |  | ||||||
|     const blob = new Blob([file], {type: "text/gpx"}); |  | ||||||
|     const anchorElement = document.createElement("a"); |  | ||||||
|     anchorElement.href = URL.createObjectURL(blob); |  | ||||||
|     anchorElement.download = "merged.gpx"; |  | ||||||
|     anchorElement.click(); |  | ||||||
|     URL.revokeObjectURL(anchorElement.href); |  | ||||||
| } |  | ||||||
							
								
								
									
										5842
									
								
								www/package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										5842
									
								
								www/package-lock.json
									
										
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -1,35 +0,0 @@ | ||||||
| { |  | ||||||
|   "name": "gpx-web-utils", |  | ||||||
|   "version": "0.0.1", |  | ||||||
|   "description": "just some gpx-related tools that i want to use.", |  | ||||||
|   "main": "index.js", |  | ||||||
|   "scripts": { |  | ||||||
|     "build": "webpack --config webpack.config.js", |  | ||||||
|     "start": "webpack-dev-server" |  | ||||||
|   }, |  | ||||||
|   "repository": { |  | ||||||
|     "type": "git", |  | ||||||
|     "url": "git+https://github.com/thermokarst/gpx-web-utils.git" |  | ||||||
|   }, |  | ||||||
|   "keywords": [ |  | ||||||
|     "webassembly", |  | ||||||
|     "wasm", |  | ||||||
|     "rust", |  | ||||||
|     "webpack" |  | ||||||
|   ], |  | ||||||
|   "author": "Matthew Ryan Dillon <matthewrdillon@gmail.com>", |  | ||||||
|   "license": "MIT", |  | ||||||
|   "bugs": { |  | ||||||
|     "url": "https://github.com/thermokarst/gpx-web-utils/issues" |  | ||||||
|   }, |  | ||||||
|   "homepage": "https://github.com/thermokarst/gpx-web-util#readme", |  | ||||||
|   "dependencies": { |  | ||||||
|     "gpx-web-utils": "file:../pkg" |  | ||||||
|   }, |  | ||||||
|   "devDependencies": { |  | ||||||
|     "webpack": "^4.29.3", |  | ||||||
|     "webpack-cli": "^3.1.0", |  | ||||||
|     "webpack-dev-server": "^3.1.5", |  | ||||||
|     "copy-webpack-plugin": "^5.0.0" |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  | @ -1,14 +0,0 @@ | ||||||
| const CopyWebpackPlugin = require("copy-webpack-plugin"); |  | ||||||
| const path = require('path'); |  | ||||||
| 
 |  | ||||||
| module.exports = { |  | ||||||
|   entry: "./bootstrap.js", |  | ||||||
|   output: { |  | ||||||
|     path: path.resolve(__dirname, "dist"), |  | ||||||
|     filename: "bootstrap.js", |  | ||||||
|   }, |  | ||||||
|   mode: "development", |  | ||||||
|   plugins: [ |  | ||||||
|     new CopyWebpackPlugin(['index.html']) |  | ||||||
|   ], |  | ||||||
| }; |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue