Improve handing of append_to_world

- Always use the store map list for checking for/retrieving maps, to avoid the non-unique map name problem append_to_world otherwise causes
- Change LiveAtlasWorldDefinition maps property to Set as map keys were not unique if appended maps with the same names existed
- Add appended map to both original and appended world's map set. The appended world needs this to display the map in the UI, the original world needs this to avoid situations where LiveAtlas needs the "first" map of a world, and that world has 0 non-appended maps (i.e switching worlds when following, URL without a map name)
- Add an appendedWorld property to maps to indicate when a map has been appended. This is used by MapContextMenu to show the appended world's map list instead, and in WorldListItem to filter out maps appended to other worlds
- Use the map's world property instead of the world prop in the template for WorldListItem. This fixes tooltips and prevents duplicate IDs.

Fixes #345
This commit is contained in:
James Lyne 2022-02-04 21:58:07 +00:00
parent f7b774321b
commit e91f820322
9 changed files with 63 additions and 29 deletions

View File

@ -296,9 +296,8 @@ export default defineComponent({
} }
if(targetWorld && (targetWorld !== currentWorld) || (target.map && currentMap !== target.map)) { if(targetWorld && (targetWorld !== currentWorld) || (target.map && currentMap !== target.map)) {
const mapName = target.map && targetWorld!.maps.has(target.map) ? const map = store.state.maps.get(`${targetWorld.name}_${target.map}`),
targetWorld!.maps.get(target.map)!.name : mapName = map ? map.name : targetWorld.maps.values().next().value.name;
targetWorld!.maps.entries().next().value[1].name;
this.scheduledView = target; this.scheduledView = target;

View File

@ -15,14 +15,16 @@
--> -->
<template> <template>
<div class="world"> <div v-if="maps.length" class="world">
<span class="world__name" aria-hidden="true">{{ world.displayName }}</span> <span class="world__name" aria-hidden="true">{{ world.displayName }}</span>
<div class="world__maps menu"> <div class="world__maps menu">
<template v-for="[key, map] in world.maps" :key="`${world.name}_${key}`"> <template v-for="map in maps" :key="`${map.world.name}_${map.name}`">
<input :id="`${name}-${world.name}-${key}`" type="radio" :name="name" <input :id="`${name}-${map.world.name}-${map.name}`" type="radio" :name="name"
v-bind:value="[world.name,map.name]" v-model="currentMap" v-bind:value="[map.world.name,map.name]" v-model="currentMap"
:aria-labelledby="`${name}-${world.name}-${key}-label`"> :aria-labelledby="`${name}-${map.world.name}-${map.name}-label`">
<label :id="`${name}-${world.name}-${key}-label`" class="map" :for="`${name}-${world.name}-${key}`" :title="`${world.displayName} - ${map.displayName}`"> <label :id="`${name}-${map.world.name}-${map.name}-label`" class="map"
:for="`${name}-${map.world.name}-${map.name}`"
:title="`${map.world.displayName} - ${map.displayName}`">
<img v-if="map.hasCustomIcon()" :src="map.getIcon()" alt="" /> <img v-if="map.hasCustomIcon()" :src="map.getIcon()" alt="" />
<SvgIcon v-else :name="map.getIcon()"></SvgIcon> <SvgIcon v-else :name="map.getIcon()"></SvgIcon>
</label> </label>
@ -48,6 +50,7 @@ import "@/assets/icons/block_other.svg";
import "@/assets/icons/block_other_flat.svg"; import "@/assets/icons/block_other_flat.svg";
import "@/assets/icons/block_skylands.svg"; import "@/assets/icons/block_skylands.svg";
import {LiveAtlasWorldDefinition} from "@/index"; import {LiveAtlasWorldDefinition} from "@/index";
import LiveAtlasMapDefinition from "@/model/LiveAtlasMapDefinition";
export default defineComponent({ export default defineComponent({
name: 'WorldListItem', name: 'WorldListItem',
@ -63,8 +66,21 @@ export default defineComponent({
} }
}, },
setup() { setup(props) {
const store = useStore(), const store = useStore(),
maps = computed(() => {
const maps: LiveAtlasMapDefinition[] = [];
//Filter out maps appended to other worlds
props.world.maps.forEach(map => {
console.log(map.appendedWorld, props.world);
if(!map.appendedWorld || map.appendedWorld.name === props.world.name) {
maps.push(map);
}
});
return maps;
}),
currentMap = computed({ currentMap = computed({
get: () => store.state.currentMap ? [store.state.currentWorld!.name, store.state.currentMap.name] : undefined, get: () => store.state.currentMap ? [store.state.currentWorld!.name, store.state.currentMap.name] : undefined,
set: (value) => value && store.commit(MutationTypes.SET_CURRENT_MAP, { set: (value) => value && store.commit(MutationTypes.SET_CURRENT_MAP, {
@ -74,7 +90,8 @@ export default defineComponent({
}); });
return { return {
currentMap currentMap,
maps
} }
} }
}); });

View File

@ -35,7 +35,7 @@
<li role="none"> <li role="none">
<button type="button" role="menuitem" @click.prevent="pan">{{ messageCenterHere }}</button> <button type="button" role="menuitem" @click.prevent="pan">{{ messageCenterHere }}</button>
</li> </li>
<WorldListItem v-if="currentWorld && mapCount > 1" :world="currentWorld" name="context"></WorldListItem> <WorldListItem v-if="currentMap && mapCount > 1" :world="currentMap.appendedWorld || currentMap.world" name="context"></WorldListItem>
</ul> </ul>
</nav> </nav>
</template> </template>
@ -72,10 +72,17 @@ export default defineComponent({
menuElement = ref<HTMLInputElement | null>(null), menuElement = ref<HTMLInputElement | null>(null),
menuVisible = computed(() => !!event.value), menuVisible = computed(() => !!event.value),
currentWorld = computed(() => store.state.currentWorld),
currentMap = computed(() => store.state.currentMap), currentMap = computed(() => store.state.currentMap),
currentZoom = computed(() => store.state.currentZoom), currentZoom = computed(() => store.state.currentZoom),
mapCount = computed(() => currentWorld.value ? currentWorld.value.maps.size : 0), mapCount = computed(() => {
if(!currentMap.value) {
return 0;
}
//Use appendedWorld if present for map list
return currentMap.value?.appendedWorld ?
currentMap.value?.appendedWorld.maps.size : currentMap.value.world.maps.size;
}),
location = computed(() => { location = computed(() => {
if (!event.value || !currentMap.value) { if (!event.value || !currentMap.value) {
@ -221,7 +228,7 @@ export default defineComponent({
locationLabel, locationLabel,
locationCopy, locationCopy,
currentWorld, currentMap,
mapCount, mapCount,
style, style,

2
src/index.d.ts vendored
View File

@ -156,7 +156,7 @@ interface LiveAtlasWorldDefinition {
dimension: LiveAtlasDimension; dimension: LiveAtlasDimension;
center: Coordinate; center: Coordinate;
defaultZoom?: number; defaultZoom?: number;
maps: Map<string, LiveAtlasMapDefinition>; maps: Set<LiveAtlasMapDefinition>;
} }
interface LiveAtlasWorldState { interface LiveAtlasWorldState {

View File

@ -21,6 +21,7 @@ import {ImageFormat} from "dynmap";
export interface LiveAtlasMapDefinitionOptions { export interface LiveAtlasMapDefinitionOptions {
world: LiveAtlasWorldDefinition; world: LiveAtlasWorldDefinition;
appendedWorld?: LiveAtlasWorldDefinition; // append_to_world
name: string; name: string;
displayName?: string; displayName?: string;
icon?: string; icon?: string;
@ -39,6 +40,7 @@ export interface LiveAtlasMapDefinitionOptions {
export default class LiveAtlasMapDefinition { export default class LiveAtlasMapDefinition {
readonly world: LiveAtlasWorldDefinition; readonly world: LiveAtlasWorldDefinition;
readonly appendedWorld?: LiveAtlasWorldDefinition;
readonly name: string; readonly name: string;
readonly icon?: string; readonly icon?: string;
readonly displayName: string; readonly displayName: string;
@ -55,7 +57,8 @@ export default class LiveAtlasMapDefinition {
readonly tileUpdateInterval?: number; readonly tileUpdateInterval?: number;
constructor(options: LiveAtlasMapDefinitionOptions) { constructor(options: LiveAtlasMapDefinitionOptions) {
this.world = options.world; //Ignore append_to_world here otherwise things break this.world = options.world;
this.appendedWorld = options.appendedWorld; // append_to_world
this.name = options.name; this.name = options.name;
this.icon = options.icon || undefined; this.icon = options.icon || undefined;
this.displayName = options.displayName || ''; this.displayName = options.displayName || '';

View File

@ -160,7 +160,7 @@ export default class Pl3xmapMapProvider extends MapProvider {
dimension = 'end'; dimension = 'end';
} }
const maps: Map<string, LiveAtlasMapDefinition> = new Map(); const maps: Set<LiveAtlasMapDefinition> = new Set();
const w = { const w = {
name: world.name || '(Unnamed world)', name: world.name || '(Unnamed world)',
@ -172,7 +172,7 @@ export default class Pl3xmapMapProvider extends MapProvider {
maps, maps,
}; };
maps.set('flat', Object.freeze(new LiveAtlasMapDefinition({ maps.add(Object.freeze(new LiveAtlasMapDefinition({
world: w, world: w,
background: 'transparent', background: 'transparent',

View File

@ -112,21 +112,20 @@ export const actions: ActionTree<State, State> & Actions = {
} }
if(worldName) { if(worldName) {
const world = state.worlds.get(worldName) as LiveAtlasWorldDefinition;
// Use config default map if it exists // Use config default map if it exists
if(state.configuration.defaultMap && world.maps.has(state.configuration.defaultMap)) { if(state.configuration.defaultMap && state.maps.has(`${worldName}_${state.configuration.defaultMap}`)) {
mapName = state.configuration.defaultMap; mapName = state.configuration.defaultMap;
} }
// Prefer map from parsed url if present and it exists // Prefer map from parsed url if present and it exists
if(state.parsedUrl?.map && world.maps.has(state.parsedUrl.map)) { if(state.parsedUrl?.map && state.maps.has(`${worldName}_${state.parsedUrl.map}`)) {
mapName = state.parsedUrl.map; mapName = state.parsedUrl.map;
} }
// Use first map, if any, if neither of the above exist // Use first map, if any, if neither of the above exist
if(!mapName) { if(!mapName) {
mapName = world.maps.size ? world.maps.entries().next().value[1].name : undefined; const world = state.worlds.get(worldName) as LiveAtlasWorldDefinition;
mapName = world.maps.size ? world.maps.values().next().value.name : undefined;
} }
} }

View File

@ -169,7 +169,7 @@ export const mutations: MutationTree<State> & Mutations = {
worlds.forEach(world => { worlds.forEach(world => {
state.worlds.set(world.name, world); state.worlds.set(world.name, world);
world.maps.forEach(map => state.maps.set(`${world.name}_${map.name}`, map)); world.maps.forEach(map => state.maps.set(`${map.world.name}_${map.name}`, map));
}); });
//Update current world if a world with the same name still exists, otherwise clear //Update current world if a world with the same name still exists, otherwise clear

View File

@ -110,7 +110,7 @@ export function buildWorlds(response: Configuration): Array<LiveAtlasWorldDefini
y: world.center.y || 0, y: world.center.y || 0,
z: world.center.z || 0 z: world.center.z || 0
}, },
maps: new Map(), maps: new Set(),
}); });
}); });
@ -126,8 +126,11 @@ export function buildWorlds(response: Configuration): Array<LiveAtlasWorldDefini
return; return;
} }
assignedWorld.maps.set(map.name, Object.freeze(new LiveAtlasMapDefinition({ // Maps with append_to_world set are added both the original and target world's map set
world: actualWorld, //Ignore append_to_world here for Dynmap URL parity // The world property is always the original world, an additional appendedWorld property contains the target world
const mapDef = Object.freeze(new LiveAtlasMapDefinition({
world: actualWorld,
appendedWorld: actualWorld !== assignedWorld ? assignedWorld : undefined,
background: map.background || '#000000', background: map.background || '#000000',
backgroundDay: map.backgroundday || '#000000', backgroundDay: map.backgroundday || '#000000',
backgroundNight: map.backgroundnight || '#000000', backgroundNight: map.backgroundnight || '#000000',
@ -141,7 +144,13 @@ export function buildWorlds(response: Configuration): Array<LiveAtlasWorldDefini
worldToMap: map.worldtomap || undefined, worldToMap: map.worldtomap || undefined,
nativeZoomLevels: map.mapzoomout || 1, nativeZoomLevels: map.mapzoomout || 1,
extraZoomLevels: map.mapzoomin || 0 extraZoomLevels: map.mapzoomin || 0
}))); })) as LiveAtlasMapDefinition;
actualWorld.maps.add(mapDef);
if(actualWorld !== assignedWorld) {
assignedWorld.maps.add(mapDef);
}
}); });
}); });