43
43
* }
44
44
* }
45
45
* - `extract` turns a prop value into a reduced value to store.
46
- * - `apply` puts an extracted value back into the prop.
46
+ * - `apply` puts an extracted value back into the prop. Make sure this creates
47
+ * a new object rather than mutating `proValue`, and that if there are
48
+ * multiple `piece` entries for one `propName`, their `apply` functions
49
+ * commute - which should not be an issue if they extract and apply
50
+ * non-intersecting parts of the full prop.
47
51
* You only need to define these for the props that need them.
48
52
* It's important that `extract` pulls out *only* the relevant pieces of the
49
53
* prop, because persistence is only maintained if the extracted value of the
52
56
*/
53
57
54
58
import {
55
- difference ,
56
59
equals ,
57
60
filter ,
58
61
forEach ,
59
62
keys ,
60
63
lensPath ,
61
64
set ,
65
+ symmetricDifference ,
62
66
type ,
63
67
} from 'ramda' ;
64
68
@@ -159,10 +163,12 @@ const noopTransform = {
159
163
apply : ( storedValue , _propValue ) => storedValue ,
160
164
} ;
161
165
162
- const getTransform = ( element , propName ) =>
163
- ( element . persistenceTransforms || { } ) [ propName ] || noopTransform ;
166
+ const getTransform = ( element , propName , propPart ) =>
167
+ propPart
168
+ ? element . persistenceTransforms [ propName ] [ propPart ]
169
+ : noopTransform ;
164
170
165
- const getNewValKey = ( id , propName ) => id + '.' + propName ;
171
+ const getNewValKey = ( id , persistedProp ) => id + '.' + persistedProp ;
166
172
const getOriginalValKey = newValKey => newValKey + '.orig' ;
167
173
const getPersistIdKey = newValKey => newValKey + '.id' ;
168
174
@@ -202,41 +208,37 @@ export function recordUiEdit(layout, newProps) {
202
208
return ;
203
209
}
204
210
205
- forEach ( propName => {
206
- // TODO: this only supports specifying top-level props to persist
207
- // DO we need nested specification?
208
- // This *does* support custom methods to save/restore these props,
209
- // so if we persist `columns` on a table, the component can specify
210
- // to only keep & restore the names, associating them with IDs.
211
- // It just wouldn't allow us to separately enable/disable persisting
212
- // something else inside columns.
211
+ forEach ( persistedProp => {
212
+ const [ propName , propPart ] = persistedProp . split ( '.' ) ;
213
213
if ( newProps [ propName ] ) {
214
214
const storage = stores [ persistence_type ] ;
215
- const transform = getTransform ( element , propName ) ;
215
+ const { extract } = getTransform ( element , propName , propPart ) ;
216
216
217
- const newValKey = getNewValKey ( id , propName ) ;
217
+ const newValKey = getNewValKey ( id , persistedProp ) ;
218
218
const persistIdKey = getPersistIdKey ( newValKey ) ;
219
- const setOriginalAndId = ( ) => {
220
- storage . setItem (
221
- getOriginalValKey ( newValKey ) ,
222
- transform . extract ( props [ propName ] )
223
- ) ;
224
- storage . setItem ( persistIdKey , persistence ) ;
225
- } ;
226
- if (
227
- ! storage . hasItem ( newValKey ) ||
228
- storage . getItem ( persistIdKey ) !== persistence
229
- ) {
230
- setOriginalAndId ( ) ;
219
+ const previousVal = extract ( props [ propName ] ) ;
220
+ const newVal = extract ( newProps [ propName ] ) ;
221
+
222
+ // mainly for nested props with multiple persisted parts, it's
223
+ // possible to have the same value as before - should not store
224
+ // in this case.
225
+ if ( previousVal !== newVal ) {
226
+ if (
227
+ ! storage . hasItem ( newValKey ) ||
228
+ storage . getItem ( persistIdKey ) !== persistence
229
+ ) {
230
+ storage . setItem ( getOriginalValKey ( newValKey ) , previousVal ) ;
231
+ storage . setItem ( persistIdKey , persistence ) ;
232
+ }
233
+ storage . setItem ( newValKey , newVal ) ;
231
234
}
232
- storage . setItem ( newValKey , transform . extract ( newProps [ propName ] ) ) ;
233
235
}
234
236
} , persisted_props ) ;
235
237
}
236
238
237
- function clearUIEdit ( id , persistence_type , propName ) {
239
+ function clearUIEdit ( id , persistence_type , persistedProp ) {
238
240
const storage = stores [ persistence_type ] ;
239
- const newValKey = getNewValKey ( id , propName ) ;
241
+ const newValKey = getNewValKey ( id , persistedProp ) ;
240
242
241
243
if ( storage . hasItem ( newValKey ) ) {
242
244
storage . removeItem ( newValKey ) ;
@@ -270,10 +272,13 @@ function persistenceMods(layout, component, path) {
270
272
let layoutOut = layout ;
271
273
if ( persistence ) {
272
274
const storage = stores [ persistence_type ] ;
273
- forEach ( propName => {
274
- const newValKey = getNewValKey ( id , propName ) ;
275
+ const update = { } ;
276
+ forEach ( persistedProp => {
277
+ const [ propName , propPart ] = persistedProp . split ( '.' ) ;
278
+ const newValKey = getNewValKey ( id , persistedProp ) ;
275
279
const storedPersistID = storage . getItem ( getPersistIdKey ( newValKey ) ) ;
276
- const transform = getTransform ( element , propName ) ;
280
+ const transform = getTransform ( element , propName , propPart ) ;
281
+
277
282
if ( storedPersistID ) {
278
283
if (
279
284
storedPersistID === persistence &&
@@ -282,19 +287,25 @@ function persistenceMods(layout, component, path) {
282
287
transform . extract ( props [ propName ] )
283
288
)
284
289
) {
285
- layoutOut = set (
286
- lensPath ( path . concat ( 'props' , propName ) ) ,
287
- transform . apply (
288
- storage . getItem ( newValKey ) ,
289
- props [ propName ]
290
- ) ,
291
- layoutOut
290
+ // To handle multiple nested props, apply each stored value
291
+ // in turn; then at the end we'll push these into the layout
292
+ update [ propName ] = transform . apply (
293
+ storage . getItem ( newValKey ) ,
294
+ propName in update ? update [ propName ] : props [ propName ]
292
295
) ;
293
296
} else {
294
- clearUIEdit ( id , persistence_type , propName ) ;
297
+ clearUIEdit ( id , persistence_type , persistedProp ) ;
295
298
}
296
299
}
297
300
} , persisted_props ) ;
301
+
302
+ for ( const propName in update ) {
303
+ layoutOut = set (
304
+ lensPath ( path . concat ( 'props' , propName ) ) ,
305
+ update [ propName ] ,
306
+ layoutOut
307
+ ) ;
308
+ }
298
309
}
299
310
300
311
// recurse inward
@@ -326,9 +337,13 @@ function persistenceMods(layout, component, path) {
326
337
* but not for props nested inside children
327
338
*/
328
339
export function prunePersistence ( layout , newProps ) {
329
- const { id, persistence, persisted_props, persistence_type} = getProps (
330
- layout
331
- ) ;
340
+ const {
341
+ id,
342
+ persistence,
343
+ persisted_props,
344
+ persistence_type,
345
+ element,
346
+ } = getProps ( layout ) ;
332
347
if ( ! persistence ) {
333
348
return ;
334
349
}
@@ -343,15 +358,26 @@ export function prunePersistence(layout, newProps) {
343
358
return ;
344
359
}
345
360
361
+ // if the persisted props list itself changed, clear any props not
362
+ // present in both the new and old
346
363
if ( 'persisted_props' in newProps ) {
347
364
forEach (
348
- prevPropName => clearUIEdit ( id , persistence_type , prevPropName ) ,
349
- difference ( persisted_props , newProps . persisted_props )
365
+ persistedProp => clearUIEdit ( id , persistence_type , persistedProp ) ,
366
+ symmetricDifference ( persisted_props , newProps . persisted_props )
350
367
) ;
351
368
}
352
369
353
- forEach (
354
- propName => clearUIEdit ( id , persistence_type , propName ) ,
355
- difference ( keys ( newProps ) , persisted_props )
356
- ) ;
370
+ // now the main point - clear any edit associated with a prop that changed
371
+ // note that this is independent of the new prop value.
372
+ const transforms = element . persistenceTransforms || { } ;
373
+ for ( const propName in newProps ) {
374
+ const propTransforms = transforms [ propName ] ;
375
+ if ( propTransforms ) {
376
+ for ( const propPart in propTransforms ) {
377
+ clearUIEdit ( id , persistence_type , `${ propName } .${ propPart } ` ) ;
378
+ }
379
+ } else {
380
+ clearUIEdit ( id , persistence_type , propName ) ;
381
+ }
382
+ }
357
383
}
0 commit comments