11import {
2- cloneHTMLElement ,
2+ cloneElementWithNewTagName ,
3+ cloneHTMLElement ,
34 setValueOnElement
4- } from "./dom_utils" ;
5- import morphdom from "morphdom" ;
6- import { normalizeAttributesForComparison } from "./normalize_attributes_for_comparison" ;
5+ } from './dom_utils' ;
6+ import morphdom from 'morphdom' ;
7+ import {
8+ normalizeAttributesForComparison
9+ } from './normalize_attributes_for_comparison' ;
10+ import Component from './Component' ;
711
812export function executeMorphdom (
913 rootFromElement : HTMLElement ,
1014 rootToElement : HTMLElement ,
1115 modifiedElements : Array < HTMLElement > ,
1216 getElementValue : ( element : HTMLElement ) => any ,
17+ childComponents : Component [ ] ,
1318) {
14- // make sure everything is in non-loading state, the same as the HTML currently on the page
19+ const childComponentMap : Map < HTMLElement , Component > = new Map ( ) ;
20+ childComponents . forEach ( ( childComponent ) => {
21+ childComponentMap . set ( childComponent . element , childComponent ) ;
22+ // TODO: add driver to make this agnostic
23+ const childComponentToElement = rootToElement . querySelector ( `[data-live-id-value=${ childComponent . id } ]` )
24+ if ( childComponentToElement && childComponentToElement . tagName !== childComponent . element . tagName ) {
25+ // we need to "correct" the tag name for the child to match the "from"
26+ // so that we always get a "diff", not a remove/add
27+ const newTag = cloneElementWithNewTagName ( childComponentToElement , childComponent . element . tagName ) ;
28+ rootToElement . replaceChild ( newTag , childComponentToElement ) ;
29+ }
30+ } ) ;
31+
1532 morphdom ( rootFromElement , rootToElement , {
1633 getNodeKey : ( node : Node ) => {
17- if ( ! ( node instanceof HTMLElement ) ) {
18- return ;
19- }
34+ if ( ! ( node instanceof HTMLElement ) ) {
35+ return ;
36+ }
37+
38+ // TODO: abstract out to make this function agnostic of markup
39+ if ( node . dataset . liveId ) {
40+ return node . dataset . liveId ;
41+ }
2042
21- return node . dataset . liveId ;
43+ // TODO: do we really need data-live-id and data-live-value-id?
44+ return node . dataset . liveIdValue
2245 } ,
2346 onBeforeElUpdated : ( fromEl , toEl ) => {
47+ if ( fromEl === rootFromElement ) {
48+ return true ;
49+ }
50+
2451 if ( ! ( fromEl instanceof HTMLElement ) || ! ( toEl instanceof HTMLElement ) ) {
2552 return false ;
2653 }
2754
55+ const childComponent = childComponentMap . get ( fromEl ) || false
56+ if ( childComponent ) {
57+ return childComponent . updateFromNewElement ( toEl ) ;
58+ }
59+
2860 // if this field's value has been modified since this HTML was
2961 // requested, set the toEl's value to match the fromEl
3062 if ( modifiedElements . includes ( fromEl ) ) {
@@ -47,16 +79,6 @@ export function executeMorphdom(
4779 }
4880 }
4981
50- // avoid updating child components: they will handle themselves
51- const controllerName = fromEl . hasAttribute ( 'data-controller' ) ? fromEl . getAttribute ( 'data-controller' ) : null ;
52- if ( controllerName
53- && controllerName . split ( ' ' ) . indexOf ( 'live' ) !== - 1
54- && fromEl !== rootFromElement
55- ) {
56- // TODO: add new child logic here
57- return false ;
58- }
59-
6082 // look for data-live-ignore, and don't update
6183 return ! fromEl . hasAttribute ( 'data-live-ignore' ) ;
6284 } ,
0 commit comments