More or less cosmetic

This commit is contained in:
Tony Garnock-Jones 2021-12-11 16:54:21 +01:00
parent 92fa548109
commit 666a3daac3
1 changed files with 89 additions and 88 deletions

View File

@ -76,12 +76,12 @@ export function spawnWindowEventFactory(ds: Ref) {
const facet = Turn.activeFacet; const facet = Turn.activeFacet;
facet.preventInertCheck(); facet.preventInertCheck();
let handler = function (event: Event) { let handler = (event: Event) => {
facet.turn(() => { facet.turn(() => {
send message P.WindowEvent(eventType, embed(create ({ data: event }))); send message P.WindowEvent(eventType, embed(create ({ data: event })));
}); });
return dealWithPreventDefault(eventType, event); return dealWithPreventDefault(eventType, event);
} };
function updateEventListeners(install: boolean) { function updateEventListeners(install: boolean) {
if (install) { if (install) {
@ -116,108 +116,109 @@ function spawnUIFragmentFactory(ds: Ref) {
spawn named 'UIFragmentFactory' { spawn named 'UIFragmentFactory' {
at ds { at ds {
during P.UIFragment($fragmentId0, _, _, _) => spawn named ['UIFragment', fragmentId0] { during P.UIFragment($fragmentId0, _, _, _) =>
if (!isFragmentId(fragmentId0)) return; spawn named ['UIFragment', fragmentId0] {
const fragmentId = fragmentId0; if (!isFragmentId(fragmentId0)) return;
const fragmentId = fragmentId0;
field version: number = 0; field version: number = 0;
assert P.UIFragmentVersion(fragmentId, version.value) when (version.value > 0); assert P.UIFragmentVersion(fragmentId, version.value) when (version.value > 0);
let selector: string; let selector: string;
let html: Array<ChildNode>; let html: Array<ChildNode>;
let orderBy: NodeOrderKey; let orderBy: NodeOrderKey;
let anchorNodes: Array<Element> = []; let anchorNodes: Array<Element> = [];
let eventRegistrations = let eventRegistrations =
new FlexMap<RegistrationKey, HandlerClosure>(JSON.stringify); new FlexMap<RegistrationKey, HandlerClosure>(JSON.stringify);
on stop removeNodes(); on stop removeNodes();
during Observe({ during Observe({
"pattern": :pattern P.UIEvent(fragmentId, "pattern": :pattern P.UIEvent(fragmentId,
\Q.lit($selector: string), \Q.lit($selector: string),
\Q.lit($eventType: string), \Q.lit($eventType: string),
\_) \_)
}) => { }) => {
updateEventListeners([ selector, eventType ], true); updateEventListeners([ selector, eventType ], true);
on stop updateEventListeners([ selector, eventType ], false); on stop updateEventListeners([ selector, eventType ], false);
}
on asserted P.UIFragment(fragmentId, $newSelector: string, $newHtml, $newOrderBy) => {
if (!isNodeOrderKey(newOrderBy)) return;
removeNodes();
selector = newSelector;
html = (newHtml as Embedded<Ref>).embeddedValue.target.data as ChildNode[];
orderBy = newOrderBy;
anchorNodes = (selector !== null) ? selectorMatch(document.body, selector) : [];
if (anchorNodes.length === 0) {
console.warn('UIFragment found no parent nodes matching selector', selector, fragmentId);
} }
anchorNodes.forEach(anchorNode => { on asserted P.UIFragment(fragmentId, $newSelector: string, $newHtml, $newOrderBy) => {
let insertionPoint = findInsertionPoint(anchorNode, orderBy, fragmentId); if (!isNodeOrderKey(newOrderBy)) return;
html.forEach(newNode => {
setSortKey(newNode, orderBy, fragmentId);
anchorNode.insertBefore(newNode, insertionPoint);
configureNode(newNode);
});
});
// (re)install event listeners removeNodes();
eventRegistrations.forEach((_handler, key) => updateEventListeners(key, true));
version.value++; selector = newSelector;
} html = (newHtml as Embedded<Ref>).embeddedValue.target.data as ChildNode[];
orderBy = newOrderBy;
anchorNodes = (selector !== null) ? selectorMatch(document.body, selector) : [];
function removeNodes() { if (anchorNodes.length === 0) {
anchorNodes.forEach(anchorNode => { console.warn('UIFragment found no parent nodes matching selector', selector, fragmentId);
let insertionPoint = findInsertionPoint(anchorNode, orderBy, fragmentId);
while (true) {
let n = insertionPoint ? insertionPoint.previousSibling : anchorNode.lastChild;
if (!(n && hasSortKey(n, orderBy, fragmentId))) break;
n.parentNode?.removeChild(n); // auto-updates previousSibling/lastChild
} }
});
}
function updateEventListeners(key: RegistrationKey, install: boolean) { anchorNodes.forEach(anchorNode => {
const [selector, eventType] = key; let insertionPoint = findInsertionPoint(anchorNode, orderBy, fragmentId);
html.forEach(newNode => {
let handlerClosure: HandlerClosure; setSortKey(newNode, orderBy, fragmentId);
if (!eventRegistrations.has(key)) { anchorNode.insertBefore(newNode, insertionPoint);
const facet = Turn.activeFacet; configureNode(newNode);
function handler(event: Event) {
facet.turn(() => {
send message P.UIEvent(fragmentId, selector, eventType, embed(create ({ data: event })));
}); });
return dealWithPreventDefault(eventType, event); });
}
eventRegistrations.set(key, handler); // (re)install event listeners
handlerClosure = handler; eventRegistrations.forEach((_handler, key) => updateEventListeners(key, true));
} else {
handlerClosure = eventRegistrations.get(key)!; version.value++;
} }
anchorNodes.forEach(anchorNode => { function removeNodes() {
let insertionPoint = findInsertionPoint(anchorNode, orderBy, fragmentId); anchorNodes.forEach(anchorNode => {
while (true) { let insertionPoint = findInsertionPoint(anchorNode, orderBy, fragmentId);
let uiNode = insertionPoint ? insertionPoint.previousSibling : anchorNode.lastChild; while (true) {
if (!(uiNode && hasSortKey(uiNode, orderBy, fragmentId))) break; let n = insertionPoint ? insertionPoint.previousSibling : anchorNode.lastChild;
if (isQueryableNode(uiNode)) { if (!(n && hasSortKey(n, orderBy, fragmentId))) break;
selectorMatch(uiNode, selector).forEach( n.parentNode?.removeChild(n); // auto-updates previousSibling/lastChild
eventUpdater(cleanEventType(eventType), handlerClosure, install));
} }
insertionPoint = uiNode; });
} }
});
if (!install) { function updateEventListeners(key: RegistrationKey, install: boolean) {
eventRegistrations.delete(key); const [selector, eventType] = key;
let handlerClosure: HandlerClosure;
if (!eventRegistrations.has(key)) {
const facet = Turn.activeFacet;
function handler(event: Event) {
facet.turn(() => {
send message P.UIEvent(fragmentId, selector, eventType, embed(create ({ data: event })));
});
return dealWithPreventDefault(eventType, event);
}
eventRegistrations.set(key, handler);
handlerClosure = handler;
} else {
handlerClosure = eventRegistrations.get(key)!;
}
anchorNodes.forEach(anchorNode => {
let insertionPoint = findInsertionPoint(anchorNode, orderBy, fragmentId);
while (true) {
let uiNode = insertionPoint ? insertionPoint.previousSibling : anchorNode.lastChild;
if (!(uiNode && hasSortKey(uiNode, orderBy, fragmentId))) break;
if (isQueryableNode(uiNode)) {
selectorMatch(uiNode, selector).forEach(
eventUpdater(cleanEventType(eventType), handlerClosure, install));
}
insertionPoint = uiNode;
}
});
if (!install) {
eventRegistrations.delete(key);
}
} }
} }
}
} }
} }
} }
@ -309,7 +310,7 @@ function configureNode(n: ChildNode) {
// Runs post-insertion configuration of nodes. // Runs post-insertion configuration of nodes.
// TODO: review this design. // TODO: review this design.
selectorMatch(n, '.-syndicate-focus').forEach( selectorMatch(n, '.-syndicate-focus').forEach(
function (n: Element | HTMLTextAreaElement | HTMLInputElement) { (n: Element | HTMLTextAreaElement | HTMLInputElement) => {
if ('focus' in n && 'setSelectionRange' in n) { if ('focus' in n && 'setSelectionRange' in n) {
n.focus(); n.focus();
n.setSelectionRange(n.value.length, n.value.length); n.setSelectionRange(n.value.length, n.value.length);
@ -573,7 +574,7 @@ function selectorMatch(n: Element | Node, selector: string): Array<Element> {
} }
function eventUpdater(eventType: string, handlerClosure: (event: Event) => void, install: boolean) { function eventUpdater(eventType: string, handlerClosure: (event: Event) => void, install: boolean) {
return function (n: EventTarget) { return (n: EventTarget) => {
// addEventListener and removeEventListener are idempotent. // addEventListener and removeEventListener are idempotent.
if (install) { if (install) {
n.addEventListener(eventType, handlerClosure); n.addEventListener(eventType, handlerClosure);