@@ -10,6 +10,27 @@ import 'package:webf/src/dom/node_traversal.dart';
10
10
11
11
typedef InsertNodeHandler = void Function (ContainerNode container, Node child, Node ? next);
12
12
13
+ enum DynamicRestyleFlag {
14
+ ChildrenAffectedByFirstChildRules ,
15
+ ChildrenAffectedByLastChildRules ,
16
+ ChildrenAffectedByDirectAdjacentRules ,
17
+ ChildrenAffectedByForwardPositionalRules ,
18
+ ChildrenAffectedByBackwardPositionalRules ,
19
+ }
20
+
21
+ extension StructuralRules on DynamicRestyleFlag {
22
+ bool childrenAffectedByStructuralRules () {
23
+ if (this == DynamicRestyleFlag .ChildrenAffectedByFirstChildRules ||
24
+ this == DynamicRestyleFlag .ChildrenAffectedByLastChildRules ||
25
+ this == DynamicRestyleFlag .ChildrenAffectedByDirectAdjacentRules ||
26
+ this == DynamicRestyleFlag .ChildrenAffectedByForwardPositionalRules ||
27
+ this == DynamicRestyleFlag .ChildrenAffectedByBackwardPositionalRules ) {
28
+ return true ;
29
+ }
30
+ return false ;
31
+ }
32
+ }
33
+
13
34
bool collectChildrenAndRemoveFromOldParent (Node node, List <Node > nodes) {
14
35
if (node is DocumentFragment ) {
15
36
getChildNodes (node, nodes);
@@ -34,6 +55,15 @@ void getChildNodes(ContainerNode node, List<Node> nodes) {
34
55
abstract class ContainerNode extends Node {
35
56
ContainerNode (NodeType nodeType, [BindingContext ? context]) : super (nodeType, context);
36
57
58
+ List <DynamicRestyleFlag >? restyleFlags;
59
+
60
+ void addFlag (DynamicRestyleFlag flag) {
61
+ restyleFlags ?? = [];
62
+ if (restyleFlags? .contains (flag) == false ) {
63
+ restyleFlags? .add (flag);
64
+ }
65
+ }
66
+
37
67
void _adoptAndAppendChild (ContainerNode container, Node child, Node ? next) {
38
68
child.parentOrShadowHostNode = this ;
39
69
if (lastChild != null ) {
@@ -333,6 +363,70 @@ abstract class ContainerNode extends Node {
333
363
}
334
364
}
335
365
366
+ void CheckForSiblingStyleChanges (Element parent, bool isRemoved, Node ? nodeBeforeChange, Node ? nodeAfterChange) {
367
+
368
+ if (! isRendererAttached) {
369
+ return ;
370
+ }
371
+
372
+ final elementBeforeChange = nodeBeforeChange as Element ? ;
373
+ final elementAfterChange = nodeAfterChange as Element ? ;
374
+
375
+ // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
376
+ // In the DOM case, we only need to do something if |afterChange| is not 0.
377
+ // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
378
+ if (elementAfterChange != null &&
379
+ restyleFlags? .contains (DynamicRestyleFlag .ChildrenAffectedByFirstChildRules ) == true ) {
380
+ // Find our new first child.
381
+ final newFirstElement = parent.firstChild as Element ? ;
382
+
383
+ // This is the insert/append case.
384
+ if (newFirstElement != elementAfterChange && elementAfterChange.isRendererAttached) {
385
+ elementAfterChange.recalculateStyle ();
386
+ }
387
+
388
+ if (newFirstElement != null && isRemoved && newFirstElement == elementAfterChange) {
389
+ newFirstElement.recalculateStyle ();
390
+ }
391
+ }
392
+
393
+ if (elementBeforeChange != null &&
394
+ restyleFlags? .contains (DynamicRestyleFlag .ChildrenAffectedByLastChildRules ) == true ) {
395
+ // Find our new first child.
396
+ final newLastElement = parent.lastChild as Element ? ;
397
+
398
+ // This is the insert/append case.
399
+ if (newLastElement != elementBeforeChange && elementBeforeChange.isRendererAttached) {
400
+ elementBeforeChange.recalculateStyle ();
401
+ }
402
+
403
+ if (newLastElement != null && isRemoved && newLastElement == elementBeforeChange) {
404
+ newLastElement.recalculateStyle ();
405
+ }
406
+ }
407
+
408
+ // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element
409
+ // that could be affected by this DOM change.
410
+ if (restyleFlags? .contains (DynamicRestyleFlag .ChildrenAffectedByDirectAdjacentRules ) == true && elementAfterChange != null ) {
411
+ elementAfterChange.recalculateStyle ();
412
+ }
413
+
414
+ // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
415
+ // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
416
+ // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
417
+ // backward case.
418
+ // |afterChange| is 0 in the parser callback case, so we won't do any work for the forward case if we don't have to.
419
+ // For performance reasons we just mark the parent node as changed, since we don't want to make childrenChanged O(n^2) by crawling all our kids
420
+ // here. recalcStyle will then force a walk of the children when it sees that this has happened.
421
+ if (elementAfterChange != null &&
422
+ restyleFlags? .contains (DynamicRestyleFlag .ChildrenAffectedByForwardPositionalRules ) == true ) {
423
+ parent.recalculateStyle ();
424
+ } else if (elementBeforeChange != null &&
425
+ restyleFlags? .contains (DynamicRestyleFlag .ChildrenAffectedByBackwardPositionalRules ) == true ) {
426
+ parent.recalculateStyle ();
427
+ }
428
+ }
429
+
336
430
Node ? _firstChild;
337
431
338
432
@override
0 commit comments