Port html package (and one example)
This commit is contained in:
parent
7a7ad76036
commit
74377b87f6
|
@ -3,9 +3,8 @@
|
||||||
<head>
|
<head>
|
||||||
<title>Syndicate: Table Example</title>
|
<title>Syndicate: Table Example</title>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<script src="../../../../node_modules/@syndicate-lang/core/dist/syndicate.js"></script>
|
<script src="node_modules/@syndicate-lang/core/dist/syndicate.js"></script>
|
||||||
<script src="../../../../node_modules/@syndicate-lang/html/dist/syndicate-html.js"></script>
|
<script src="node_modules/@syndicate-lang/html/dist/syndicate-html.js"></script>
|
||||||
<script src="index.js"></script>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Table Example</h1>
|
<h1>Table Example</h1>
|
||||||
|
@ -27,8 +26,6 @@
|
||||||
Source code: <a href="src/index.ts">index.ts</a>
|
Source code: <a href="src/index.ts">index.ts</a>
|
||||||
</p>
|
</p>
|
||||||
<div id="extra"></div>
|
<div id="extra"></div>
|
||||||
<script>
|
<script src="index.js"></script>
|
||||||
Syndicate.bootModule(Main.__SYNDICATE__bootProc);
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "yarn compile && yarn rollup",
|
"prepare": "yarn compile && yarn rollup",
|
||||||
"compile": "syndicate-tsc",
|
"compile": "syndicate-tsc",
|
||||||
|
"compile:watch": "syndicate-tsc -w --verbose --intermediate-directory src.ts",
|
||||||
"rollup": "rollup -c",
|
"rollup": "rollup -c",
|
||||||
|
"rollup:watch": "rollup -c -w",
|
||||||
"clean": "rm -rf lib/ index.js index.js.map"
|
"clean": "rm -rf lib/ index.js index.js.map"
|
||||||
},
|
},
|
||||||
"author": "Tony Garnock-Jones <tonyg@leastfixedpoint.com>",
|
"author": "Tony Garnock-Jones <tonyg@leastfixedpoint.com>",
|
||||||
|
|
|
@ -1,56 +1,60 @@
|
||||||
/// SPDX-License-Identifier: GPL-3.0-or-later
|
/// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
/// SPDX-FileCopyrightText: Copyright © 2016-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
/// SPDX-FileCopyrightText: Copyright © 2016-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||||
|
|
||||||
import { Embedded, Value } from '@syndicate-lang/core';
|
import { Dataspace, Embedded, Value, Ref } from '@syndicate-lang/core';
|
||||||
activate import { UIEvent, GlobalEvent, HtmlFragments, template, Anchor } from '@syndicate-lang/html';
|
import { boot as bootHtml, UIEvent, GlobalEvent, HtmlFragments, template, Anchor } from '@syndicate-lang/html';
|
||||||
|
|
||||||
assertion type Person(id, firstName, lastName, address, age);
|
assertion type Person(id, firstName, lastName, address, age);
|
||||||
message type SetSortColumn(number);
|
message type SetSortColumn(number);
|
||||||
|
|
||||||
boot {
|
Dataspace.boot(ds => {
|
||||||
function newRow(id: number, firstName: string, lastName: string, address: string, age: number) {
|
bootHtml(ds);
|
||||||
spawn named ('model' + id) {
|
at ds {
|
||||||
assert Person(id, firstName, lastName, address, age);
|
function newRow(id: number, firstName: string, lastName: string, address: string, age: number) {
|
||||||
|
spawn named ('model' + id) {
|
||||||
|
assert Person(id, firstName, lastName, address, age);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newRow(1, 'Keith', 'Example', '94 Main St.', 44);
|
||||||
|
newRow(2, 'Karen', 'Fakeperson', '5504 Long Dr.', 34);
|
||||||
|
newRow(3, 'Angus', 'McFictional', '2B Pioneer Heights', 39);
|
||||||
|
newRow(4, 'Sue', 'Donnem', '1 Infinite Loop', 104);
|
||||||
|
newRow(5, 'Boaty', 'McBoatface', 'Arctic Ocean', 1);
|
||||||
|
|
||||||
|
spawn named 'view' {
|
||||||
|
let ui = new Anchor();
|
||||||
|
field orderColumn: number = 2;
|
||||||
|
|
||||||
|
function cell(text: Value): HtmlFragments {
|
||||||
|
return template`<td>${text.toString()}</td>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
on message SetSortColumn($c: number) => orderColumn.value = c;
|
||||||
|
|
||||||
|
during Person($id: number, $firstName: string, $lastName: string, $address: string, $age: number) => {
|
||||||
|
assert ui.context(id).html(
|
||||||
|
'table#the-table tbody',
|
||||||
|
template`<tr>${[id, firstName, lastName, address, age].map(cell)}</tr>`,
|
||||||
|
[id, firstName, lastName, address, age][orderColumn.value]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spawn named 'controller' {
|
||||||
|
on message GlobalEvent('table#the-table th', 'click', $e) => {
|
||||||
|
const event = (e as Embedded<Ref>).embeddedValue.target.data as Event;
|
||||||
|
send message SetSortColumn(JSON.parse((event.target as HTMLElement).dataset.column!));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spawn named 'alerter' {
|
||||||
|
let ui = new Anchor();
|
||||||
|
assert ui.html('#extra', template`<button>Click me</button>`);
|
||||||
|
|
||||||
|
on message UIEvent(ui.fragmentId, '.', 'click', $_e) => {
|
||||||
|
alert("Hello!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
newRow(1, 'Keith', 'Example', '94 Main St.', 44);
|
|
||||||
newRow(2, 'Karen', 'Fakeperson', '5504 Long Dr.', 34);
|
|
||||||
newRow(3, 'Angus', 'McFictional', '2B Pioneer Heights', 39);
|
|
||||||
newRow(4, 'Sue', 'Donnem', '1 Infinite Loop', 104);
|
|
||||||
newRow(5, 'Boaty', 'McBoatface', 'Arctic Ocean', 1);
|
|
||||||
|
|
||||||
spawn named 'view' {
|
|
||||||
let ui = new Anchor();
|
|
||||||
field orderColumn: number = 2;
|
|
||||||
|
|
||||||
function cell(text: Value): HtmlFragments {
|
|
||||||
return template`<td>${text.toString()}</td>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
on message SetSortColumn($c: number) => this.orderColumn = c;
|
|
||||||
|
|
||||||
during Person($id: number, $firstName: string, $lastName: string, $address: string, $age: number) => {
|
|
||||||
assert ui.context(id)
|
|
||||||
.html('table#the-table tbody',
|
|
||||||
template`<tr>${[id, firstName, lastName, address, age].map(cell)}</tr>`,
|
|
||||||
[id, firstName, lastName, address, age][this.orderColumn]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spawn named 'controller' {
|
|
||||||
on message GlobalEvent('table#the-table th', 'click', $e) => {
|
|
||||||
send message SetSortColumn(
|
|
||||||
JSON.parse(((e as Embedded<Event>).embeddedValue.target as HTMLElement).dataset.column!));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spawn named 'alerter' {
|
|
||||||
let ui = new Anchor();
|
|
||||||
assert ui.html('#extra', template`<button>Click me</button>`);
|
|
||||||
|
|
||||||
on message UIEvent(ui.fragmentId, '.', 'click', $_e) => {
|
|
||||||
alert("Hello!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
/// SPDX-License-Identifier: GPL-3.0-or-later
|
/// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
/// SPDX-FileCopyrightText: Copyright © 2016-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
/// SPDX-FileCopyrightText: Copyright © 2016-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||||
|
|
||||||
import { randomId, Facet, Observe, FlexMap, Value, embed, Embedded } from "@syndicate-lang/core";
|
import { randomId, Observe, FlexMap, embed, Embedded, Ref, Turn, AnyValue } from "@syndicate-lang/core";
|
||||||
|
import { QuasiValue as Q } from "@syndicate-lang/core";
|
||||||
|
|
||||||
import * as P from "./protocol";
|
import * as P from "./protocol";
|
||||||
export * from "./protocol";
|
export * from "./protocol";
|
||||||
|
@ -9,15 +10,15 @@ export * from "./protocol";
|
||||||
import { HtmlFragments } from "./html";
|
import { HtmlFragments } from "./html";
|
||||||
export * from "./html";
|
export * from "./html";
|
||||||
|
|
||||||
boot {
|
export function boot(ds: Ref) {
|
||||||
spawnGlobalEventFactory(thisFacet);
|
spawnGlobalEventFactory(ds);
|
||||||
spawnWindowEventFactory(thisFacet);
|
spawnWindowEventFactory(ds);
|
||||||
spawnUIFragmentFactory(thisFacet);
|
spawnUIFragmentFactory(ds);
|
||||||
spawnUIAttributeFactory(thisFacet);
|
spawnUIAttributeFactory(ds);
|
||||||
spawnUIPropertyFactory(thisFacet);
|
spawnUIPropertyFactory(ds);
|
||||||
spawnUIChangeablePropertyFactory(thisFacet);
|
spawnUIChangeablePropertyFactory(ds);
|
||||||
spawnLocationHashTracker(thisFacet);
|
spawnLocationHashTracker(ds);
|
||||||
spawnAttributeUpdater(thisFacet);
|
spawnAttributeUpdater(ds);
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -32,16 +33,20 @@ export function newFragmentId() {
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
export function spawnGlobalEventFactory<T>(thisFacet: Facet<T>) {
|
export function spawnGlobalEventFactory(ds: Ref) {
|
||||||
spawn named 'GlobalEventFactory' {
|
spawn named 'GlobalEventFactory' {
|
||||||
during Observe(P.GlobalEvent($selector: string, $eventType: string, _)) =>
|
at ds {
|
||||||
spawn named ['GlobalEvent', selector, eventType] {
|
during Observe({
|
||||||
let sender = thisFacet.wrapExternal((thisFacet, e: Event) => {
|
"pattern": :pattern P.GlobalEvent(\Q.lit($selector: string),
|
||||||
send message P.GlobalEvent(selector, eventType, embed(e));
|
\Q.lit($eventType: string),
|
||||||
});
|
\_)
|
||||||
|
}) => spawn named ['GlobalEvent', selector, eventType] {
|
||||||
|
const facet = Turn.activeFacet;
|
||||||
|
|
||||||
function handler(event: Event) {
|
function handler(event: Event) {
|
||||||
sender(event);
|
facet.turn(() => {
|
||||||
|
send message P.GlobalEvent(selector, eventType, embed(create ({ data: event })));
|
||||||
|
});
|
||||||
return dealWithPreventDefault(eventType, event);
|
return dealWithPreventDefault(eventType, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +55,7 @@ export function spawnGlobalEventFactory<T>(thisFacet: Facet<T>) {
|
||||||
eventUpdater(cleanEventType(eventType), handler, install));
|
eventUpdater(cleanEventType(eventType), handler, install));
|
||||||
}
|
}
|
||||||
|
|
||||||
on start updateEventListeners(true);
|
updateEventListeners(true);
|
||||||
on stop updateEventListeners(false);
|
on stop updateEventListeners(false);
|
||||||
|
|
||||||
on asserted P.UIFragmentVersion($_i, $_v) => updateEventListeners(true);
|
on asserted P.UIFragmentVersion($_i, $_v) => updateEventListeners(true);
|
||||||
|
@ -58,19 +63,22 @@ export function spawnGlobalEventFactory<T>(thisFacet: Facet<T>) {
|
||||||
// lets us ignore UIFragmentVersion records coming and going; on
|
// lets us ignore UIFragmentVersion records coming and going; on
|
||||||
// the other hand, we do potentially a lot of redundant work.
|
// the other hand, we do potentially a lot of redundant work.
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function spawnWindowEventFactory<T>(thisFacet: Facet<T>) {
|
export function spawnWindowEventFactory(ds: Ref) {
|
||||||
spawn named 'WindowEventFactory' {
|
spawn named 'WindowEventFactory' {
|
||||||
during Observe(P.WindowEvent($eventType: string, _)) =>
|
at ds {
|
||||||
spawn named ['WindowEvent', eventType] {
|
during Observe({
|
||||||
let sender = thisFacet.wrapExternal((thisFacet, e: Event) => {
|
"pattern": :pattern P.WindowEvent(\Q.lit($eventType: string), \_)
|
||||||
send message P.WindowEvent(eventType, embed(e));
|
}) => spawn named ['WindowEvent', eventType] {
|
||||||
});
|
const facet = Turn.activeFacet;
|
||||||
|
|
||||||
let handler = function (event: Event) {
|
let handler = function (event: Event) {
|
||||||
sender(event);
|
facet.turn(() => {
|
||||||
|
send message P.WindowEvent(eventType, embed(create ({ data: event })));
|
||||||
|
});
|
||||||
return dealWithPreventDefault(eventType, event);
|
return dealWithPreventDefault(eventType, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,9 +90,10 @@ export function spawnWindowEventFactory<T>(thisFacet: Facet<T>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
on start updateEventListeners(true);
|
updateEventListeners(true);
|
||||||
on stop updateEventListeners(false);
|
on stop updateEventListeners(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,17 +110,17 @@ function isNodeOrderKey(x: any): x is NodeOrderKey {
|
||||||
|
|
||||||
type HandlerClosure = (event: Event) => void;
|
type HandlerClosure = (event: Event) => void;
|
||||||
|
|
||||||
function spawnUIFragmentFactory<T>(thisFacet: Facet<T>) {
|
function spawnUIFragmentFactory(ds: Ref) {
|
||||||
type RegistrationKey = [string, string]; // [selector, eventType]
|
type RegistrationKey = [string, string]; // [selector, eventType]
|
||||||
|
|
||||||
spawn named 'UIFragmentFactory' {
|
spawn named 'UIFragmentFactory' {
|
||||||
during P.UIFragment($fragmentId0, _, _, _) =>
|
at ds {
|
||||||
spawn named ['UIFragment', fragmentId0] {
|
during P.UIFragment($fragmentId0, _, _, _) => spawn named ['UIFragment', fragmentId0] {
|
||||||
if (!isFragmentId(fragmentId0)) return;
|
if (!isFragmentId(fragmentId0)) return;
|
||||||
const fragmentId = fragmentId0;
|
const fragmentId = fragmentId0;
|
||||||
|
|
||||||
field version: number = 0;
|
field version: number = 0;
|
||||||
assert P.UIFragmentVersion(fragmentId, this.version) when (this.version > 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>;
|
||||||
|
@ -122,8 +131,13 @@ function spawnUIFragmentFactory<T>(thisFacet: Facet<T>) {
|
||||||
|
|
||||||
on stop removeNodes();
|
on stop removeNodes();
|
||||||
|
|
||||||
during Observe(P.UIEvent(fragmentId, $selector: string, $eventType: string, _)) => {
|
during Observe({
|
||||||
on start updateEventListeners([ selector, eventType ], true);
|
"pattern": :pattern P.UIEvent(fragmentId,
|
||||||
|
\Q.lit($selector: string),
|
||||||
|
\Q.lit($eventType: string),
|
||||||
|
\_)
|
||||||
|
}) => {
|
||||||
|
updateEventListeners([ selector, eventType ], true);
|
||||||
on stop updateEventListeners([ selector, eventType ], false);
|
on stop updateEventListeners([ selector, eventType ], false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +147,7 @@ function spawnUIFragmentFactory<T>(thisFacet: Facet<T>) {
|
||||||
removeNodes();
|
removeNodes();
|
||||||
|
|
||||||
selector = newSelector;
|
selector = newSelector;
|
||||||
html = (newHtml as Embedded<Array<ChildNode>>).embeddedValue;
|
html = (newHtml as Embedded<Ref>).embeddedValue.target.data as ChildNode[];
|
||||||
orderBy = newOrderBy;
|
orderBy = newOrderBy;
|
||||||
anchorNodes = (selector !== null) ? selectorMatch(document.body, selector) : [];
|
anchorNodes = (selector !== null) ? selectorMatch(document.body, selector) : [];
|
||||||
|
|
||||||
|
@ -153,7 +167,7 @@ function spawnUIFragmentFactory<T>(thisFacet: Facet<T>) {
|
||||||
// (re)install event listeners
|
// (re)install event listeners
|
||||||
eventRegistrations.forEach((_handler, key) => updateEventListeners(key, true));
|
eventRegistrations.forEach((_handler, key) => updateEventListeners(key, true));
|
||||||
|
|
||||||
this.version++;
|
version.value++;
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeNodes() {
|
function removeNodes() {
|
||||||
|
@ -172,11 +186,11 @@ function spawnUIFragmentFactory<T>(thisFacet: Facet<T>) {
|
||||||
|
|
||||||
let handlerClosure: HandlerClosure;
|
let handlerClosure: HandlerClosure;
|
||||||
if (!eventRegistrations.has(key)) {
|
if (!eventRegistrations.has(key)) {
|
||||||
let sender = thisFacet.wrapExternal((thisFacet, e: Event) => {
|
const facet = Turn.activeFacet;
|
||||||
send message P.UIEvent(fragmentId, selector, eventType, embed(e));
|
|
||||||
});
|
|
||||||
function handler(event: Event) {
|
function handler(event: Event) {
|
||||||
sender(event);
|
facet.turn(() => {
|
||||||
|
send message P.UIEvent(fragmentId, selector, eventType, embed(create ({ data: event })));
|
||||||
|
});
|
||||||
return dealWithPreventDefault(eventType, event);
|
return dealWithPreventDefault(eventType, event);
|
||||||
}
|
}
|
||||||
eventRegistrations.set(key, handler);
|
eventRegistrations.set(key, handler);
|
||||||
|
@ -203,6 +217,7 @@ function spawnUIFragmentFactory<T>(thisFacet: Facet<T>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,29 +318,32 @@ function configureNode(n: ChildNode) {
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
function spawnUIAttributeFactory<T>(thisFacet: Facet<T>) {
|
function spawnUIAttributeFactory(ds: Ref) {
|
||||||
spawn named 'UIAttributeFactory' {
|
spawn named 'UIAttributeFactory' {
|
||||||
during P.UIAttribute($selector: string, $attribute: string, $value) =>
|
at ds {
|
||||||
spawn named ['UIAttribute', selector, attribute, value] {
|
during P.UIAttribute($selector: string, $attribute: string, $value) =>
|
||||||
_attributeLike(thisFacet, selector, attribute, value, 'attribute');
|
spawn named ['UIAttribute', selector, attribute, value] {
|
||||||
}
|
_attributeLike(selector, attribute, value, 'attribute');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function spawnUIPropertyFactory<T>(thisFacet: Facet<T>) {
|
function spawnUIPropertyFactory(ds: Ref) {
|
||||||
spawn named 'UIPropertyFactory' {
|
spawn named 'UIPropertyFactory' {
|
||||||
during P.UIProperty($selector: string, $property: string, $value) =>
|
at ds {
|
||||||
spawn named ['UIProperty', selector, property, value] {
|
during P.UIProperty($selector: string, $property: string, $value) =>
|
||||||
_attributeLike(thisFacet, selector, property, value, 'property');
|
spawn named ['UIProperty', selector, property, value] {
|
||||||
}
|
_attributeLike(selector, property, value, 'property');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _attributeLike<T>(thisFacet: Facet<T>,
|
function _attributeLike(selector: string,
|
||||||
selector: string,
|
key: string,
|
||||||
key: string,
|
value: AnyValue,
|
||||||
value: Value,
|
kind: 'attribute' | 'property')
|
||||||
kind: 'attribute' | 'property')
|
|
||||||
{
|
{
|
||||||
let savedValues: Array<{node: Element, value: any}> = [];
|
let savedValues: Array<{node: Element, value: any}> = [];
|
||||||
|
|
||||||
|
@ -387,7 +405,7 @@ function _attributeLike<T>(thisFacet: Facet<T>,
|
||||||
});
|
});
|
||||||
savedValues = [];
|
savedValues = [];
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
function splitClassValue(v: string | null): Array<string> {
|
function splitClassValue(v: string | null): Array<string> {
|
||||||
v = (v ?? '').trim();
|
v = (v ?? '').trim();
|
||||||
|
@ -396,22 +414,28 @@ function splitClassValue(v: string | null): Array<string> {
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
function spawnUIChangeablePropertyFactory<T>(thisFacet: Facet<T>) {
|
function spawnUIChangeablePropertyFactory(ds: Ref) {
|
||||||
spawn named 'UIChangeablePropertyFactory' {
|
spawn named 'UIChangeablePropertyFactory' {
|
||||||
during Observe(P.UIChangeableProperty($selector: string, $property: string, _)) =>
|
at ds {
|
||||||
spawn named ['UIChangeableProperty', selector, property] {
|
during Observe({
|
||||||
on start selectorMatch(document.body, selector).forEach(node => {
|
"pattern": :pattern P.UIChangeableProperty(\Q.lit($selector: string),
|
||||||
|
\Q.lit($property: string),
|
||||||
|
\_)
|
||||||
|
}) => spawn named ['UIChangeableProperty', selector, property] {
|
||||||
|
selectorMatch(document.body, selector).forEach(node => {
|
||||||
react {
|
react {
|
||||||
field value: any = (node as any)[property];
|
field propValue: any = (node as any)[property];
|
||||||
assert P.UIChangeableProperty(selector, property, this.value);
|
assert P.UIChangeableProperty(selector, property, propValue.value);
|
||||||
const handlerClosure = thisFacet.wrapExternal((_thisFacet, _e: Event) => {
|
const facet = Turn.activeFacet;
|
||||||
this.value = (node as any)[property];
|
const handlerClosure = (_e: Event) => facet.turn(() => {
|
||||||
|
propValue.value = (node as any)[property];
|
||||||
});
|
});
|
||||||
on start eventUpdater('change', handlerClosure, true)(node);
|
eventUpdater('change', handlerClosure, true)(node);
|
||||||
on stop eventUpdater('change', handlerClosure, false)(node);
|
on stop eventUpdater('change', handlerClosure, false)(node);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,56 +487,56 @@ export class Anchor {
|
||||||
}
|
}
|
||||||
|
|
||||||
html(selector: string, html: HtmlFragments, orderBy: NodeOrderKey = ''): ReturnType<typeof P.UIFragment> {
|
html(selector: string, html: HtmlFragments, orderBy: NodeOrderKey = ''): ReturnType<typeof P.UIFragment> {
|
||||||
return P.UIFragment(this.fragmentId, selector, embed(html.nodes()), orderBy);
|
return P.UIFragment(this.fragmentId, selector, embed(create ({ data: html.nodes() })), orderBy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
function spawnLocationHashTracker<T>(thisFacet: Facet<T>) {
|
function spawnLocationHashTracker(ds: Ref) {
|
||||||
spawn named 'LocationHashTracker' {
|
spawn named 'LocationHashTracker' {
|
||||||
field hashValue: string = '/';
|
at ds {
|
||||||
assert P.LocationHash(this.hashValue);
|
field hashValue: string = '/';
|
||||||
|
assert P.LocationHash(hashValue.value);
|
||||||
|
|
||||||
const loadHash = () => {
|
const loadHash = () => {
|
||||||
var h = window.location.hash;
|
var h = window.location.hash;
|
||||||
if (h.length && h[0] === '#') {
|
if (h.length && h[0] === '#') {
|
||||||
h = h.slice(1);
|
h = h.slice(1);
|
||||||
}
|
}
|
||||||
this.hashValue = h || '/';
|
hashValue.value = h || '/';
|
||||||
};
|
};
|
||||||
|
const facet = Turn.activeFacet;
|
||||||
|
const handlerClosure = () => facet.turn(loadHash);
|
||||||
|
|
||||||
let handlerClosure = thisFacet.wrapExternal(loadHash);
|
|
||||||
|
|
||||||
on start {
|
|
||||||
loadHash();
|
loadHash();
|
||||||
window.addEventListener('hashchange', handlerClosure);
|
window.addEventListener('hashchange', handlerClosure);
|
||||||
}
|
on stop window.removeEventListener('hashchange', handlerClosure);
|
||||||
on stop {
|
|
||||||
window.removeEventListener('hashchange', handlerClosure);
|
|
||||||
}
|
|
||||||
|
|
||||||
on message P.SetLocationHash($newHash: string) => {
|
on message P.SetLocationHash($newHash: string) => {
|
||||||
window.location.hash = newHash;
|
window.location.hash = newHash;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
function spawnAttributeUpdater<T>(thisFacet: Facet<T>) {
|
function spawnAttributeUpdater(ds: Ref) {
|
||||||
spawn named 'AttributeUpdater' {
|
spawn named 'AttributeUpdater' {
|
||||||
on message P.SetAttribute($s: string, $k: string, $v: string) =>
|
at ds {
|
||||||
update(s, n => n.setAttribute(k, v));
|
on message P.SetAttribute($s: string, $k: string, $v: string) =>
|
||||||
on message P.RemoveAttribute($s: string, $k: string) =>
|
update(s, n => n.setAttribute(k, v));
|
||||||
update(s, n => n.removeAttribute(k));
|
on message P.RemoveAttribute($s: string, $k: string) =>
|
||||||
on message P.SetProperty($s: string, $k: string, $v) =>
|
update(s, n => n.removeAttribute(k));
|
||||||
update(s, n => { (n as any)[k] = v });
|
on message P.SetProperty($s: string, $k: string, $v) =>
|
||||||
on message P.RemoveProperty($s: string, $k: string) =>
|
update(s, n => { (n as any)[k] = v });
|
||||||
update(s, n => { delete (n as any)[k]; });
|
on message P.RemoveProperty($s: string, $k: string) =>
|
||||||
|
update(s, n => { delete (n as any)[k]; });
|
||||||
|
|
||||||
function update(selector: string, nodeUpdater: (n: Element) => void) {
|
function update(selector: string, nodeUpdater: (n: Element) => void) {
|
||||||
selectorMatch(document.body, selector).forEach(nodeUpdater);
|
selectorMatch(document.body, selector).forEach(nodeUpdater);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue