diff --git a/src/App.vue b/src/App.vue index d1d5310..84e6c5e 100644 --- a/src/App.vue +++ b/src/App.vue @@ -39,8 +39,7 @@ export default defineComponent({ }, setup() { - const initialUrl = window.location.hash.replace('#', ''), - store = useStore(), + const store = useStore(), updateInterval = computed(() => store.state.configuration.updateInterval), title = computed(() => store.state.configuration.title), currentUrl = computed(() => store.getters.url), @@ -85,15 +84,10 @@ export default defineComponent({ }, parseUrl = () => { - if(!initialUrl) { - return; - } + const parsedUrl = Util.parseUrl(); - try { - const result = Util.parseMapHash(initialUrl); - store.commit(MutationTypes.SET_PARSED_URL, result); - } catch(e) { - console.warn('Ignoring invalid url ' + e); + if(parsedUrl) { + store.commit(MutationTypes.SET_PARSED_URL, parsedUrl); } }; diff --git a/src/dynmap.d.ts b/src/dynmap.d.ts index b9dc712..0604cec 100644 --- a/src/dynmap.d.ts +++ b/src/dynmap.d.ts @@ -293,6 +293,7 @@ interface DynmapParsedUrl { map?: string; location?: Coordinate; zoom?: number; + legacy: boolean; } interface DynmapChat { diff --git a/src/util.ts b/src/util.ts index ca4fe86..2d65c2c 100644 --- a/src/util.ts +++ b/src/util.ts @@ -76,24 +76,39 @@ export default { }; }, + parseUrl() { + const query = new URLSearchParams(window.location.search), + hash = window.location.hash.replace('#', ''); + + if(hash) { + try { + return this.parseMapHash(hash); + } catch (e) { + console.warn('Ignoring invalid url ' + e); + } + } + + try { + return this.parseMapSearchParams(query); + } catch(e) { + console.warn('Ignoring invalid legacy url ' + e); + } + + return null; + }, + parseMapHash(hash: string) { const parts = hash.replace('#', '').split(';'); - if(parts.length < 3) { - throw new TypeError('Not enough parts'); - } + const world = parts[0] || undefined, + map = parts[1] || undefined, + location = (parts[2] || '').split(',') + .map(item => parseFloat(item)) + .filter(item => !isNaN(item) && isFinite(item)), + zoom = typeof parts[3] !== 'undefined' ? parseInt(parts[3]) : undefined; - const world = parts[0], - map = parts[1], - location = parts[2].split(',').map(item => parseFloat(item)), - zoom = parts[3] ? parseInt(parts[3]) : undefined; - - if(location.length !== 3) { - throw new TypeError('Location should contain exactly 3 numbers'); - } - - if(location.filter(item => isNaN(item) || !isFinite(item)).length) { - throw new TypeError('Invalid value in location'); + if(location.length && location.length !== 3) { + throw new TypeError('Location should contain exactly 3 valid numbers'); } if(typeof zoom !== 'undefined' && (isNaN(zoom) || zoom < 0 || !isFinite(zoom))) { @@ -103,12 +118,44 @@ export default { return { world, map, - location: { + location: location.length ? { x: location[0], y: location[1], z: location[2], - }, + } : undefined, zoom, + legacy: false, + } + }, + + parseMapSearchParams(query: URLSearchParams) { + const world = query.get('worldname') || undefined, + map = query.get('mapname') || undefined, + location = [ + query.get('x') || '', + query.get('y') || '', + query.get('z') || '' + ].map(item => parseFloat(item)).filter(item => !isNaN(item) && isFinite(item)), + zoom = query.has('zoom') ? parseInt(query.get('zoom') as string) : undefined; + + if(location.length && location.length !== 3) { + throw new TypeError('Location should contain exactly 3 valid numbers'); + } + + if(typeof zoom !== 'undefined' && (isNaN(zoom) || zoom < 0 || !isFinite(zoom))) { + throw new TypeError('Invalid value for zoom'); + } + + return { + world, + map, + location: location.length ? { + x: location[0], + y: location[1], + z: location[2], + } : undefined, + zoom, + legacy: true, } } } \ No newline at end of file