@@ -305,15 +305,6 @@ function htmlToElement(html) {
305
305
}
306
306
return child ;
307
307
}
308
- function cloneElementWithNewTagName ( element , newTag ) {
309
- const originalTag = element . tagName ;
310
- const startRX = new RegExp ( '^<' + originalTag , 'i' ) ;
311
- const endRX = new RegExp ( originalTag + '>$' , 'i' ) ;
312
- const startSubst = '<' + newTag ;
313
- const endSubst = newTag + '>' ;
314
- const newHTML = element . outerHTML . replace ( startRX , startSubst ) . replace ( endRX , endSubst ) ;
315
- return htmlToElement ( newHTML ) ;
316
- }
317
308
function getElementAsTagText ( element ) {
318
309
return element . innerHTML
319
310
? element . outerHTML . slice ( 0 , element . outerHTML . indexOf ( element . innerHTML ) )
@@ -365,6 +356,7 @@ class ValueStore {
365
356
this . props = { } ;
366
357
this . dirtyProps = { } ;
367
358
this . pendingProps = { } ;
359
+ this . updatedPropsFromParent = { } ;
368
360
this . props = props ;
369
361
}
370
362
get ( name ) {
@@ -398,27 +390,33 @@ class ValueStore {
398
390
getDirtyProps ( ) {
399
391
return Object . assign ( { } , this . dirtyProps ) ;
400
392
}
393
+ getUpdatedPropsFromParent ( ) {
394
+ return Object . assign ( { } , this . updatedPropsFromParent ) ;
395
+ }
401
396
flushDirtyPropsToPending ( ) {
402
397
this . pendingProps = Object . assign ( { } , this . dirtyProps ) ;
403
398
this . dirtyProps = { } ;
404
399
}
405
400
reinitializeAllProps ( props ) {
406
401
this . props = props ;
402
+ this . updatedPropsFromParent = { } ;
407
403
this . pendingProps = { } ;
408
404
}
409
405
pushPendingPropsBackToDirty ( ) {
410
406
this . dirtyProps = Object . assign ( Object . assign ( { } , this . pendingProps ) , this . dirtyProps ) ;
411
407
this . pendingProps = { } ;
412
408
}
413
- reinitializeProvidedProps ( props ) {
409
+ storeNewPropsFromParent ( props ) {
414
410
let changed = false ;
415
411
for ( const [ key , value ] of Object . entries ( props ) ) {
416
412
const currentValue = this . get ( key ) ;
417
413
if ( currentValue !== value ) {
418
414
changed = true ;
419
- this . props [ key ] = value ;
420
415
}
421
416
}
417
+ if ( changed ) {
418
+ this . updatedPropsFromParent = props ;
419
+ }
422
420
return changed ;
423
421
}
424
422
}
@@ -1201,14 +1199,6 @@ function executeMorphdom(rootFromElement, rootToElement, modifiedFieldElements,
1201
1199
const childComponentMap = new Map ( ) ;
1202
1200
childComponents . forEach ( ( childComponent ) => {
1203
1201
childComponentMap . set ( childComponent . element , childComponent ) ;
1204
- if ( ! childComponent . id ) {
1205
- throw new Error ( 'Child is missing id.' ) ;
1206
- }
1207
- const childComponentToElement = findChildComponent ( childComponent . id , rootToElement ) ;
1208
- if ( childComponentToElement && childComponentToElement . tagName !== childComponent . element . tagName ) {
1209
- const newTag = cloneElementWithNewTagName ( childComponentToElement , childComponent . element . tagName ) ;
1210
- childComponentToElement . replaceWith ( newTag ) ;
1211
- }
1212
1202
} ) ;
1213
1203
morphdom ( rootFromElement , rootToElement , {
1214
1204
getNodeKey : ( node ) => {
@@ -1227,7 +1217,8 @@ function executeMorphdom(rootFromElement, rootToElement, modifiedFieldElements,
1227
1217
if ( fromEl instanceof HTMLElement && toEl instanceof HTMLElement ) {
1228
1218
if ( childComponentMap . has ( fromEl ) ) {
1229
1219
const childComponent = childComponentMap . get ( fromEl ) ;
1230
- return childComponent . updateFromNewElement ( toEl ) ;
1220
+ childComponent . updateFromNewElementFromParentRender ( toEl ) ;
1221
+ return false ;
1231
1222
}
1232
1223
if ( modifiedFieldElements . includes ( fromEl ) ) {
1233
1224
setValueOnElement ( toEl , getElementValue ( fromEl ) ) ;
@@ -1867,20 +1858,19 @@ class Component {
1867
1858
this . action ( action , data , 1 ) ;
1868
1859
} ) ;
1869
1860
}
1870
- updateFromNewElement ( toEl ) {
1861
+ updateFromNewElementFromParentRender ( toEl ) {
1871
1862
const props = this . elementDriver . getComponentProps ( toEl ) ;
1872
1863
if ( props === null ) {
1873
- return false ;
1864
+ return ;
1874
1865
}
1875
- const isChanged = this . valueStore . reinitializeProvidedProps ( props ) ;
1866
+ const isChanged = this . valueStore . storeNewPropsFromParent ( props ) ;
1876
1867
const fingerprint = toEl . dataset . liveFingerprintValue ;
1877
1868
if ( fingerprint !== undefined ) {
1878
1869
this . fingerprint = fingerprint ;
1879
1870
}
1880
1871
if ( isChanged ) {
1881
1872
this . render ( ) ;
1882
1873
}
1883
- return false ;
1884
1874
}
1885
1875
onChildComponentModelUpdate ( modelName , value , childComponent ) {
1886
1876
if ( ! childComponent . id ) {
@@ -1909,7 +1899,7 @@ class Component {
1909
1899
const thisPromiseResolve = this . nextRequestPromiseResolve ;
1910
1900
this . resetPromise ( ) ;
1911
1901
this . unsyncedInputsTracker . resetUnsyncedFields ( ) ;
1912
- this . backendRequest = this . backend . makeRequest ( this . valueStore . getOriginalProps ( ) , this . pendingActions , this . valueStore . getDirtyProps ( ) , this . getChildrenFingerprints ( ) ) ;
1902
+ this . backendRequest = this . backend . makeRequest ( this . valueStore . getOriginalProps ( ) , this . pendingActions , this . valueStore . getDirtyProps ( ) , this . getChildrenFingerprints ( ) , this . valueStore . getUpdatedPropsFromParent ( ) ) ;
1913
1903
this . hooks . triggerHook ( 'loading.state:started' , this . element , this . backendRequest ) ;
1914
1904
this . pendingActions = [ ] ;
1915
1905
this . valueStore . flushDirtyPropsToPending ( ) ;
@@ -2065,7 +2055,10 @@ class Component {
2065
2055
if ( ! child . id ) {
2066
2056
throw new Error ( 'missing id' ) ;
2067
2057
}
2068
- fingerprints [ child . id ] = child . fingerprint ;
2058
+ fingerprints [ child . id ] = {
2059
+ fingerprint : child . fingerprint ,
2060
+ tag : child . element . tagName . toLowerCase ( ) ,
2061
+ } ;
2069
2062
} ) ;
2070
2063
return fingerprints ;
2071
2064
}
@@ -2129,7 +2122,7 @@ class RequestBuilder {
2129
2122
this . url = url ;
2130
2123
this . csrfToken = csrfToken ;
2131
2124
}
2132
- buildRequest ( props , actions , updated , childrenFingerprints ) {
2125
+ buildRequest ( props , actions , updated , children , updatedPropsFromParent ) {
2133
2126
const splitUrl = this . url . split ( '?' ) ;
2134
2127
let [ url ] = splitUrl ;
2135
2128
const [ , queryString ] = splitUrl ;
@@ -2138,22 +2131,28 @@ class RequestBuilder {
2138
2131
fetchOptions . headers = {
2139
2132
Accept : 'application/vnd.live-component+html' ,
2140
2133
} ;
2141
- const hasFingerprints = Object . keys ( childrenFingerprints ) . length > 0 ;
2134
+ const hasFingerprints = Object . keys ( children ) . length > 0 ;
2142
2135
if ( actions . length === 0 &&
2143
- this . willDataFitInUrl ( JSON . stringify ( props ) , JSON . stringify ( updated ) , params , JSON . stringify ( childrenFingerprints ) ) ) {
2136
+ this . willDataFitInUrl ( JSON . stringify ( props ) , JSON . stringify ( updated ) , params , JSON . stringify ( children ) , JSON . stringify ( updatedPropsFromParent ) ) ) {
2144
2137
params . set ( 'props' , JSON . stringify ( props ) ) ;
2145
2138
params . set ( 'updated' , JSON . stringify ( updated ) ) ;
2139
+ if ( Object . keys ( updatedPropsFromParent ) . length > 0 ) {
2140
+ params . set ( 'propsFromParent' , JSON . stringify ( updatedPropsFromParent ) ) ;
2141
+ }
2146
2142
if ( hasFingerprints ) {
2147
- params . set ( 'childrenFingerprints ' , JSON . stringify ( childrenFingerprints ) ) ;
2143
+ params . set ( 'children ' , JSON . stringify ( children ) ) ;
2148
2144
}
2149
2145
fetchOptions . method = 'GET' ;
2150
2146
}
2151
2147
else {
2152
2148
fetchOptions . method = 'POST' ;
2153
2149
fetchOptions . headers [ 'Content-Type' ] = 'application/json' ;
2154
2150
const requestData = { props, updated } ;
2151
+ if ( Object . keys ( updatedPropsFromParent ) . length > 0 ) {
2152
+ requestData . propsFromParent = updatedPropsFromParent ;
2153
+ }
2155
2154
if ( hasFingerprints ) {
2156
- requestData . childrenFingerprints = childrenFingerprints ;
2155
+ requestData . children = children ;
2157
2156
}
2158
2157
if ( actions . length > 0 ) {
2159
2158
if ( this . csrfToken ) {
@@ -2176,8 +2175,8 @@ class RequestBuilder {
2176
2175
fetchOptions,
2177
2176
} ;
2178
2177
}
2179
- willDataFitInUrl ( propsJson , updatedJson , params , childrenFingerprintsJson ) {
2180
- const urlEncodedJsonData = new URLSearchParams ( propsJson + updatedJson + childrenFingerprintsJson ) . toString ( ) ;
2178
+ willDataFitInUrl ( propsJson , updatedJson , params , childrenJson , propsFromParentJson ) {
2179
+ const urlEncodedJsonData = new URLSearchParams ( propsJson + updatedJson + childrenJson + propsFromParentJson ) . toString ( ) ;
2181
2180
return ( urlEncodedJsonData + params . toString ( ) ) . length < 1500 ;
2182
2181
}
2183
2182
}
@@ -2186,8 +2185,8 @@ class Backend {
2186
2185
constructor ( url , csrfToken = null ) {
2187
2186
this . requestBuilder = new RequestBuilder ( url , csrfToken ) ;
2188
2187
}
2189
- makeRequest ( props , actions , updated , childrenFingerprints ) {
2190
- const { url, fetchOptions } = this . requestBuilder . buildRequest ( props , actions , updated , childrenFingerprints ) ;
2188
+ makeRequest ( props , actions , updated , children , updatedPropsFromParent ) {
2189
+ const { url, fetchOptions } = this . requestBuilder . buildRequest ( props , actions , updated , children , updatedPropsFromParent ) ;
2191
2190
return new BackendRequest ( fetch ( url , fetchOptions ) , actions . map ( ( backendAction ) => backendAction . name ) , Object . keys ( updated ) ) ;
2192
2191
}
2193
2192
}
@@ -2855,7 +2854,7 @@ LiveControllerDefault.values = {
2855
2854
listeners : { type : Array , default : [ ] } ,
2856
2855
debounce : { type : Number , default : 150 } ,
2857
2856
id : String ,
2858
- fingerprint : String ,
2857
+ fingerprint : { type : String , default : '' } ,
2859
2858
} ;
2860
2859
LiveControllerDefault . componentRegistry = new ComponentRegistry ( ) ;
2861
2860
0 commit comments