@thomas-siegfried/tapout 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +1205 -1205
  3. package/package.json +55 -55
  4. package/src/applyBindings.ts +372 -372
  5. package/src/arrayToDomMapping.ts +300 -300
  6. package/src/attributeInterpolationMarkup.ts +91 -91
  7. package/src/bindingContext.ts +207 -207
  8. package/src/bindingEvent.ts +198 -198
  9. package/src/bindingProvider.ts +260 -260
  10. package/src/bindings.ts +963 -963
  11. package/src/compareArrays.ts +122 -122
  12. package/src/componentBinding.ts +318 -318
  13. package/src/componentDecorator.ts +62 -62
  14. package/src/components.ts +367 -367
  15. package/src/computed.ts +439 -439
  16. package/src/configure.ts +52 -52
  17. package/src/controlFlowBindings.ts +206 -206
  18. package/src/core.ts +60 -60
  19. package/src/decorators.ts +407 -407
  20. package/src/dependencyDetection.ts +76 -76
  21. package/src/disposable.ts +36 -36
  22. package/src/domData.ts +42 -42
  23. package/src/domNodeDisposal.ts +94 -94
  24. package/src/effects.ts +29 -29
  25. package/src/event.ts +173 -173
  26. package/src/expressionRewriting.ts +219 -219
  27. package/src/extenders.ts +102 -102
  28. package/src/filters.ts +91 -91
  29. package/src/index.ts +150 -150
  30. package/src/interpolationMarkup.ts +130 -130
  31. package/src/memoization.ts +71 -71
  32. package/src/namespacedBindings.ts +132 -132
  33. package/src/observable.ts +48 -48
  34. package/src/observableArray.ts +397 -397
  35. package/src/options.ts +25 -25
  36. package/src/selectExtensions.ts +68 -68
  37. package/src/slotBinding.ts +84 -84
  38. package/src/subscribable.ts +266 -266
  39. package/src/tasks.ts +79 -79
  40. package/src/templateEngine.ts +108 -108
  41. package/src/templateRendering.ts +399 -399
  42. package/src/templateRewriting.ts +94 -94
  43. package/src/templateSources.ts +134 -134
  44. package/src/utils.ts +123 -123
  45. package/src/utilsDom.ts +87 -87
  46. package/src/virtualElements.ts +153 -153
  47. package/src/wireParams.ts +49 -49
@@ -1,94 +1,94 @@
1
- import { parseObjectLiteral, preProcessBindings } from './expressionRewriting.js';
2
- import type { KeyValuePair } from './expressionRewriting.js';
3
- import { memoize } from './memoization.js';
4
- import type { TemplateEngine } from './templateEngine.js';
5
- import type { BindingContext } from './bindingContext.js';
6
- import { applyBindingAccessorsToNode } from './applyBindings.js';
7
-
8
- const memoizeDataBindingAttributeSyntaxRegex =
9
- /(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:"[^"]*"|'[^']*'|[^>]*))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi;
10
-
11
- const memoizeVirtualContainerBindingSyntaxRegex =
12
- /<!--\s*tap\b\s*([\s\S]*?)\s*-->/g;
13
-
14
- export const bindingRewriteValidators: Record<string, boolean | ((value: string) => string | void)> = {};
15
-
16
- function validateDataBindValuesForRewriting(keyValueArray: KeyValuePair[]): void {
17
- for (const kv of keyValueArray) {
18
- const key = kv.key;
19
- if (key && Object.prototype.hasOwnProperty.call(bindingRewriteValidators, key)) {
20
- const validator = bindingRewriteValidators[key];
21
- if (typeof validator === 'function') {
22
- const msg = validator(kv.value || '');
23
- if (msg) throw new Error(msg);
24
- } else if (!validator) {
25
- throw new Error("This template engine does not support the '" + key + "' binding within its templates");
26
- }
27
- }
28
- }
29
- }
30
-
31
- function constructMemoizedTagReplacement(
32
- dataBindAttributeValue: string,
33
- tagToRetain: string,
34
- nodeName: string,
35
- templateEngine: TemplateEngine,
36
- ): string {
37
- const dataBindKeyValueArray = parseObjectLiteral(dataBindAttributeValue);
38
- validateDataBindValuesForRewriting(dataBindKeyValueArray);
39
- const rewrittenDataBindAttributeValue = preProcessBindings(dataBindKeyValueArray, { valueAccessors: true });
40
-
41
- const applyBindingsToNextSiblingScript =
42
- "tap.__tr_ambtns(function($context,$element){return(function(){return{ " +
43
- rewrittenDataBindAttributeValue +
44
- " } })()},'" + nodeName.toLowerCase() + "')";
45
- return templateEngine.createJavaScriptEvaluatorBlock(applyBindingsToNextSiblingScript) + tagToRetain;
46
- }
47
-
48
- export function ensureTemplateIsRewritten(
49
- template: string | Node,
50
- templateEngine: TemplateEngine,
51
- templateDocument?: Document,
52
- ): void {
53
- if (!templateEngine.isTemplateRewritten(template, templateDocument)) {
54
- templateEngine.rewriteTemplate(template, (htmlString) => {
55
- return memoizeBindingAttributeSyntax(htmlString, templateEngine);
56
- }, templateDocument);
57
- }
58
- }
59
-
60
- export function memoizeBindingAttributeSyntax(
61
- htmlString: string,
62
- templateEngine: TemplateEngine,
63
- ): string {
64
- return htmlString
65
- .replace(memoizeDataBindingAttributeSyntaxRegex, function () {
66
- return constructMemoizedTagReplacement(
67
- arguments[4], // dataBindAttributeValue
68
- arguments[1], // tagToRetain
69
- arguments[2], // nodeName
70
- templateEngine,
71
- );
72
- })
73
- .replace(memoizeVirtualContainerBindingSyntaxRegex, function () {
74
- return constructMemoizedTagReplacement(
75
- arguments[1], // dataBindAttributeValue
76
- '<!-- tap -->', // tagToRetain
77
- '#comment', // nodeName
78
- templateEngine,
79
- );
80
- });
81
- }
82
-
83
- export function applyMemoizedBindingsToNextSibling(
84
- bindings: ((ctx: BindingContext, el: Node) => Record<string, () => unknown>),
85
- nodeName: string,
86
- ): string {
87
- return memoize(function (domNode: unknown, bindingContext: unknown) {
88
- const node = domNode as Node;
89
- const nodeToBind = node.nextSibling;
90
- if (nodeToBind && nodeToBind.nodeName.toLowerCase() === nodeName) {
91
- applyBindingAccessorsToNode(nodeToBind, bindings, bindingContext);
92
- }
93
- });
94
- }
1
+ import { parseObjectLiteral, preProcessBindings } from './expressionRewriting.js';
2
+ import type { KeyValuePair } from './expressionRewriting.js';
3
+ import { memoize } from './memoization.js';
4
+ import type { TemplateEngine } from './templateEngine.js';
5
+ import type { BindingContext } from './bindingContext.js';
6
+ import { applyBindingAccessorsToNode } from './applyBindings.js';
7
+
8
+ const memoizeDataBindingAttributeSyntaxRegex =
9
+ /(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:"[^"]*"|'[^']*'|[^>]*))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi;
10
+
11
+ const memoizeVirtualContainerBindingSyntaxRegex =
12
+ /<!--\s*tap\b\s*([\s\S]*?)\s*-->/g;
13
+
14
+ export const bindingRewriteValidators: Record<string, boolean | ((value: string) => string | void)> = {};
15
+
16
+ function validateDataBindValuesForRewriting(keyValueArray: KeyValuePair[]): void {
17
+ for (const kv of keyValueArray) {
18
+ const key = kv.key;
19
+ if (key && Object.prototype.hasOwnProperty.call(bindingRewriteValidators, key)) {
20
+ const validator = bindingRewriteValidators[key];
21
+ if (typeof validator === 'function') {
22
+ const msg = validator(kv.value || '');
23
+ if (msg) throw new Error(msg);
24
+ } else if (!validator) {
25
+ throw new Error("This template engine does not support the '" + key + "' binding within its templates");
26
+ }
27
+ }
28
+ }
29
+ }
30
+
31
+ function constructMemoizedTagReplacement(
32
+ dataBindAttributeValue: string,
33
+ tagToRetain: string,
34
+ nodeName: string,
35
+ templateEngine: TemplateEngine,
36
+ ): string {
37
+ const dataBindKeyValueArray = parseObjectLiteral(dataBindAttributeValue);
38
+ validateDataBindValuesForRewriting(dataBindKeyValueArray);
39
+ const rewrittenDataBindAttributeValue = preProcessBindings(dataBindKeyValueArray, { valueAccessors: true });
40
+
41
+ const applyBindingsToNextSiblingScript =
42
+ "tap.__tr_ambtns(function($context,$element){return(function(){return{ " +
43
+ rewrittenDataBindAttributeValue +
44
+ " } })()},'" + nodeName.toLowerCase() + "')";
45
+ return templateEngine.createJavaScriptEvaluatorBlock(applyBindingsToNextSiblingScript) + tagToRetain;
46
+ }
47
+
48
+ export function ensureTemplateIsRewritten(
49
+ template: string | Node,
50
+ templateEngine: TemplateEngine,
51
+ templateDocument?: Document,
52
+ ): void {
53
+ if (!templateEngine.isTemplateRewritten(template, templateDocument)) {
54
+ templateEngine.rewriteTemplate(template, (htmlString) => {
55
+ return memoizeBindingAttributeSyntax(htmlString, templateEngine);
56
+ }, templateDocument);
57
+ }
58
+ }
59
+
60
+ export function memoizeBindingAttributeSyntax(
61
+ htmlString: string,
62
+ templateEngine: TemplateEngine,
63
+ ): string {
64
+ return htmlString
65
+ .replace(memoizeDataBindingAttributeSyntaxRegex, function () {
66
+ return constructMemoizedTagReplacement(
67
+ arguments[4], // dataBindAttributeValue
68
+ arguments[1], // tagToRetain
69
+ arguments[2], // nodeName
70
+ templateEngine,
71
+ );
72
+ })
73
+ .replace(memoizeVirtualContainerBindingSyntaxRegex, function () {
74
+ return constructMemoizedTagReplacement(
75
+ arguments[1], // dataBindAttributeValue
76
+ '<!-- tap -->', // tagToRetain
77
+ '#comment', // nodeName
78
+ templateEngine,
79
+ );
80
+ });
81
+ }
82
+
83
+ export function applyMemoizedBindingsToNextSibling(
84
+ bindings: ((ctx: BindingContext, el: Node) => Record<string, () => unknown>),
85
+ nodeName: string,
86
+ ): string {
87
+ return memoize(function (domNode: unknown, bindingContext: unknown) {
88
+ const node = domNode as Node;
89
+ const nodeToBind = node.nextSibling;
90
+ if (nodeToBind && nodeToBind.nodeName.toLowerCase() === nodeName) {
91
+ applyBindingAccessorsToNode(nodeToBind, bindings, bindingContext);
92
+ }
93
+ });
94
+ }
@@ -1,134 +1,134 @@
1
- import { domDataGet, domDataSet, domDataNextKey } from './domData.js';
2
- import { parseHtmlFragment } from './utilsDom.js';
3
-
4
- const enum TemplateType {
5
- Script = 1,
6
- TextArea = 2,
7
- Template = 3,
8
- Element = 4,
9
- }
10
-
11
- const dataDomDataPrefix = domDataNextKey();
12
- const templatesDomDataKey = domDataNextKey();
13
-
14
- interface TemplateDomData {
15
- containerData?: DocumentFragment | HTMLElement;
16
- alwaysCheckText?: boolean;
17
- textData?: string;
18
- }
19
-
20
- function getTemplateDomData(element: Node): TemplateDomData {
21
- return (domDataGet(element, templatesDomDataKey) as TemplateDomData) || {};
22
- }
23
-
24
- function setTemplateDomData(element: Node, data: TemplateDomData): void {
25
- domDataSet(element, templatesDomDataKey, data);
26
- }
27
-
28
- export class DomElementSource {
29
- readonly domElement: Element;
30
- private templateType: TemplateType;
31
-
32
- constructor(element: Element) {
33
- this.domElement = element;
34
- const tagName = element.tagName?.toLowerCase();
35
- this.templateType =
36
- tagName === 'script' ? TemplateType.Script :
37
- tagName === 'textarea' ? TemplateType.TextArea :
38
- tagName === 'template' && (element as HTMLTemplateElement).content &&
39
- (element as HTMLTemplateElement).content.nodeType === 11 ? TemplateType.Template :
40
- TemplateType.Element;
41
- }
42
-
43
- text(): string;
44
- text(value: string): void;
45
- text(value?: string): string | void {
46
- const prop = this.templateType === TemplateType.Script ? 'text'
47
- : this.templateType === TemplateType.TextArea ? 'value'
48
- : 'innerHTML';
49
-
50
- if (arguments.length === 0) {
51
- return (this.domElement as unknown as Record<string, unknown>)[prop] as string;
52
- } else {
53
- (this.domElement as unknown as Record<string, unknown>)[prop] = value;
54
- }
55
- }
56
-
57
- data(key: string): unknown;
58
- data(key: string, value: unknown): void;
59
- data(key: string, value?: unknown): unknown | void {
60
- if (arguments.length === 1) {
61
- return domDataGet(this.domElement, dataDomDataPrefix + key);
62
- } else {
63
- domDataSet(this.domElement, dataDomDataPrefix + key, value);
64
- }
65
- }
66
-
67
- nodes(): DocumentFragment | HTMLElement | undefined;
68
- nodes(value: DocumentFragment | HTMLElement): void;
69
- nodes(value?: DocumentFragment | HTMLElement): DocumentFragment | HTMLElement | undefined | void {
70
- const element = this.domElement;
71
- if (arguments.length === 0) {
72
- const templateData = getTemplateDomData(element);
73
- let nodes = templateData.containerData || (
74
- this.templateType === TemplateType.Template ? (element as HTMLTemplateElement).content :
75
- this.templateType === TemplateType.Element ? element as HTMLElement :
76
- undefined
77
- );
78
-
79
- if (!nodes || templateData.alwaysCheckText) {
80
- const text = this.text();
81
- if (text && text !== templateData.textData) {
82
- const parsed = parseHtmlFragment(text, element.ownerDocument);
83
- const container = element.ownerDocument.createElement('div');
84
- for (const n of parsed) container.appendChild(n);
85
- setTemplateDomData(element, {
86
- containerData: container,
87
- textData: text,
88
- alwaysCheckText: true,
89
- });
90
- nodes = container;
91
- }
92
- }
93
- return nodes;
94
- } else {
95
- const templateData = getTemplateDomData(element);
96
- templateData.containerData = value;
97
- setTemplateDomData(element, templateData);
98
- }
99
- }
100
- }
101
-
102
- export class AnonymousSource extends DomElementSource {
103
- constructor(element: Element | Comment) {
104
- super(element as Element);
105
- }
106
-
107
- override text(): string;
108
- override text(value: string): void;
109
- override text(value?: string): string | void {
110
- if (arguments.length === 0) {
111
- const data = domDataGet(this.domElement, dataDomDataPrefix + 'anonymousTemplateText') as string | undefined;
112
- if (data === undefined) {
113
- const nodesContainer = this.nodes();
114
- if (nodesContainer) {
115
- return (nodesContainer as HTMLElement).innerHTML;
116
- }
117
- }
118
- return data as string;
119
- } else {
120
- domDataSet(this.domElement, dataDomDataPrefix + 'anonymousTemplateText', value);
121
- }
122
- }
123
-
124
- override nodes(): DocumentFragment | HTMLElement | undefined;
125
- override nodes(value: DocumentFragment | HTMLElement): void;
126
- override nodes(value?: DocumentFragment | HTMLElement): DocumentFragment | HTMLElement | undefined | void {
127
- if (arguments.length === 0) {
128
- const containerData = getTemplateDomData(this.domElement).containerData;
129
- return containerData;
130
- } else {
131
- setTemplateDomData(this.domElement, { containerData: value });
132
- }
133
- }
134
- }
1
+ import { domDataGet, domDataSet, domDataNextKey } from './domData.js';
2
+ import { parseHtmlFragment } from './utilsDom.js';
3
+
4
+ const enum TemplateType {
5
+ Script = 1,
6
+ TextArea = 2,
7
+ Template = 3,
8
+ Element = 4,
9
+ }
10
+
11
+ const dataDomDataPrefix = domDataNextKey();
12
+ const templatesDomDataKey = domDataNextKey();
13
+
14
+ interface TemplateDomData {
15
+ containerData?: DocumentFragment | HTMLElement;
16
+ alwaysCheckText?: boolean;
17
+ textData?: string;
18
+ }
19
+
20
+ function getTemplateDomData(element: Node): TemplateDomData {
21
+ return (domDataGet(element, templatesDomDataKey) as TemplateDomData) || {};
22
+ }
23
+
24
+ function setTemplateDomData(element: Node, data: TemplateDomData): void {
25
+ domDataSet(element, templatesDomDataKey, data);
26
+ }
27
+
28
+ export class DomElementSource {
29
+ readonly domElement: Element;
30
+ private templateType: TemplateType;
31
+
32
+ constructor(element: Element) {
33
+ this.domElement = element;
34
+ const tagName = element.tagName?.toLowerCase();
35
+ this.templateType =
36
+ tagName === 'script' ? TemplateType.Script :
37
+ tagName === 'textarea' ? TemplateType.TextArea :
38
+ tagName === 'template' && (element as HTMLTemplateElement).content &&
39
+ (element as HTMLTemplateElement).content.nodeType === 11 ? TemplateType.Template :
40
+ TemplateType.Element;
41
+ }
42
+
43
+ text(): string;
44
+ text(value: string): void;
45
+ text(value?: string): string | void {
46
+ const prop = this.templateType === TemplateType.Script ? 'text'
47
+ : this.templateType === TemplateType.TextArea ? 'value'
48
+ : 'innerHTML';
49
+
50
+ if (arguments.length === 0) {
51
+ return (this.domElement as unknown as Record<string, unknown>)[prop] as string;
52
+ } else {
53
+ (this.domElement as unknown as Record<string, unknown>)[prop] = value;
54
+ }
55
+ }
56
+
57
+ data(key: string): unknown;
58
+ data(key: string, value: unknown): void;
59
+ data(key: string, value?: unknown): unknown | void {
60
+ if (arguments.length === 1) {
61
+ return domDataGet(this.domElement, dataDomDataPrefix + key);
62
+ } else {
63
+ domDataSet(this.domElement, dataDomDataPrefix + key, value);
64
+ }
65
+ }
66
+
67
+ nodes(): DocumentFragment | HTMLElement | undefined;
68
+ nodes(value: DocumentFragment | HTMLElement): void;
69
+ nodes(value?: DocumentFragment | HTMLElement): DocumentFragment | HTMLElement | undefined | void {
70
+ const element = this.domElement;
71
+ if (arguments.length === 0) {
72
+ const templateData = getTemplateDomData(element);
73
+ let nodes = templateData.containerData || (
74
+ this.templateType === TemplateType.Template ? (element as HTMLTemplateElement).content :
75
+ this.templateType === TemplateType.Element ? element as HTMLElement :
76
+ undefined
77
+ );
78
+
79
+ if (!nodes || templateData.alwaysCheckText) {
80
+ const text = this.text();
81
+ if (text && text !== templateData.textData) {
82
+ const parsed = parseHtmlFragment(text, element.ownerDocument);
83
+ const container = element.ownerDocument.createElement('div');
84
+ for (const n of parsed) container.appendChild(n);
85
+ setTemplateDomData(element, {
86
+ containerData: container,
87
+ textData: text,
88
+ alwaysCheckText: true,
89
+ });
90
+ nodes = container;
91
+ }
92
+ }
93
+ return nodes;
94
+ } else {
95
+ const templateData = getTemplateDomData(element);
96
+ templateData.containerData = value;
97
+ setTemplateDomData(element, templateData);
98
+ }
99
+ }
100
+ }
101
+
102
+ export class AnonymousSource extends DomElementSource {
103
+ constructor(element: Element | Comment) {
104
+ super(element as Element);
105
+ }
106
+
107
+ override text(): string;
108
+ override text(value: string): void;
109
+ override text(value?: string): string | void {
110
+ if (arguments.length === 0) {
111
+ const data = domDataGet(this.domElement, dataDomDataPrefix + 'anonymousTemplateText') as string | undefined;
112
+ if (data === undefined) {
113
+ const nodesContainer = this.nodes();
114
+ if (nodesContainer) {
115
+ return (nodesContainer as HTMLElement).innerHTML;
116
+ }
117
+ }
118
+ return data as string;
119
+ } else {
120
+ domDataSet(this.domElement, dataDomDataPrefix + 'anonymousTemplateText', value);
121
+ }
122
+ }
123
+
124
+ override nodes(): DocumentFragment | HTMLElement | undefined;
125
+ override nodes(value: DocumentFragment | HTMLElement): void;
126
+ override nodes(value?: DocumentFragment | HTMLElement): DocumentFragment | HTMLElement | undefined | void {
127
+ if (arguments.length === 0) {
128
+ const containerData = getTemplateDomData(this.domElement).containerData;
129
+ return containerData;
130
+ } else {
131
+ setTemplateDomData(this.domElement, { containerData: value });
132
+ }
133
+ }
134
+ }