diff --git a/AGENTS.md b/AGENTS.md index 0b12344..b9b8d7d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -62,6 +62,10 @@ A live target that's in the page is inserted with `moveBefore` too (when it's in The `isEqualNode` pass gives each target the first free equal element, so when an element changes and a sibling is identical to its old version, the unchanged target takes the changed element's live node and the two would swap places. Identical live elements are interchangeable, so once every sibling is matched, each set of them is given to its targets in order, when that leaves more nodes in place than the order the passes chose (checked once for all the sets, so many sets stay fast). On a tie the passes' order stays, since moving other nodes instead changes which whitespace is reused. An element holding the user's changes is never identical to anything, but the `isEqualNode` pass gives its identical untouched sibling the target in its place, and the changed element takes a later one. So before that, in both modes, each changed element is ordered the same way with the untouched siblings of its shape, whatever targets they took, among targets with the same outline (the shape without attributes other than `is`, or a textarea's text, which is only its default value) and the same choices, counting duplicates, and for targets holding choices, the same attributes apart from `class` and `style`, as the choice pass prefers. Sets without a changed element are left to the ordering above. The kind pass can give an element a target with another outline, and the choice pass can give a changed control a target holding another value than its identical sibling's, so a changed element never trades into either. The shape, name and kind passes can cross changed elements, like inputs holding typed text, so they take their targets in order with the rest. Matching by name, in the name pass and the outline pass, skips an element that would be replaced rather than morphed, like an input of another type, so a same-name input of the target's type keeps its target and the user's text. The name pass still gives the target such an element once no target can take it to morph, because replacing it asks both vetoes before changing anything, while removing it and adding the target doesn't. This order always wins, even when it leaves fewer nodes in place, since the user's text belongs in its own row, whatever other nodes move (Joel's rule that user intent wins). Before the name and kind passes, when a changed element is still without a target, or an untouched sibling gave one its target, the free elements with the same outline as one take the targets with that outline in order, changed elements first, among the targets those passes would give them, so a typed row isn't given the first target of its tag when that has another outline, and an untouched row goes rather than a typed one when there are fewer targets. A target holding a `morphlex-clobber` element only takes an untouched element in that pass, so an earlier clobbered row doesn't shift the typed rows after it. When ordering, a changed element never trades into a target holding a `morphlex-clobber` element: such a target takes the first untouched sibling, and the other targets take the first free sibling while enough untouched ones are left for those. The equal target a changed element takes is morphed, not skipped. Untouched siblings of the same shape that no target took can stay instead of the ones the passes kept, since removing either leaves the same markup, so the ones that stay are chosen (a dynamic program over the siblings in order) to cross the fewest other matches, where crossing a changed element outweighs crossing all the others, and two changed elements crossing outweighs both, so typed rows of different kinds keep their order. On a tie, or when the program would be too big (a morph removing many of many identical siblings), the passes' choice stays. +### Addresses: `href` and `src` + +A non-empty `href` or `src` pairs elements sharing it first, but doesn't stop an element matching by its tag, so a link, image or iframe whose address changes is morphed in place: a focused link keeps focus, and Chromium and WebKit keep a stylesheet applied until its new `href` loads. A `name`, an `id` and form controls still block matching by tag. A script with a `src` (or an SVG script with an `href`) and a media `source` with a `src` are still replaced, because a script doesn't run again when its address changes, and a media element doesn't look at a source again. An address loads as soon as it changes, with the attributes the element has then, so `#visitAttributes` updates `srcdoc`, `src` and `href` after every other attribute is added, changed or removed, so an iframe's new page gets its `sandbox` and a link's new sheet its `integrity`. `srcdoc` goes first, since it takes precedence over `src`. A link whose `rel` changes along with its `href` can briefly load the old `href` for its new `rel`; that's rare enough to leave. + ### Whitespace between elements Whitespace text nodes are only ever matched with whitespace. The live whitespace stays in place while the children are placed, and target whitespace reuses the live whitespace at the insertion point, so unchanged whitespace isn't removed and added again. Whitespace nothing reused is removed afterwards. diff --git a/README.md b/README.md index 96eb719..a0c8284 100644 --- a/README.md +++ b/README.md @@ -186,7 +186,7 @@ When morphing the children of an element, Morphlex pairs each new child with an 4. An element that contains one of the same `id`s somewhere inside it. 5. With `preserveChanges`, a checkbox, radio or option the user changed is paired with one making the same choice, such as the same name and value in the same form, and an element such as a `