@microsoft/fast-html 1.0.0-alpha.16 → 1.0.0-alpha.18
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.
- package/dist/dts/components/element.d.ts +10 -10
- package/dist/dts/components/index.d.ts +1 -0
- package/dist/dts/components/observer-map.d.ts +143 -0
- package/dist/dts/components/observer-map.spec.d.ts +1 -0
- package/dist/dts/components/template.d.ts +11 -0
- package/dist/dts/components/utilities.d.ts +60 -1
- package/dist/dts/fixtures/observer-map/main.d.ts +1 -0
- package/dist/dts/fixtures/observer-map/observer-map.spec.d.ts +1 -0
- package/dist/dts/index.d.ts +1 -1
- package/dist/esm/components/element.js +24 -17
- package/dist/esm/components/index.js +1 -0
- package/dist/esm/components/observer-map.js +551 -0
- package/dist/esm/components/observer-map.spec.js +613 -0
- package/dist/esm/components/template.js +103 -85
- package/dist/esm/components/utilities.js +301 -50
- package/dist/esm/components/utilities.spec.js +109 -1
- package/dist/esm/fixtures/attribute/main.js +3 -3
- package/dist/esm/fixtures/binding/main.js +5 -5
- package/dist/esm/fixtures/children/main.js +3 -3
- package/dist/esm/fixtures/dot-syntax/dot-syntax.spec.js +109 -2
- package/dist/esm/fixtures/dot-syntax/main.js +30 -4
- package/dist/esm/fixtures/event/main.js +6 -6
- package/dist/esm/fixtures/observer-map/main.js +304 -0
- package/dist/esm/fixtures/observer-map/observer-map.spec.js +174 -0
- package/dist/esm/fixtures/partial/main.js +3 -2
- package/dist/esm/fixtures/ref/main.js +3 -2
- package/dist/esm/fixtures/repeat/main.js +5 -5
- package/dist/esm/fixtures/slotted/main.js +3 -3
- package/dist/esm/fixtures/when/main.js +21 -21
- package/dist/esm/index.js +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/fast-html.api.json +247 -32
- package/dist/fast-html.d.ts +214 -6
- package/dist/fast-html.untrimmed.d.ts +214 -6
- package/package.json +5 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __decorate, __metadata } from "tslib";
|
|
2
2
|
import { RenderableFASTElement, TemplateElement } from "@microsoft/fast-html";
|
|
3
|
-
import { observable } from "@microsoft/fast-element";
|
|
4
|
-
class TestElement extends
|
|
3
|
+
import { FASTElement, observable } from "@microsoft/fast-element";
|
|
4
|
+
class TestElement extends FASTElement {
|
|
5
5
|
constructor() {
|
|
6
6
|
super(...arguments);
|
|
7
7
|
this.listItems = [];
|
|
@@ -16,7 +16,7 @@ __decorate([
|
|
|
16
16
|
observable,
|
|
17
17
|
__metadata("design:type", Array)
|
|
18
18
|
], TestElement.prototype, "list", void 0);
|
|
19
|
-
TestElement.defineAsync({
|
|
19
|
+
RenderableFASTElement(TestElement).defineAsync({
|
|
20
20
|
name: "test-element",
|
|
21
21
|
templateOptions: "defer-and-hydrate",
|
|
22
22
|
});
|
|
@@ -1,9 +1,116 @@
|
|
|
1
1
|
import { __awaiter } from "tslib";
|
|
2
2
|
import { expect, test } from "@playwright/test";
|
|
3
|
-
test.describe("f-template", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
3
|
+
test.describe("f-template dot-syntax bindings", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
4
4
|
test("create a object property reference using dot syntax in a binding", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
5
5
|
yield page.goto("/dot-syntax");
|
|
6
6
|
const customElement = yield page.locator("test-element");
|
|
7
|
-
yield expect(customElement).toHaveText("bar");
|
|
7
|
+
yield expect(customElement.locator("span").nth(0)).toHaveText("bar");
|
|
8
|
+
}));
|
|
9
|
+
test("should display initial property values correctly", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
10
|
+
yield page.goto("/dot-syntax");
|
|
11
|
+
const customElement = yield page.locator("test-element");
|
|
12
|
+
// Check initial values
|
|
13
|
+
yield expect(customElement.locator("span").nth(0)).toHaveText("bar");
|
|
14
|
+
yield expect(customElement.locator("span").nth(1)).toHaveText("");
|
|
15
|
+
yield expect(customElement.locator("span").nth(2)).toHaveText("FOO");
|
|
16
|
+
}));
|
|
17
|
+
test("should update object.b when 'Set b' button is clicked", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
18
|
+
yield page.goto("/dot-syntax");
|
|
19
|
+
const customElement = yield page.locator("test-element");
|
|
20
|
+
const setBButton = customElement.locator("button").nth(0);
|
|
21
|
+
const bSpan = customElement.locator("span").nth(0);
|
|
22
|
+
// Verify initial state
|
|
23
|
+
yield expect(bSpan).toHaveText("bar");
|
|
24
|
+
// Click the "Set b" button
|
|
25
|
+
yield setBButton.click();
|
|
26
|
+
// Verify the value updated
|
|
27
|
+
yield expect(bSpan).toHaveText("Hello");
|
|
28
|
+
}));
|
|
29
|
+
test("should update object.a.b1 when 'Set a.b1' button is clicked", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
30
|
+
yield page.goto("/dot-syntax");
|
|
31
|
+
const customElement = yield page.locator("test-element");
|
|
32
|
+
const setAB1Button = customElement.locator("button").nth(1);
|
|
33
|
+
const ab1Span = customElement.locator("span").nth(1);
|
|
34
|
+
// Verify initial state (should be empty/undefined)
|
|
35
|
+
yield expect(ab1Span).toHaveText("");
|
|
36
|
+
// Click the "Set a.b1" button
|
|
37
|
+
yield setAB1Button.click();
|
|
38
|
+
// Verify the value updated
|
|
39
|
+
yield expect(ab1Span).toHaveText("World");
|
|
40
|
+
}));
|
|
41
|
+
test("should update object.a.b2.c when 'Set a.b2.c' button is clicked", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
42
|
+
yield page.goto("/dot-syntax");
|
|
43
|
+
const customElement = yield page.locator("test-element");
|
|
44
|
+
const setAB2CButton = customElement.locator("button").nth(2);
|
|
45
|
+
const ab2cSpan = customElement.locator("span").nth(2);
|
|
46
|
+
// Click the "Set a.b2.c" button
|
|
47
|
+
yield setAB2CButton.click();
|
|
48
|
+
// Verify the value updated
|
|
49
|
+
yield expect(ab2cSpan).toHaveText("Pluto");
|
|
50
|
+
}));
|
|
51
|
+
test("should handle multiple property updates independently", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
52
|
+
yield page.goto("/dot-syntax");
|
|
53
|
+
const customElement = yield page.locator("test-element");
|
|
54
|
+
const setBButton = customElement.locator("button").nth(0);
|
|
55
|
+
const setAB1Button = customElement.locator("button").nth(1);
|
|
56
|
+
const setAB2CButton = customElement.locator("button").nth(2);
|
|
57
|
+
const bSpan = customElement.locator("span").nth(0);
|
|
58
|
+
const ab1Span = customElement.locator("span").nth(1);
|
|
59
|
+
const ab2cSpan = customElement.locator("span").nth(2);
|
|
60
|
+
// Update multiple properties
|
|
61
|
+
yield setBButton.click();
|
|
62
|
+
yield setAB1Button.click();
|
|
63
|
+
yield setAB2CButton.click();
|
|
64
|
+
// Verify all values are updated correctly
|
|
65
|
+
yield expect(bSpan).toHaveText("Hello");
|
|
66
|
+
yield expect(ab1Span).toHaveText("World");
|
|
67
|
+
yield expect(ab2cSpan).toHaveText("Pluto");
|
|
68
|
+
}));
|
|
69
|
+
test("should maintain property values after multiple clicks", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
70
|
+
yield page.goto("/dot-syntax");
|
|
71
|
+
const customElement = yield page.locator("test-element");
|
|
72
|
+
const setBButton = customElement.locator("button").nth(0);
|
|
73
|
+
const bSpan = customElement.locator("span").nth(0);
|
|
74
|
+
// Click multiple times to ensure consistency
|
|
75
|
+
yield setBButton.click();
|
|
76
|
+
yield expect(bSpan).toHaveText("Hello");
|
|
77
|
+
yield setBButton.click();
|
|
78
|
+
yield expect(bSpan).toHaveText("Hello"); // Should remain the same
|
|
79
|
+
yield setBButton.click();
|
|
80
|
+
yield expect(bSpan).toHaveText("Hello"); // Should still be the same
|
|
81
|
+
}));
|
|
82
|
+
test("should update nested properties correctly", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
83
|
+
yield page.goto("/dot-syntax");
|
|
84
|
+
const customElement = yield page.locator("test-element");
|
|
85
|
+
const setAB1Button = customElement.locator("button").nth(1);
|
|
86
|
+
const setAB2CButton = customElement.locator("button").nth(2);
|
|
87
|
+
const ab1Span = customElement.locator("span").nth(1);
|
|
88
|
+
const ab2cSpan = customElement.locator("span").nth(2);
|
|
89
|
+
// Test nested property updates
|
|
90
|
+
yield setAB1Button.click();
|
|
91
|
+
yield expect(ab1Span).toHaveText("World");
|
|
92
|
+
yield setAB2CButton.click();
|
|
93
|
+
yield expect(ab2cSpan).toHaveText("Pluto");
|
|
94
|
+
// Verify both nested properties coexist
|
|
95
|
+
yield expect(ab1Span).toHaveText("World");
|
|
96
|
+
yield expect(ab2cSpan).toHaveText("Pluto");
|
|
97
|
+
}));
|
|
98
|
+
test("should have correct button labels", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
99
|
+
yield page.goto("/dot-syntax");
|
|
100
|
+
const customElement = yield page.locator("test-element");
|
|
101
|
+
// Verify button labels
|
|
102
|
+
yield expect(customElement.locator("button").nth(0)).toHaveText("Set b");
|
|
103
|
+
yield expect(customElement.locator("button").nth(1)).toHaveText("Set a.b1");
|
|
104
|
+
yield expect(customElement.locator("button").nth(2)).toHaveText("Set a.b2.c");
|
|
105
|
+
}));
|
|
106
|
+
test("should reflect property changes in DOM immediately", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
107
|
+
yield page.goto("/dot-syntax");
|
|
108
|
+
const customElement = yield page.locator("test-element");
|
|
109
|
+
const setBButton = customElement.locator("button").nth(0);
|
|
110
|
+
const bSpan = customElement.locator("span").nth(0);
|
|
111
|
+
// Verify immediate DOM update without additional waiting
|
|
112
|
+
yield setBButton.click();
|
|
113
|
+
// Should update immediately due to reactive system
|
|
114
|
+
yield expect(bSpan).toHaveText("Hello", { timeout: 1000 });
|
|
8
115
|
}));
|
|
9
116
|
}));
|
|
@@ -1,16 +1,42 @@
|
|
|
1
|
+
import { FASTElement } from "@microsoft/fast-element";
|
|
1
2
|
import { RenderableFASTElement, TemplateElement } from "@microsoft/fast-html";
|
|
2
|
-
class TestElement extends
|
|
3
|
+
class TestElement extends FASTElement {
|
|
3
4
|
constructor() {
|
|
4
5
|
super(...arguments);
|
|
5
6
|
this.object = {
|
|
6
|
-
|
|
7
|
+
b: "bar",
|
|
8
|
+
a: {
|
|
9
|
+
b2: {
|
|
10
|
+
c: "FOO",
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
this.handleBClick = () => {
|
|
15
|
+
this.object.b = "Hello";
|
|
16
|
+
};
|
|
17
|
+
this.handleAB1Click = () => {
|
|
18
|
+
if (this.object.a) {
|
|
19
|
+
this.object.a.b1 = "World";
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
this.object.a = {
|
|
23
|
+
b1: "World",
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
this.handleAB2CClick = () => {
|
|
28
|
+
this.object.a.b2.c = "Pluto";
|
|
7
29
|
};
|
|
8
30
|
}
|
|
9
31
|
}
|
|
10
|
-
TestElement.defineAsync({
|
|
32
|
+
RenderableFASTElement(TestElement).defineAsync({
|
|
11
33
|
name: "test-element",
|
|
12
34
|
templateOptions: "defer-and-hydrate",
|
|
13
35
|
});
|
|
14
|
-
TemplateElement.
|
|
36
|
+
TemplateElement.options({
|
|
37
|
+
"test-element": {
|
|
38
|
+
observerMap: "all",
|
|
39
|
+
},
|
|
40
|
+
}).define({
|
|
15
41
|
name: "f-template",
|
|
16
42
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __decorate, __metadata } from "tslib";
|
|
2
2
|
import { RenderableFASTElement, TemplateElement } from "@microsoft/fast-html";
|
|
3
|
-
import { attr } from "@microsoft/fast-element";
|
|
4
|
-
class TestElement extends
|
|
3
|
+
import { attr, FASTElement } from "@microsoft/fast-element";
|
|
4
|
+
class TestElement extends FASTElement {
|
|
5
5
|
constructor() {
|
|
6
6
|
super(...arguments);
|
|
7
7
|
this.foo = "";
|
|
@@ -14,16 +14,16 @@ class TestElement extends RenderableFASTElement {
|
|
|
14
14
|
this.handleAttributeArgClick = (foo) => {
|
|
15
15
|
console.log(foo);
|
|
16
16
|
};
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
this.handleModifyAttributeClick = () => {
|
|
18
|
+
this.foo = "modified-by-click";
|
|
19
|
+
};
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
__decorate([
|
|
23
23
|
attr,
|
|
24
24
|
__metadata("design:type", String)
|
|
25
25
|
], TestElement.prototype, "foo", void 0);
|
|
26
|
-
TestElement.defineAsync({
|
|
26
|
+
RenderableFASTElement(TestElement).defineAsync({
|
|
27
27
|
name: "test-element",
|
|
28
28
|
templateOptions: "defer-and-hydrate",
|
|
29
29
|
});
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { FASTElement } from "@microsoft/fast-element";
|
|
2
|
+
import { RenderableFASTElement, TemplateElement } from "../../components/index.js";
|
|
3
|
+
class ObserverMapTestElement extends FASTElement {
|
|
4
|
+
constructor() {
|
|
5
|
+
super(...arguments);
|
|
6
|
+
this.users = [
|
|
7
|
+
{
|
|
8
|
+
id: 1,
|
|
9
|
+
name: "Alice Johnson",
|
|
10
|
+
details: {
|
|
11
|
+
personal: {
|
|
12
|
+
age: 28,
|
|
13
|
+
location: {
|
|
14
|
+
city: "New York",
|
|
15
|
+
country: "USA",
|
|
16
|
+
coordinates: {
|
|
17
|
+
lat: 40.7128,
|
|
18
|
+
lng: -74.006,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
preferences: {
|
|
23
|
+
theme: "dark",
|
|
24
|
+
notifications: {
|
|
25
|
+
email: true,
|
|
26
|
+
push: false,
|
|
27
|
+
settings: {
|
|
28
|
+
frequency: "daily",
|
|
29
|
+
categories: ["tech", "news"],
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
posts: [
|
|
35
|
+
{
|
|
36
|
+
id: 101,
|
|
37
|
+
title: "First Post",
|
|
38
|
+
content: "Hello World!",
|
|
39
|
+
metadata: {
|
|
40
|
+
views: 150,
|
|
41
|
+
likes: 25,
|
|
42
|
+
tags: ["introduction", "hello"],
|
|
43
|
+
author: {
|
|
44
|
+
name: "Alice Johnson",
|
|
45
|
+
verified: true,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: 102,
|
|
51
|
+
title: "Tech Update",
|
|
52
|
+
content: "Latest in technology...",
|
|
53
|
+
metadata: {
|
|
54
|
+
views: 320,
|
|
55
|
+
likes: 45,
|
|
56
|
+
tags: ["tech", "update"],
|
|
57
|
+
author: {
|
|
58
|
+
name: "Alice Johnson",
|
|
59
|
+
verified: true,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: 2,
|
|
67
|
+
name: "Bob Smith",
|
|
68
|
+
details: {
|
|
69
|
+
personal: {
|
|
70
|
+
age: 35,
|
|
71
|
+
location: {
|
|
72
|
+
city: "London",
|
|
73
|
+
country: "UK",
|
|
74
|
+
coordinates: {
|
|
75
|
+
lat: 51.5074,
|
|
76
|
+
lng: -0.1278,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
preferences: {
|
|
81
|
+
theme: "light",
|
|
82
|
+
notifications: {
|
|
83
|
+
email: false,
|
|
84
|
+
push: true,
|
|
85
|
+
settings: {
|
|
86
|
+
frequency: "weekly",
|
|
87
|
+
categories: ["sports", "music"],
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
posts: [
|
|
93
|
+
{
|
|
94
|
+
id: 201,
|
|
95
|
+
title: "Music Review",
|
|
96
|
+
content: "Amazing concert last night...",
|
|
97
|
+
metadata: {
|
|
98
|
+
views: 89,
|
|
99
|
+
likes: 12,
|
|
100
|
+
tags: ["music", "review"],
|
|
101
|
+
author: {
|
|
102
|
+
name: "Bob Smith",
|
|
103
|
+
verified: false,
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
},
|
|
109
|
+
];
|
|
110
|
+
this.selectedUserId = 1;
|
|
111
|
+
this.stats = {
|
|
112
|
+
totalUsers: 2,
|
|
113
|
+
activeUsers: 1,
|
|
114
|
+
metrics: {
|
|
115
|
+
engagement: {
|
|
116
|
+
daily: 45,
|
|
117
|
+
weekly: 120,
|
|
118
|
+
monthly: 500,
|
|
119
|
+
},
|
|
120
|
+
performance: {
|
|
121
|
+
loadTime: 1.2,
|
|
122
|
+
renderTime: 0.8,
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
// Methods to test deeply nested property changes
|
|
127
|
+
this.updateUserAge = (userId) => {
|
|
128
|
+
const user = this.users.find(u => u.id === userId);
|
|
129
|
+
if (user) {
|
|
130
|
+
user.details.personal.age += 1;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
this.toggleUserTheme = (userId) => {
|
|
134
|
+
const user = this.users.find(u => u.id === userId);
|
|
135
|
+
if (user) {
|
|
136
|
+
user.details.preferences.theme =
|
|
137
|
+
user.details.preferences.theme === "dark" ? "light" : "dark";
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
this.updateUserLocation = (userId) => {
|
|
141
|
+
const user = this.users.find(u => u.id === userId);
|
|
142
|
+
if (user) {
|
|
143
|
+
// Use hardcoded values since we can only pass single argument
|
|
144
|
+
user.details.personal.location.city = "Tokyo";
|
|
145
|
+
user.details.personal.location.country = "Japan";
|
|
146
|
+
// Update coordinates randomly for demo
|
|
147
|
+
user.details.personal.location.coordinates.lat = Math.random() * 180 - 90;
|
|
148
|
+
user.details.personal.location.coordinates.lng = Math.random() * 360 - 180;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
this.addPostToUser = (userId) => {
|
|
152
|
+
const user = this.users.find(u => u.id === userId);
|
|
153
|
+
if (user) {
|
|
154
|
+
const newPostId = Math.max(...user.posts.map((p) => p.id)) + 1;
|
|
155
|
+
user.posts.push({
|
|
156
|
+
id: newPostId,
|
|
157
|
+
title: `New Post ${newPostId}`,
|
|
158
|
+
content: `This is a new post with ID ${newPostId}`,
|
|
159
|
+
metadata: {
|
|
160
|
+
views: 0,
|
|
161
|
+
likes: 0,
|
|
162
|
+
tags: ["new", "auto-generated"],
|
|
163
|
+
author: {
|
|
164
|
+
name: user.name,
|
|
165
|
+
verified: Math.random() > 0.5,
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
this.incrementPostLikes = (postId) => {
|
|
172
|
+
// Find the post across all users since we only have postId
|
|
173
|
+
for (const user of this.users) {
|
|
174
|
+
const post = user.posts.find((p) => p.id === postId);
|
|
175
|
+
if (post) {
|
|
176
|
+
post.metadata.likes += 1;
|
|
177
|
+
post.metadata.views += Math.floor(Math.random() * 5) + 1;
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
this.updateNotificationSettings = (userId) => {
|
|
183
|
+
const user = this.users.find(u => u.id === userId);
|
|
184
|
+
if (user) {
|
|
185
|
+
user.details.preferences.notifications.email =
|
|
186
|
+
!user.details.preferences.notifications.email;
|
|
187
|
+
user.details.preferences.notifications.push =
|
|
188
|
+
!user.details.preferences.notifications.push;
|
|
189
|
+
// Cycle through frequency options
|
|
190
|
+
const frequencies = ["daily", "weekly", "monthly"];
|
|
191
|
+
const currentIndex = frequencies.indexOf(user.details.preferences.notifications.settings.frequency);
|
|
192
|
+
const nextIndex = (currentIndex + 1) % frequencies.length;
|
|
193
|
+
user.details.preferences.notifications.settings.frequency =
|
|
194
|
+
frequencies[nextIndex];
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
this.addNotificationCategory = (userId) => {
|
|
198
|
+
const user = this.users.find(u => u.id === userId);
|
|
199
|
+
if (user) {
|
|
200
|
+
// Use hardcoded category since we can only pass single argument
|
|
201
|
+
const category = "sports";
|
|
202
|
+
if (!user.details.preferences.notifications.settings.categories.includes(category)) {
|
|
203
|
+
user.details.preferences.notifications.settings.categories.push(category);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
this.removeNotificationCategory = (userId) => {
|
|
208
|
+
const user = this.users.find(u => u.id === userId);
|
|
209
|
+
if (user) {
|
|
210
|
+
// Use hardcoded category since we can only pass single argument
|
|
211
|
+
const category = "tech";
|
|
212
|
+
const index = user.details.preferences.notifications.settings.categories.indexOf(category);
|
|
213
|
+
if (index > -1) {
|
|
214
|
+
user.details.preferences.notifications.settings.categories.splice(index, 1);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
this.addNewUser = () => {
|
|
219
|
+
const newId = Math.max(...this.users.map(u => u.id)) + 1;
|
|
220
|
+
this.users.push({
|
|
221
|
+
id: newId,
|
|
222
|
+
name: `User ${newId}`,
|
|
223
|
+
details: {
|
|
224
|
+
personal: {
|
|
225
|
+
age: Math.floor(Math.random() * 50) + 18,
|
|
226
|
+
location: {
|
|
227
|
+
city: "Random City",
|
|
228
|
+
country: "Random Country",
|
|
229
|
+
coordinates: {
|
|
230
|
+
lat: Math.random() * 180 - 90,
|
|
231
|
+
lng: Math.random() * 360 - 180,
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
preferences: {
|
|
236
|
+
theme: Math.random() > 0.5 ? "dark" : "light",
|
|
237
|
+
notifications: {
|
|
238
|
+
email: Math.random() > 0.5,
|
|
239
|
+
push: Math.random() > 0.5,
|
|
240
|
+
settings: {
|
|
241
|
+
frequency: ["daily", "weekly", "monthly"][Math.floor(Math.random() * 3)],
|
|
242
|
+
categories: ["general"],
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
posts: [],
|
|
248
|
+
});
|
|
249
|
+
this.stats.totalUsers = this.users.length;
|
|
250
|
+
};
|
|
251
|
+
this.removeUser = (userId) => {
|
|
252
|
+
const index = this.users.findIndex(u => u.id === userId);
|
|
253
|
+
if (index > -1) {
|
|
254
|
+
this.users.splice(index, 1);
|
|
255
|
+
this.stats.totalUsers = this.users.length;
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
this.updateStats = () => {
|
|
259
|
+
this.stats.metrics.engagement.daily += Math.floor(Math.random() * 10);
|
|
260
|
+
this.stats.metrics.engagement.weekly += Math.floor(Math.random() * 20);
|
|
261
|
+
this.stats.metrics.engagement.monthly += Math.floor(Math.random() * 50);
|
|
262
|
+
this.stats.metrics.performance.loadTime = Math.random() * 2 + 0.5;
|
|
263
|
+
this.stats.metrics.performance.renderTime = Math.random() * 1 + 0.3;
|
|
264
|
+
};
|
|
265
|
+
this.selectUser = (userId) => {
|
|
266
|
+
this.selectedUserId = userId;
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
RenderableFASTElement(ObserverMapTestElement).defineAsync({
|
|
271
|
+
name: "observer-map-test-element",
|
|
272
|
+
templateOptions: "defer-and-hydrate",
|
|
273
|
+
});
|
|
274
|
+
class ObserverMapInternalTestElement extends FASTElement {
|
|
275
|
+
constructor() {
|
|
276
|
+
super(...arguments);
|
|
277
|
+
this.a = {
|
|
278
|
+
b: {},
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
defineB() {
|
|
282
|
+
this.a.b = {
|
|
283
|
+
c: "Hello world",
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
updateC() {
|
|
287
|
+
this.a.b.c = "Hello pluto";
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
RenderableFASTElement(ObserverMapInternalTestElement).defineAsync({
|
|
291
|
+
name: "observer-map-internal-test-element",
|
|
292
|
+
templateOptions: "defer-and-hydrate",
|
|
293
|
+
});
|
|
294
|
+
// Configure TemplateElement with observerMap enabled for this test
|
|
295
|
+
TemplateElement.options({
|
|
296
|
+
"observer-map-test-element": {
|
|
297
|
+
observerMap: "all", // Enable ObserverMap to track all the nested property changes
|
|
298
|
+
},
|
|
299
|
+
"observer-map-internal-test-element": {
|
|
300
|
+
observerMap: "all", // Enable ObserverMap to track all the nested property changes
|
|
301
|
+
},
|
|
302
|
+
}).define({
|
|
303
|
+
name: "f-template",
|
|
304
|
+
});
|