@@ -61,8 +61,8 @@ import {
6161 forEach ,
6262 keys ,
6363 lensPath ,
64+ mergeRight ,
6465 set ,
65- symmetricDifference ,
6666 type ,
6767} from 'ramda' ;
6868import { createAction } from 'redux-actions' ;
@@ -276,9 +276,8 @@ const getTransform = (element, propName, propPart) =>
276276 ? element . persistenceTransforms [ propName ] [ propPart ]
277277 : noopTransform ;
278278
279- const getNewValKey = ( id , persistedProp ) => id + '.' + persistedProp ;
280- const getOriginalValKey = newValKey => newValKey + '.orig' ;
281- const getPersistIdKey = newValKey => newValKey + '.id' ;
279+ const getValsKey = ( id , persistedProp , persistence ) =>
280+ `${ id } .${ persistedProp } .${ JSON . stringify ( persistence ) } ` ;
282281
283282const getProps = layout => {
284283 const { props} = layout ;
@@ -322,43 +321,27 @@ export function recordUiEdit(layout, newProps, dispatch) {
322321 const storage = getStore ( persistence_type , dispatch ) ;
323322 const { extract} = getTransform ( element , propName , propPart ) ;
324323
325- const newValKey = getNewValKey ( id , persistedProp ) ;
326- const persistIdKey = getPersistIdKey ( newValKey ) ;
327- const previousVal = extract ( props [ propName ] ) ;
324+ const valsKey = getValsKey ( id , persistedProp , persistence ) ;
325+ let originalVal = extract ( props [ propName ] ) ;
328326 const newVal = extract ( newProps [ propName ] ) ;
329327
330328 // mainly for nested props with multiple persisted parts, it's
331329 // possible to have the same value as before - should not store
332330 // in this case.
333- if ( previousVal !== newVal ) {
334- if (
335- ! storage . hasItem ( newValKey ) ||
336- storage . getItem ( persistIdKey ) !== persistence
337- ) {
338- storage . setItem (
339- getOriginalValKey ( newValKey ) ,
340- previousVal ,
341- dispatch
342- ) ;
343- storage . setItem ( persistIdKey , persistence , dispatch ) ;
331+ if ( originalVal !== newVal ) {
332+ if ( storage . hasItem ( valsKey ) ) {
333+ originalVal = storage . getItem ( valsKey ) [ 1 ] ;
344334 }
345- storage . setItem ( newValKey , newVal , dispatch ) ;
335+ const vals =
336+ originalVal === undefined
337+ ? [ newVal ]
338+ : [ newVal , originalVal ] ;
339+ storage . setItem ( valsKey , vals ) ;
346340 }
347341 }
348342 } , persisted_props ) ;
349343}
350344
351- function clearUIEdit ( id , persistence_type , persistedProp , dispatch ) {
352- const storage = getStore ( persistence_type , dispatch ) ;
353- const newValKey = getNewValKey ( id , persistedProp ) ;
354-
355- if ( storage . hasItem ( newValKey ) ) {
356- storage . removeItem ( newValKey ) ;
357- storage . removeItem ( getOriginalValKey ( newValKey ) ) ;
358- storage . removeItem ( getPersistIdKey ( newValKey ) ) ;
359- }
360- }
361-
362345/*
363346 * Used for entire layouts (on load) or partial layouts (from children
364347 * callbacks) to apply previously-stored UI edits to components
@@ -371,6 +354,28 @@ export function applyPersistence(layout, dispatch) {
371354 return persistenceMods ( layout , layout , [ ] , dispatch ) ;
372355}
373356
357+ const UNDO = true ;
358+ function modProp ( key , storage , element , props , persistedProp , update , undo ) {
359+ if ( storage . hasItem ( key ) ) {
360+ const [ newVal , originalVal ] = storage . getItem ( key ) ;
361+ const fromVal = undo ? newVal : originalVal ;
362+ const toVal = undo ? originalVal : newVal ;
363+ const [ propName , propPart ] = persistedProp . split ( '.' ) ;
364+ const transform = getTransform ( element , propName , propPart ) ;
365+
366+ if ( equals ( fromVal , transform . extract ( props [ propName ] ) ) ) {
367+ update [ propName ] = transform . apply (
368+ toVal ,
369+ propName in update ? update [ propName ] : props [ propName ]
370+ ) ;
371+ } else {
372+ // clear this saved edit - we've started with the wrong
373+ // value for this persistence ID
374+ storage . removeItem ( key ) ;
375+ }
376+ }
377+ }
378+
374379function persistenceMods ( layout , component , path , dispatch ) {
375380 const {
376381 id,
@@ -385,31 +390,18 @@ function persistenceMods(layout, component, path, dispatch) {
385390 if ( persistence ) {
386391 const storage = getStore ( persistence_type , dispatch ) ;
387392 const update = { } ;
388- forEach ( persistedProp => {
389- const [ propName , propPart ] = persistedProp . split ( '.' ) ;
390- const newValKey = getNewValKey ( id , persistedProp ) ;
391- const storedPersistID = storage . getItem ( getPersistIdKey ( newValKey ) ) ;
392- const transform = getTransform ( element , propName , propPart ) ;
393-
394- if ( storedPersistID ) {
395- if (
396- storedPersistID === persistence &&
397- equals (
398- storage . getItem ( getOriginalValKey ( newValKey ) ) ,
399- transform . extract ( props [ propName ] )
400- )
401- ) {
402- // To handle multiple nested props, apply each stored value
403- // in turn; then at the end we'll push these into the layout
404- update [ propName ] = transform . apply (
405- storage . getItem ( newValKey ) ,
406- propName in update ? update [ propName ] : props [ propName ]
407- ) ;
408- } else {
409- clearUIEdit ( id , persistence_type , persistedProp , dispatch ) ;
410- }
411- }
412- } , persisted_props ) ;
393+ forEach (
394+ persistedProp =>
395+ modProp (
396+ getValsKey ( id , persistedProp , persistence ) ,
397+ storage ,
398+ element ,
399+ props ,
400+ persistedProp ,
401+ update
402+ ) ,
403+ persisted_props
404+ ) ;
413405
414406 for ( const propName in update ) {
415407 layoutOut = set (
@@ -452,51 +444,85 @@ function persistenceMods(layout, component, path, dispatch) {
452444export function prunePersistence ( layout , newProps , dispatch ) {
453445 const {
454446 id,
447+ props,
455448 persistence,
456449 persisted_props,
457450 persistence_type,
458451 element,
459452 } = getProps ( layout ) ;
460- if ( ! persistence ) {
461- return ;
462- }
463453
464- // first look for conditions that clear the persistence store entirely
465- if (
466- ( 'persistence' in newProps && newProps . persistence !== persistence ) ||
467- ( 'persistence_type' in newProps &&
468- newProps . persistence_type !== persistence_type )
469- ) {
470- getStore ( persistence_type , dispatch ) . clear ( id ) ;
471- return ;
454+ const getFinal = ( propName , prevVal ) =>
455+ propName in newProps ? newProps [ propName ] : prevVal ;
456+ const finalPersistence = getFinal ( 'persistence' , persistence ) ;
457+
458+ if ( ! persistence && ! finalPersistence ) {
459+ return newProps ;
472460 }
473461
474- // if the persisted props list itself changed, clear any props not
475- // present in both the new and old
476- if ( 'persisted_props' in newProps ) {
462+ const finalPersistenceType = getFinal ( 'persistence_type' , persistence_type ) ;
463+ const finalPersistedProps = getFinal ( 'persisted_props' , persisted_props ) ;
464+ const persistenceChanged =
465+ finalPersistence !== persistence ||
466+ finalPersistenceType !== persistence_type ||
467+ finalPersistedProps !== persisted_props ;
468+
469+ const notInNewProps = persistedProp =>
470+ ! ( persistedProp . split ( '.' ) [ 0 ] in newProps ) ;
471+
472+ const update = { } ;
473+
474+ if ( persistenceChanged && persistence ) {
475+ // clear previously-applied persistence
476+ const storage = getStore ( persistence_type , dispatch ) ;
477477 forEach (
478478 persistedProp =>
479- clearUIEdit ( id , persistence_type , persistedProp , dispatch ) ,
480- symmetricDifference ( persisted_props , newProps . persisted_props )
479+ modProp (
480+ getValsKey ( id , persistedProp , persistence ) ,
481+ storage ,
482+ element ,
483+ props ,
484+ persistedProp ,
485+ update ,
486+ UNDO
487+ ) ,
488+ filter ( notInNewProps , persisted_props )
481489 ) ;
482490 }
483491
484- // now the main point - clear any edit associated with a prop that changed
485- // note that this is independent of the new prop value.
486- const transforms = element . persistenceTransforms || { } ;
487- for ( const propName in newProps ) {
488- const propTransforms = transforms [ propName ] ;
489- if ( propTransforms ) {
490- for ( const propPart in propTransforms ) {
491- clearUIEdit (
492- id ,
493- persistence_type ,
494- `${ propName } .${ propPart } ` ,
495- dispatch
496- ) ;
492+ if ( finalPersistence ) {
493+ const finalStorage = getStore ( finalPersistenceType , dispatch ) ;
494+
495+ if ( persistenceChanged ) {
496+ // apply new persistence
497+ forEach (
498+ persistedProp =>
499+ modProp (
500+ getValsKey ( id , persistedProp , persistence ) ,
501+ finalStorage ,
502+ element ,
503+ props ,
504+ persistedProp ,
505+ update
506+ ) ,
507+ filter ( notInNewProps , finalPersistedProps )
508+ ) ;
509+ }
510+
511+ // now the main point - clear any edit of a prop that changed
512+ // note that this is independent of the new prop value.
513+ const transforms = element . persistenceTransforms || { } ;
514+ for ( const propName in newProps ) {
515+ const propTransforms = transforms [ propName ] ;
516+ if ( propTransforms ) {
517+ for ( const propPart in propTransforms ) {
518+ finalStorage . removeItem (
519+ getValsKey ( id , `${ propName } .${ propPart } ` , persistence )
520+ ) ;
521+ }
522+ } else {
523+ finalStorage . removeItem ( getValsKey ( id , propName , persistence ) ) ;
497524 }
498- } else {
499- clearUIEdit ( id , persistence_type , propName , dispatch ) ;
500525 }
501526 }
527+ return persistenceChanged ? mergeRight ( newProps , update ) : newProps ;
502528}
0 commit comments