4343 * }
4444 * }
4545 * - `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.
4751 * You only need to define these for the props that need them.
4852 * It's important that `extract` pulls out *only* the relevant pieces of the
4953 * prop, because persistence is only maintained if the extracted value of the
5256 */
5357
5458import {
55- difference ,
5659 equals ,
5760 filter ,
5861 forEach ,
5962 keys ,
6063 lensPath ,
6164 set ,
65+ symmetricDifference ,
6266 type ,
6367} from 'ramda' ;
6468
@@ -159,10 +163,12 @@ const noopTransform = {
159163 apply : ( storedValue , _propValue ) => storedValue ,
160164} ;
161165
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 ;
164170
165- const getNewValKey = ( id , propName ) => id + '.' + propName ;
171+ const getNewValKey = ( id , persistedProp ) => id + '.' + persistedProp ;
166172const getOriginalValKey = newValKey => newValKey + '.orig' ;
167173const getPersistIdKey = newValKey => newValKey + '.id' ;
168174
@@ -202,41 +208,37 @@ export function recordUiEdit(layout, newProps) {
202208 return ;
203209 }
204210
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 ( '.' ) ;
213213 if ( newProps [ propName ] ) {
214214 const storage = stores [ persistence_type ] ;
215- const transform = getTransform ( element , propName ) ;
215+ const { extract } = getTransform ( element , propName , propPart ) ;
216216
217- const newValKey = getNewValKey ( id , propName ) ;
217+ const newValKey = getNewValKey ( id , persistedProp ) ;
218218 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 ) ;
231234 }
232- storage . setItem ( newValKey , transform . extract ( newProps [ propName ] ) ) ;
233235 }
234236 } , persisted_props ) ;
235237}
236238
237- function clearUIEdit ( id , persistence_type , propName ) {
239+ function clearUIEdit ( id , persistence_type , persistedProp ) {
238240 const storage = stores [ persistence_type ] ;
239- const newValKey = getNewValKey ( id , propName ) ;
241+ const newValKey = getNewValKey ( id , persistedProp ) ;
240242
241243 if ( storage . hasItem ( newValKey ) ) {
242244 storage . removeItem ( newValKey ) ;
@@ -270,10 +272,13 @@ function persistenceMods(layout, component, path) {
270272 let layoutOut = layout ;
271273 if ( persistence ) {
272274 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 ) ;
275279 const storedPersistID = storage . getItem ( getPersistIdKey ( newValKey ) ) ;
276- const transform = getTransform ( element , propName ) ;
280+ const transform = getTransform ( element , propName , propPart ) ;
281+
277282 if ( storedPersistID ) {
278283 if (
279284 storedPersistID === persistence &&
@@ -282,19 +287,25 @@ function persistenceMods(layout, component, path) {
282287 transform . extract ( props [ propName ] )
283288 )
284289 ) {
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 ]
292295 ) ;
293296 } else {
294- clearUIEdit ( id , persistence_type , propName ) ;
297+ clearUIEdit ( id , persistence_type , persistedProp ) ;
295298 }
296299 }
297300 } , 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+ }
298309 }
299310
300311 // recurse inward
@@ -326,9 +337,13 @@ function persistenceMods(layout, component, path) {
326337 * but not for props nested inside children
327338 */
328339export 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 ) ;
332347 if ( ! persistence ) {
333348 return ;
334349 }
@@ -343,15 +358,26 @@ export function prunePersistence(layout, newProps) {
343358 return ;
344359 }
345360
361+ // if the persisted props list itself changed, clear any props not
362+ // present in both the new and old
346363 if ( 'persisted_props' in newProps ) {
347364 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 )
350367 ) ;
351368 }
352369
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+ }
357383}
0 commit comments