@@ -45,9 +45,9 @@ export default class CustomElementRegistry {
4545
4646 /**
4747 * @private
48- * @type {!Array<string > }
48+ * @type {!Array<!CustomElementDefinition > }
4949 */
50- this . _unflushedLocalNames = [ ] ;
50+ this . _pendingDefinitions = [ ] ;
5151
5252 /**
5353 * @private
@@ -121,8 +121,7 @@ export default class CustomElementRegistry {
121121 } ;
122122
123123 this . _internals . setDefinition ( localName , definition ) ;
124-
125- this . _unflushedLocalNames . push ( localName ) ;
124+ this . _pendingDefinitions . push ( definition ) ;
126125
127126 // If we've already called the flush callback and it hasn't called back yet,
128127 // don't call it again.
@@ -137,12 +136,64 @@ export default class CustomElementRegistry {
137136 // happen if a flush callback keeps the function it is given and calls it
138137 // multiple times.
139138 if ( this . _flushPending === false ) return ;
140-
141139 this . _flushPending = false ;
142- this . _internals . patchAndUpgradeTree ( document ) ;
143140
144- while ( this . _unflushedLocalNames . length > 0 ) {
145- const localName = this . _unflushedLocalNames . shift ( ) ;
141+ const pendingDefinitions = this . _pendingDefinitions ;
142+
143+ /**
144+ * Unupgraded elements with definitions that were defined *before* the last
145+ * flush, in document order.
146+ * @type {!Array<!Element> }
147+ */
148+ const elementsWithStableDefinitions = [ ] ;
149+
150+ /**
151+ * A map from `localName`s of definitions that were defined *after* the last
152+ * flush to unupgraded elements matching that definition, in document order.
153+ * @type {!Map<string, !Array<!Element>> }
154+ */
155+ const elementsWithPendingDefinitions = new Map ( ) ;
156+ for ( let i = 0 ; i < pendingDefinitions . length ; i ++ ) {
157+ elementsWithPendingDefinitions . set ( pendingDefinitions [ i ] . localName , [ ] ) ;
158+ }
159+
160+ this . _internals . patchAndUpgradeTree ( document , {
161+ upgrade : element => {
162+ // Ignore the element if it has already upgraded or failed to upgrade.
163+ if ( element . __CE_state !== undefined ) return ;
164+
165+ const localName = element . localName ;
166+
167+ // If there is an applicable pending definition for the element, add the
168+ // element to the list of elements to be upgraded with that definition.
169+ const pendingElements = elementsWithPendingDefinitions . get ( localName ) ;
170+ if ( pendingElements ) {
171+ pendingElements . push ( element ) ;
172+ // If there is *any other* applicable definition for the element, add it
173+ // to the list of elements with stable definitions that need to be upgraded.
174+ } else if ( this . _internals . localNameToDefinition ( localName ) ) {
175+ elementsWithStableDefinitions . push ( element ) ;
176+ }
177+ } ,
178+ } ) ;
179+
180+ // Upgrade elements with 'stable' definitions first.
181+ for ( let i = 0 ; i < elementsWithStableDefinitions . length ; i ++ ) {
182+ this . _internals . upgradeElement ( elementsWithStableDefinitions [ i ] ) ;
183+ }
184+
185+ // Upgrade elements with 'pending' definitions in the order they were defined.
186+ while ( pendingDefinitions . length > 0 ) {
187+ const definition = pendingDefinitions . shift ( ) ;
188+ const localName = definition . localName ;
189+
190+ // Attempt to upgrade all applicable elements.
191+ const pendingUpgradableElements = elementsWithPendingDefinitions . get ( definition . localName ) ;
192+ for ( let i = 0 ; i < pendingUpgradableElements . length ; i ++ ) {
193+ this . _internals . upgradeElement ( pendingUpgradableElements [ i ] ) ;
194+ }
195+
196+ // Resolve any promises created by `whenDefined` for the definition.
146197 const deferred = this . _whenDefinedDeferred . get ( localName ) ;
147198 if ( deferred ) {
148199 deferred . resolve ( undefined ) ;
@@ -184,7 +235,7 @@ export default class CustomElementRegistry {
184235 // Resolve immediately only if the given local name has a definition *and*
185236 // the full document walk to upgrade elements with that local name has
186237 // already happened.
187- if ( definition && this . _unflushedLocalNames . indexOf ( localName ) === - 1 ) {
238+ if ( definition && ! this . _pendingDefinitions . some ( d => d . localName === localName ) ) {
188239 deferred . resolve ( undefined ) ;
189240 }
190241
0 commit comments