@@ -72,6 +72,11 @@ import {
7272export interface IComponent extends ExtractMethods < Component > { }
7373export interface SetAttrOptions extends SetOptions , UpdateStyleOptions , DataWatchersOptions { }
7474export interface ComponentSetOptions extends SetOptions , DataWatchersOptions { }
75+ export interface CheckIdOptions {
76+ keepIds ?: string [ ] ;
77+ idMap ?: PrevToNewIdMap ;
78+ updatedIds ?: Record < string , ComponentDefinitionDefined [ ] > ;
79+ }
7580
7681const escapeRegExp = ( str : string ) => {
7782 return str . replace ( / [ | \\ { } ( ) [ \] ^ $ + * ? . ] / g, '\\$&' ) ;
@@ -316,7 +321,7 @@ export default class Component extends StyleableModel<ComponentProperties> {
316321 } ;
317322 const attrs = this . dataResolverWatchers . getValueOrResolver ( 'attributes' , defaultAttrs ) ;
318323 this . setAttributes ( attrs ) ;
319- this . ccid = Component . createId ( this , opt ) ;
324+ this . ccid = Component . createId ( this , opt as any ) ;
320325 this . preInit ( ) ;
321326 this . initClasses ( ) ;
322327 this . initComponents ( ) ;
@@ -2062,43 +2067,77 @@ export default class Component extends StyleableModel<ComponentProperties> {
20622067
20632068 static ensureInList ( model : Component ) {
20642069 const list = Component . getList ( model ) ;
2065- const id = model . getId ( ) ;
2070+ const propId = model . id as string | undefined ;
2071+ const id = propId || model . getId ( ) ;
20662072 const current = list [ id ] ;
20672073
20682074 if ( ! current ) {
2069- // Insert in list
20702075 list [ id ] = model ;
20712076 } else if ( current !== model ) {
2072- // Create new ID
2077+ const keepIdsCrossPages = model . em ?. Components . config . keepAttributeIdsCrossPages ;
2078+ const currentPage = current . page ;
2079+ const modelPage = model . page ;
2080+ const samePage = ! ! currentPage && ! ! modelPage && currentPage === modelPage ;
20732081 const nextId = Component . getIncrementId ( id , list ) ;
2074- model . setId ( nextId ) ;
2082+
2083+ if ( samePage || ! keepIdsCrossPages ) {
2084+ model . setId ( nextId ) ;
2085+ } else {
2086+ model . set ( { id : nextId } ) ;
2087+ }
2088+
20752089 list [ nextId ] = model ;
20762090 }
20772091
20782092 model . components ( ) . forEach ( ( i ) => Component . ensureInList ( i ) ) ;
20792093 }
20802094
2081- static createId ( model : Component , opts : any = { } ) {
2095+ static createId ( model : Component , opts : CheckIdOptions = { } ) {
20822096 const list = Component . getList ( model ) ;
2097+ const keepIdsCrossPages = model . em ?. Components . config . keepAttributeIdsCrossPages ;
20832098 const { idMap = { } } = opts ;
2084- let { id } = model . get ( 'attributes' ) ! ;
2085- let nextId ;
2099+ const attrs = model . get ( 'attributes' ) || { } ;
2100+ const attrId = attrs . id as string | undefined ;
2101+ const propId = model . id as string | undefined ;
2102+ const currentId = propId ?? attrId ;
2103+ let nextId : string ;
2104+
2105+ if ( propId ) {
2106+ nextId = Component . getIncrementId ( propId , list , opts ) ;
2107+ if ( nextId !== propId ) {
2108+ model . set ( { id : nextId } ) ;
2109+ }
2110+ } else if ( attrId ) {
2111+ const existing = list [ attrId ] as Component | undefined ;
20862112
2087- if ( id ) {
2088- nextId = Component . getIncrementId ( id , list , opts ) ;
2089- model . setId ( nextId ) ;
2090- if ( id !== nextId ) idMap [ id ] = nextId ;
2113+ if ( ! existing || existing === model ) {
2114+ nextId = attrId ;
2115+ } else {
2116+ const existingPage = existing . page ;
2117+ const newPage = model . page ;
2118+ const samePage = ! ! existingPage && ! ! newPage && existingPage === newPage ;
2119+ nextId = Component . getIncrementId ( attrId , list , opts ) ;
2120+
2121+ if ( samePage || ! keepIdsCrossPages ) {
2122+ model . setId ( nextId ) ;
2123+ } else {
2124+ model . set ( { id : nextId } ) ;
2125+ }
2126+ }
20912127 } else {
20922128 nextId = Component . getNewId ( list ) ;
20932129 }
20942130
2131+ if ( ! ! currentId && currentId !== nextId ) {
2132+ idMap [ currentId ] = nextId ;
2133+ }
2134+
20952135 list [ nextId ] = model ;
20962136 return nextId ;
20972137 }
20982138
20992139 static getNewId ( list : ObjectAny ) {
21002140 const count = Object . keys ( list ) . length ;
2101- // Testing 1000000 components with `+ 2` returns 0 collisions
21022141 const ilen = count . toString ( ) . length + 2 ;
21032142 const uid = ( Math . random ( ) + 1.1 ) . toString ( 36 ) . slice ( - ilen ) ;
21042143 let newId = `i${ uid } ` ;
@@ -2126,20 +2165,14 @@ export default class Component extends StyleableModel<ComponentProperties> {
21262165 }
21272166
21282167 static getList ( model : Component ) {
2129- const { em } = model ;
2130- const dm = em ?. Components ;
2131- return dm ?. componentsById ?? { } ;
2168+ return model . em ?. Components ?. componentsById ?? { } ;
21322169 }
21332170
21342171 static checkId (
21352172 components : ComponentDefinitionDefined | ComponentDefinitionDefined [ ] ,
21362173 styles : CssRuleJSON [ ] = [ ] ,
21372174 list : ObjectAny = { } ,
2138- opts : {
2139- keepIds ?: string [ ] ;
2140- idMap ?: PrevToNewIdMap ;
2141- updatedIds ?: Record < string , ComponentDefinitionDefined [ ] > ;
2142- } = { } ,
2175+ opts : CheckIdOptions = { } ,
21432176 ) {
21442177 opts . updatedIds = opts . updatedIds || { } ;
21452178 const comps = isArray ( components ) ? components : [ components ] ;
0 commit comments