11import isEqual from 'lodash.isequal' ;
22import { round } from './math' ;
33import { linkLocations as linkLocationsStore } from './stores' ;
4+ import { createBranchUrl } from './branch-utils' ;
45
56let linkedLocations ;
67linkLocationsStore . subscribe ( value => ( linkedLocations = value ) ) ;
78
89// Keys that should be encoded/decoded as arrays
9- const jsonKeys = [ 'maps' , ' locations'] ;
10+ const jsonKeys = [ 'locations' ] ;
1011
1112// Keys that should be encoded/decoded as boolean values
1213const booleanKeys = [ 'showCollisions' , 'showBoundaries' , 'showDiff' ] ;
@@ -31,6 +32,72 @@ function toQueryString(obj) {
3132 return qs ;
3233}
3334
35+ const findStylePreset = ( id , stylePresets ) => {
36+ const flatPresets = [
37+ ...stylePresets . filter ( p => p . type !== 'sublist' ) ,
38+ ...stylePresets . filter ( p => p . type === 'sublist' ) . flatMap ( p => p . presets ) ,
39+ ] ;
40+
41+ return flatPresets . find ( preset => preset . id === id ) ;
42+ } ;
43+
44+ const findBranchPattern = ( map , branchPatterns ) => {
45+ const branchPattern = branchPatterns . find ( p => p . id === map . branchId ) ;
46+ if ( ! branchPattern ) return null ;
47+ return {
48+ ...branchPattern ,
49+ url : createBranchUrl ( branchPattern . pattern , map . branch , map . branchStyle ) ,
50+ } ;
51+ } ;
52+
53+ const encodeMaps = ( maps , config ) => {
54+ const mapsToEncode = maps . map ( m => {
55+ let encodeMap = { id : m . id } ;
56+ let configMap ;
57+
58+ if ( m . branchId ) {
59+ configMap = findBranchPattern ( m , config ?. branchPatterns ?? [ ] ) ;
60+ encodeMap = {
61+ branchId : configMap . id ,
62+ branchStyle : m . branchStyle ,
63+ branch : m . branch ,
64+ } ;
65+ } else {
66+ configMap = findStylePreset ( m . id , config . stylePresets ) ;
67+ }
68+
69+ // If not set yet, must be a custom URL
70+ if ( ! configMap ) {
71+ return Object . fromEntries (
72+ Object . entries ( m ) . filter ( ( [ k ] ) => k !== 'style' )
73+ ) ;
74+ }
75+
76+ // Only renderer if not default
77+ if ( m . renderer !== configMap . renderer ) {
78+ encodeMap . renderer = m . renderer ;
79+ }
80+
81+ return encodeMap ;
82+ } ) ;
83+
84+ return JSON . stringify ( mapsToEncode ) ;
85+ } ;
86+
87+ const decodeMaps = ( str , config ) => {
88+ const maps = JSON . parse ( str ) ;
89+ const decodedMaps = maps
90+ . map ( m => {
91+ let configMap = findStylePreset ( m . id , config ?. stylePresets ?? [ ] ) ;
92+ if ( ! configMap )
93+ configMap = findBranchPattern ( m , config ?. branchPatterns ?? [ ] ) ;
94+ if ( ! configMap ) return m ;
95+ return { ...configMap , ...m } ;
96+ } )
97+ . filter ( v => v ) ;
98+ return decodedMaps ;
99+ } ;
100+
34101const encodeMapParams = ( { zoom, center, pitch, bearing } ) => {
35102 return [
36103 round ( zoom , 2 ) ,
@@ -71,37 +138,33 @@ function fromQueryString(qs) {
71138 return params ;
72139}
73140
74- // Remove values set to null
141+ // Remove values set to null / false
75142const cleanSettings = stateObj => {
76143 let nextState = Object . keys ( stateObj ) . reduce ( ( acc , k ) => {
77144 const value = stateObj [ k ] ;
145+ // Only include booleanKeys if not default
146+ if ( booleanKeys . includes ( k ) && ! value ) return acc ;
78147 if ( value !== null ) acc [ k ] = value ;
79148 return acc ;
80149 } , { } ) ;
81150 return nextState ;
82151} ;
83152
84- export const createHashString = mapSettings => {
85- let newMapSettings = JSON . parse ( JSON . stringify ( mapSettings ) ) ;
86- if ( newMapSettings . maps ?. length ?? 0 ) {
87- const newMaps = newMapSettings . maps ;
88-
89- // Remove map styles before hashing
90- newMapSettings . maps = newMaps . map ( m => {
91- delete m . style ;
92- return m ;
93- } ) ;
94- }
95-
153+ export const createHashString = ( mapSettings , config ) => {
96154 let nonMapSettings = Object . fromEntries (
97- Object . entries ( newMapSettings )
155+ Object . entries ( mapSettings )
98156 . filter ( ( [ k , v ] ) => ! mapLocationKeys . includes ( k ) && k !== 'locations' )
99- . map ( ( [ k , v ] ) => [ k , jsonKeys . includes ( k ) ? JSON . stringify ( v ) : v ] )
157+ . map ( ( [ k , v ] ) => {
158+ let encodedValue = v ;
159+ if ( k === 'maps' ) encodedValue = encodeMaps ( v , config ) ;
160+ else if ( jsonKeys . includes ( k ) ) encodedValue = JSON . stringify ( v ) ;
161+ return [ k , encodedValue ] ;
162+ } )
100163 ) ;
101164
102165 nonMapSettings = cleanSettings ( nonMapSettings ) ;
103166
104- const currentHash = readHash ( window . location . hash ) ;
167+ const currentHash = readHash ( window . location . hash , config ) ;
105168
106169 const requiresHistoryItem = Object . entries ( nonMapSettings ) . some ( kv => {
107170 let [ k , v ] = kv ;
@@ -120,13 +183,13 @@ export const createHashString = mapSettings => {
120183
121184 if ( linkedLocations ) {
122185 updatedSettings = {
123- map : encodeMapParams ( newMapSettings ) ,
186+ map : encodeMapParams ( mapSettings ) ,
124187 ...updatedSettings ,
125188 } ;
126189 } else {
127190 updatedSettings = {
128191 locations : JSON . stringify (
129- newMapSettings . locations . map ( location => encodeMapParams ( location ) )
192+ mapSettings . locations . map ( location => encodeMapParams ( location ) )
130193 ) ,
131194 ...updatedSettings ,
132195 } ;
@@ -137,21 +200,25 @@ export const createHashString = mapSettings => {
137200 return { nextHash, requiresHistoryItem } ;
138201} ;
139202
140- export function writeHash ( mapSettings ) {
141- const { nextHash, requiresHistoryItem } = createHashString ( mapSettings ) ;
203+ export function writeHash ( mapSettings , config ) {
204+ const { nextHash, requiresHistoryItem } = createHashString (
205+ mapSettings ,
206+ config
207+ ) ;
142208 if ( ! requiresHistoryItem ) {
143209 window . location . replace ( `${ window . location . pathname } #${ nextHash } ` ) ;
144210 } else {
145211 window . location . hash = nextHash ;
146212 }
147213}
148214
149- export function readHash ( qs ) {
215+ export function readHash ( qs , config ) {
150216 // Remove unset values, convert value as necessary
151217 let urlState = Object . fromEntries (
152218 Object . entries ( fromQueryString ( qs ) )
153219 . filter ( ( [ k , v ] ) => ! ! v )
154220 . map ( ( [ k , v ] ) => {
221+ if ( k === 'maps' ) return [ k , decodeMaps ( v , config ) ] ;
155222 if ( jsonKeys . includes ( k ) ) return [ k , JSON . parse ( v ) ] ;
156223 if ( booleanKeys . includes ( k ) ) return [ k , v === 'true' ] ;
157224 if ( numericKeys . includes ( k ) ) return [ k , + v || 0 ] ;
0 commit comments