silentium-components 0.0.5 → 0.0.7

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 (65) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/silentium-components.cjs +134 -483
  3. package/dist/silentium-components.cjs.map +1 -1
  4. package/dist/silentium-components.d.ts +8 -190
  5. package/dist/silentium-components.js +130 -467
  6. package/dist/silentium-components.js.map +1 -1
  7. package/dist/silentium-components.min.js +1 -1
  8. package/dist/silentium-components.min.mjs +1 -1
  9. package/dist/silentium-components.min.mjs.map +1 -1
  10. package/dist/silentium-components.mjs +130 -467
  11. package/dist/silentium-components.mjs.map +1 -1
  12. package/docs/build.sh +3 -4
  13. package/docs/index.html +3 -3
  14. package/docs/pages/behaviors/deadline.html +60 -0
  15. package/docs/pages/behaviors.html +5 -0
  16. package/docs/routes.json +1 -1
  17. package/eslint.config.mjs +1 -0
  18. package/package.json +7 -5
  19. package/src/behaviors/Deadline._value.test.ts +27 -0
  20. package/src/behaviors/Deadline.test.ts +28 -0
  21. package/src/behaviors/Deadline.ts +49 -0
  22. package/src/behaviors/Dirty.test.ts +5 -5
  23. package/src/behaviors/Dirty.ts +48 -54
  24. package/src/behaviors/Loading.test.ts +8 -8
  25. package/src/behaviors/Loading.ts +21 -31
  26. package/src/behaviors/Path.index.test.ts +5 -5
  27. package/src/behaviors/Path.nested.test.ts +5 -5
  28. package/src/behaviors/Path.test.ts +5 -5
  29. package/src/behaviors/Path.ts +26 -30
  30. package/src/behaviors/index.ts +1 -1
  31. package/src/controls/GroupActiveClass.test.ts +16 -13
  32. package/src/controls/GroupActiveClass.ts +19 -22
  33. package/src/controls/index.ts +0 -5
  34. package/src/index.ts +0 -2
  35. package/src/navigation/Router.test.ts +47 -0
  36. package/src/navigation/Router.ts +43 -111
  37. package/src/navigation/index.ts +0 -6
  38. package/src/strings/Concatenated.test.ts +11 -0
  39. package/src/strings/Concatenated.ts +18 -0
  40. package/src/structures/HashTable.test.ts +5 -5
  41. package/src/structures/HashTable.ts +14 -25
  42. package/src/system/RegexpMatched.test.ts +14 -0
  43. package/src/system/RegexpMatched.ts +17 -0
  44. package/src/system/index.ts +1 -0
  45. package/src/behaviors/Touched.ts +0 -1
  46. package/src/controls/ComputedElement.ts +0 -51
  47. package/src/controls/Input.ts +0 -45
  48. package/src/controls/Link.ts +0 -53
  49. package/src/controls/Text.ts +0 -16
  50. package/src/controls/Visible.ts +0 -16
  51. package/src/jsdom/JSDomDocument.ts +0 -15
  52. package/src/jsdom/JSDomElement.ts +0 -28
  53. package/src/jsdom/JSDomQuerySelector.ts +0 -28
  54. package/src/navigation/CurrentPage.ts +0 -27
  55. package/src/navigation/Navigation.default.test.ts +0 -54
  56. package/src/navigation/Navigation.main.test.ts +0 -47
  57. package/src/navigation/Navigation.ts +0 -92
  58. package/src/navigation/Navigation.wildcard.test.ts +0 -52
  59. package/src/navigation/PageFetchTransport.ts +0 -26
  60. package/src/navigation/RouteDisplay.ts +0 -18
  61. package/src/navigation/RoutePageType.ts +0 -3
  62. package/src/page/EntryPointPage.ts +0 -20
  63. package/src/page/Page.ts +0 -12
  64. package/src/page/PageFake.ts +0 -8
  65. package/src/page/index.ts +0 -2
@@ -1,479 +1,142 @@
1
- import { give, SourceAll, value, Patron, SourceChangeable, GuestCast, PatronOnce, PrivateClass, Source, sourceOf } from 'silentium';
2
- import { HistoryNewPage, HistoryPoppedPage } from 'silentium-web-api';
3
-
4
- class PageFetchTransport {
5
- constructor(basePath, template) {
6
- this.basePath = basePath;
7
- this.template = template;
8
- }
9
- content(guest) {
10
- fetch(this.basePath + "/" + this.template).then((result) => {
11
- return result.text();
12
- }).then((result) => {
13
- give(result, guest);
14
- });
15
- }
16
- }
17
-
18
- class Navigation {
19
- constructor(loading, basePath, currentPage, display, pageTransport) {
20
- this.loading = loading;
21
- this.basePath = basePath;
22
- this.currentPage = currentPage;
23
- this.display = display;
24
- this.pageTransport = pageTransport;
25
- }
26
- routes(routes) {
27
- const defaultRoute = routes.find((route) => route.default);
28
- const all = new SourceAll();
29
- value(this.basePath, new Patron(all.guestKey("basePath")));
30
- value(this.currentPage, new Patron(all.guestKey("currentPage")));
31
- all.value(
32
- new Patron(({ basePath, currentPage }) => {
33
- const urlWithoutBasePath = currentPage.replace(basePath, "");
34
- const routeMatchedToAlias = routes.find(
35
- (route2) => route2.aliases && (route2.aliases.includes(currentPage) || route2.aliases.includes(urlWithoutBasePath))
36
- );
37
- if (routeMatchedToAlias) {
38
- const correctUrl = basePath + routeMatchedToAlias.url;
39
- if (correctUrl !== currentPage) {
40
- give(correctUrl, this.currentPage);
41
- return;
42
- }
1
+ import { value, sourceAll, patron, sourceOf, patronOnce, guestCast, give, subSourceMany, sourceFiltered, subSource } from 'silentium';
2
+
3
+ const groupActiveClass = (activeClassSrc, activeElementSrc, groupElementsSrc) => {
4
+ value(
5
+ sourceAll([activeClassSrc, activeElementSrc, groupElementsSrc]),
6
+ patron(([activeClass, activeElement, groupElements]) => {
7
+ groupElements.forEach((el) => {
8
+ if (el.classList) {
9
+ el.classList.remove(activeClass);
43
10
  }
44
- let route = routes.find((route2) => {
45
- if (route2.url.indexOf("*") >= 0) {
46
- const regexp = new RegExp(
47
- route2.url.replaceAll("*", ".*").replaceAll("/", "/")
48
- );
49
- return regexp.test(urlWithoutBasePath);
50
- }
51
- return route2.url.replaceAll("*", "") === urlWithoutBasePath;
52
- });
53
- if (!route && defaultRoute) {
54
- route = defaultRoute;
55
- }
56
- if (route) {
57
- const basePathWithoutHash = basePath.replace("/#", "").replace("#", "").replace(/[^/]+\.html$/, "");
58
- give(true, this.loading);
59
- this.pageTransport.get(basePathWithoutHash, route.template).content((templateContent) => {
60
- this.display.display(templateContent);
61
- route.page.mounted();
62
- give(false, this.loading);
63
- });
64
- } else {
65
- throw new Error("No matching route in Navigation");
66
- }
67
- })
68
- );
69
- }
70
- }
71
-
72
- class RouteDisplay {
73
- constructor(selector) {
74
- this.selector = selector;
75
- }
76
- display(content) {
77
- const contentEl = document.querySelector(this.selector);
78
- if (contentEl) {
79
- contentEl.innerHTML = content;
80
- }
81
- }
82
- }
83
-
84
- var __defProp$3 = Object.defineProperty;
85
- var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
86
- var __publicField$3 = (obj, key, value) => __defNormalProp$3(obj, key + "" , value);
87
- class CurrentPage {
88
- constructor() {
89
- __publicField$3(this, "source");
90
- const correctUrl = location.href.replace(location.origin, "");
91
- this.source = new SourceChangeable(correctUrl);
92
- }
93
- give(value) {
94
- this.source.give(value);
95
- return this;
96
- }
97
- value(guest) {
98
- this.source.value(guest);
99
- return guest;
100
- }
101
- pool() {
102
- return this.source.pool();
103
- }
104
- }
105
-
106
- class Input {
107
- constructor(source, selector) {
108
- this.source = source;
109
- const el = document.querySelector(selector);
110
- this.source.value(
111
- new Patron((value) => {
112
- el.value = String(value);
113
- })
114
- );
115
- el.addEventListener("keyup", () => {
116
- this.give(el.value);
117
- });
118
- el.addEventListener("change", () => {
119
- this.give(el.value);
120
- });
121
- }
122
- value(guest) {
123
- this.source.value(guest);
124
- return this;
125
- }
126
- give(value) {
127
- this.source.give(value);
128
- return this;
129
- }
130
- pool() {
131
- return this.source.pool();
132
- }
133
- }
134
-
135
- class Visible {
136
- constructor(selector) {
137
- this.selector = selector;
138
- }
139
- give(isVisible) {
140
- const el = document.querySelector(this.selector);
141
- if (el) {
142
- el.style.display = isVisible ? "block" : "none";
143
- }
144
- return this;
145
- }
146
- }
147
-
148
- class Text {
149
- constructor(selector) {
150
- this.selector = selector;
151
- }
152
- give(value) {
153
- const element = document.querySelector(this.selector);
154
- if (element) {
155
- element.innerText = String(value);
156
- }
157
- return this;
158
- }
159
- }
160
-
161
- class Link {
162
- constructor(linkSource, basePath) {
163
- this.linkSource = linkSource;
164
- this.basePath = basePath;
165
- }
166
- watchClick(selector, subselector) {
167
- const wrapperEl = document.querySelectorAll(selector);
168
- if (wrapperEl.length) {
169
- wrapperEl.forEach((theElement) => {
170
- theElement.addEventListener("click", (e) => {
171
- if (subselector) {
172
- theElement.querySelectorAll(subselector).forEach((theSubElement) => {
173
- if (e?.target === theSubElement || e?.currentTarget === theSubElement) {
174
- this.handleClick({
175
- preventDefault: e.preventDefault.bind(e),
176
- target: theSubElement
177
- });
178
- }
179
- });
180
- } else {
181
- this.handleClick(e);
182
- }
183
- });
184
- });
185
- } else {
186
- throw new Error(`Link wrapper not found for selector ${selector}`);
187
- }
188
- }
189
- handleClick(e) {
190
- let href = e?.target?.getAttribute("href");
191
- if (!href) {
192
- href = e?.currentTarget?.getAttribute("href");
193
- }
194
- if (href && href.indexOf("http") !== 0) {
195
- e.preventDefault();
196
- value(this.basePath, (basePath) => {
197
- this.linkSource.give(basePath + href);
198
11
  });
199
- }
200
- }
201
- }
202
-
203
- class ComputedElement {
204
- constructor(sources, selectorTemplate) {
205
- this.sources = sources;
206
- this.selectorTemplate = selectorTemplate;
207
- }
208
- element(guest) {
209
- const chain = new SourceAll();
210
- this.sources.forEach((source) => {
211
- source.source.value(
212
- new GuestCast(guest, chain.guestKey(source.placeholder))
213
- );
214
- });
215
- chain.value(
216
- new GuestCast(
217
- guest,
218
- (placeholders) => {
219
- let selectorTemplate = this.selectorTemplate;
220
- Object.entries(placeholders).map((entry) => {
221
- selectorTemplate = selectorTemplate.replaceAll(entry[0], entry[1]);
222
- });
223
- const element = document.querySelector(
224
- selectorTemplate
225
- );
226
- if (element) {
227
- give(element, guest);
12
+ activeElement.classList.add(activeClass);
13
+ })
14
+ );
15
+ return groupElementsSrc;
16
+ };
17
+
18
+ const dirty = (baseEntitySource, becomePatronAuto = false, alwaysKeep = [], excludeKeys = []) => {
19
+ const comparingSrc = sourceOf();
20
+ const all = sourceAll([comparingSrc, baseEntitySource]);
21
+ const result = {
22
+ give(value2) {
23
+ give(JSON.parse(JSON.stringify(value2)), comparingSrc);
24
+ return result;
25
+ },
26
+ value(guest) {
27
+ value(
28
+ all,
29
+ guestCast(guest, ([comparing, base]) => {
30
+ if (!comparing) {
31
+ return;
228
32
  }
229
- }
230
- )
231
- );
232
- }
233
- }
234
-
235
- class GroupActiveClass {
236
- constructor(activeClass, groupSelector, document) {
237
- this.activeClass = activeClass;
238
- this.groupSelector = groupSelector;
239
- this.document = document;
240
- }
241
- give(element) {
242
- value(
243
- this.document,
244
- new PatronOnce((document) => {
245
- document.querySelectorAll(this.groupSelector).forEach((el) => {
246
- el.classList.remove(this.activeClass);
247
- });
248
- element.classList.add(this.activeClass);
249
- })
250
- );
251
- return this;
252
- }
253
- }
254
-
255
- class Router {
256
- constructor(loaderSelector, navigationResultSelector, menuSelector) {
257
- this.loaderSelector = loaderSelector;
258
- this.navigationResultSelector = navigationResultSelector;
259
- this.menuSelector = menuSelector;
260
- }
261
- routes(routes, currentPage, basePathSource, afterPageLoaded) {
262
- if (!currentPage) {
263
- currentPage = new CurrentPage();
264
- }
265
- currentPage.value(new Patron(new HistoryNewPage()));
266
- const [basePath] = location.href.replace(location.origin, "").split("#");
267
- if (!basePathSource) {
268
- basePathSource = new SourceChangeable(
269
- `${basePath}#`.replace("index.html", "").replace("//", "/")
270
- );
271
- }
272
- const pageLoading = new SourceChangeable(false);
273
- pageLoading.value(new Patron(new Visible(this.loaderSelector)));
274
- const historyPoppedPage = new HistoryPoppedPage(currentPage);
275
- historyPoppedPage.watchPop();
276
- const navigation = new Navigation(
277
- pageLoading,
278
- basePathSource,
279
- currentPage,
280
- new RouteDisplay(this.navigationResultSelector),
281
- new PrivateClass(PageFetchTransport)
282
- );
283
- navigation.routes(routes);
284
- const link = new Link(currentPage, basePathSource);
285
- link.watchClick(this.menuSelector);
286
- const urlChain = new SourceAll();
287
- basePathSource.value(new Patron(urlChain.guestKey("basePath")));
288
- currentPage.value(new Patron(urlChain.guestKey("page")));
289
- const url = new Source((guest) => {
290
- urlChain.value(
291
- new GuestCast(guest, ({ basePath: basePath2, page }) => {
292
- give(page.replace(basePath2, ""), guest);
33
+ give(
34
+ Object.fromEntries(
35
+ Object.entries(comparing).filter(([key, value2]) => {
36
+ if (alwaysKeep.includes(key)) {
37
+ return true;
38
+ }
39
+ if (excludeKeys.includes(key)) {
40
+ return false;
41
+ }
42
+ return value2 !== base[key];
43
+ })
44
+ ),
45
+ guest
46
+ );
293
47
  })
294
48
  );
295
- });
296
- const activeLink = new ComputedElement(
297
- [{ source: url, placeholder: "{url}" }],
298
- `${this.menuSelector} a[href="{url}"]`
299
- );
300
- activeLink.element(
301
- new Patron(
302
- new GroupActiveClass(
303
- "active",
304
- `${this.menuSelector} a`,
305
- sourceOf(document)
306
- )
307
- )
308
- );
309
- pageLoading.value(
310
- new Patron((isInLoading) => {
311
- if (isInLoading) {
312
- return;
313
- }
314
- if (afterPageLoaded) {
315
- afterPageLoaded();
316
- }
317
- const divDestination = document.querySelector(
318
- this.navigationResultSelector
319
- );
320
- if (divDestination) {
321
- divDestination.querySelectorAll("script").forEach((x) => {
322
- const sc = document.createElement("script");
323
- sc.setAttribute("type", "module");
324
- sc.appendChild(document.createTextNode(x.innerText));
325
- divDestination.appendChild(sc);
326
- });
327
- }
328
- })
329
- );
330
- }
331
- }
332
-
333
- class Page {
334
- constructor(title) {
335
- this.title = title;
336
- }
337
- mounted() {
338
- document.title = this.title;
339
- }
340
- }
341
-
342
- class EntryPointPage {
343
- constructor(title, entryPointUrl) {
344
- this.title = title;
345
- this.entryPointUrl = entryPointUrl;
346
- }
347
- mounted() {
348
- document.title = this.title;
349
- import(this.entryPointUrl).then((module) => {
350
- if (module.main) {
351
- module.main();
352
- }
353
- });
354
- }
355
- }
356
-
357
- var __defProp$2 = Object.defineProperty;
358
- var __defNormalProp$2 = (obj, key, value2) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value: value2 }) : obj[key] = value2;
359
- var __publicField$2 = (obj, key, value2) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value2);
360
- class Dirty {
361
- constructor(baseEntitySource, alwaysKeep = [], excludeKeys = [], becomePatronAuto = false) {
362
- this.alwaysKeep = alwaysKeep;
363
- this.excludeKeys = excludeKeys;
364
- __publicField$2(this, "comparingSource", new SourceChangeable());
365
- __publicField$2(this, "all", new SourceAll());
366
- this.comparingSource.value(new Patron(this.all.guestKey("comparing")));
367
- value(baseEntitySource, new Patron(this.all.guestKey("base")));
368
- if (becomePatronAuto) {
369
- value(baseEntitySource, new PatronOnce(this));
49
+ return result;
370
50
  }
371
- }
372
- give(value2) {
373
- give(JSON.parse(JSON.stringify(value2)), this.comparingSource);
374
- return this;
375
- }
376
- value(guest) {
377
- this.all.value(
378
- new GuestCast(guest, ({ comparing, base }) => {
379
- if (!comparing) {
380
- return;
381
- }
382
- give(
383
- Object.fromEntries(
384
- Object.entries(comparing).filter(([key, value2]) => {
385
- if (this.alwaysKeep.includes(key)) {
386
- return true;
387
- }
388
- if (this.excludeKeys.includes(key)) {
389
- return false;
390
- }
391
- return value2 !== base[key];
392
- })
393
- ),
394
- guest
395
- );
396
- })
397
- );
398
- return this;
399
- }
400
- }
401
-
402
- var __defProp$1 = Object.defineProperty;
403
- var __defNormalProp$1 = (obj, key, value2) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value: value2 }) : obj[key] = value2;
404
- var __publicField$1 = (obj, key, value2) => __defNormalProp$1(obj, key + "" , value2);
405
- class Loading {
406
- constructor(loadingStartSource, loadingFinishSource) {
407
- this.loadingStartSource = loadingStartSource;
408
- this.loadingFinishSource = loadingFinishSource;
409
- __publicField$1(this, "loadingSource", new SourceChangeable());
410
- }
411
- value(guest) {
412
- value(
413
- this.loadingStartSource,
414
- new GuestCast(guest, () => {
415
- this.loadingSource.give(true);
416
- })
417
- );
51
+ };
52
+ if (becomePatronAuto) {
53
+ value(baseEntitySource, patronOnce(result));
54
+ }
55
+ return result;
56
+ };
57
+
58
+ const loading = (loadingStartSource, loadingFinishSource) => {
59
+ const loadingSrc = sourceOf();
60
+ subSourceMany(loadingSrc, [loadingStartSource, loadingFinishSource]);
61
+ value(
62
+ loadingStartSource,
63
+ patron(() => {
64
+ loadingSrc.give(true);
65
+ })
66
+ );
67
+ value(
68
+ loadingFinishSource,
69
+ patron(() => {
70
+ loadingSrc.give(false);
71
+ })
72
+ );
73
+ return loadingSrc.value;
74
+ };
75
+
76
+ const path = (baseSrc, keySrc) => {
77
+ const pathSrc = sourceOf();
78
+ subSourceMany(pathSrc, [baseSrc, keySrc]);
79
+ value(
80
+ sourceAll([baseSrc, keySrc]),
81
+ patron(([base, key]) => {
82
+ const keyChunks = key.split(".");
83
+ let value2 = base;
84
+ keyChunks.forEach((keyChunk) => {
85
+ value2 = value2[keyChunk];
86
+ });
87
+ if (value2 !== void 0 && value2 !== base) {
88
+ give(value2, pathSrc);
89
+ }
90
+ })
91
+ );
92
+ return pathSrc.value;
93
+ };
94
+
95
+ const deadline = (error, baseSrc, timeoutSrc) => {
96
+ let timerHead = null;
97
+ return (g) => {
418
98
  value(
419
- this.loadingFinishSource,
420
- new GuestCast(guest, () => {
421
- this.loadingSource.give(false);
422
- })
423
- );
424
- this.loadingSource.value(guest);
425
- return this;
426
- }
427
- }
428
-
429
- class Touched {
430
- }
431
-
432
- class Path {
433
- constructor(baseSource, keyType) {
434
- this.baseSource = baseSource;
435
- this.keyType = keyType;
436
- }
437
- value(guest) {
438
- const all = new SourceAll(["base", "key"]);
439
- value(this.baseSource, new GuestCast(guest, all.guestKey("base")));
440
- value(this.keyType, new GuestCast(guest, all.guestKey("key")));
441
- all.value(
442
- new GuestCast(guest, ({ base, key }) => {
443
- const keyChunks = key.split(".");
444
- let value2 = base;
445
- keyChunks.forEach((keyChunk) => {
446
- value2 = value2[keyChunk];
447
- });
448
- if (value2 !== void 0 && value2 !== base) {
449
- give(value2, guest);
99
+ timeoutSrc,
100
+ guestCast(g, (timeout) => {
101
+ if (timerHead) {
102
+ clearTimeout(timerHead);
450
103
  }
104
+ let timeoutReached = false;
105
+ timerHead = setTimeout(() => {
106
+ if (timeoutReached) {
107
+ return;
108
+ }
109
+ timeoutReached = true;
110
+ give(new Error("Timeout reached in Deadline class"), error);
111
+ }, timeout);
112
+ value(
113
+ sourceFiltered(baseSrc, () => !timeoutReached),
114
+ g
115
+ );
116
+ value(
117
+ baseSrc,
118
+ patronOnce(() => {
119
+ timeoutReached = true;
120
+ })
121
+ );
451
122
  })
452
123
  );
453
- return this;
454
- }
455
- }
456
-
457
- var __defProp = Object.defineProperty;
458
- var __defNormalProp = (obj, key, value2) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value: value2 }) : obj[key] = value2;
459
- var __publicField = (obj, key, value2) => __defNormalProp(obj, key + "" , value2);
460
- class HashTable {
461
- constructor(baseSource) {
462
- __publicField(this, "source", new SourceChangeable({}));
463
- value(
464
- baseSource,
465
- new Patron(([key, value2]) => {
466
- this.source.value((lastRecord) => {
467
- lastRecord[key] = value2;
468
- });
469
- })
470
- );
471
- }
472
- value(guest) {
473
- value(this.source, guest);
474
- return this;
475
- }
476
- }
124
+ };
125
+ };
126
+
127
+ const hashTable = (baseSource) => {
128
+ const result = sourceOf({});
129
+ subSource(result, baseSource);
130
+ value(
131
+ baseSource,
132
+ patron(([key, value2]) => {
133
+ result.value((lastRecord) => {
134
+ lastRecord[key] = value2;
135
+ });
136
+ })
137
+ );
138
+ return result.value;
139
+ };
477
140
 
478
- export { ComputedElement, CurrentPage, Dirty, EntryPointPage, GroupActiveClass, HashTable, Input, Link, Loading, Navigation, Page, PageFetchTransport, Path, RouteDisplay, Router, Text, Touched, Visible };
141
+ export { deadline, dirty, groupActiveClass, hashTable, loading, path };
479
142
  //# sourceMappingURL=silentium-components.js.map