@schukai/monster 3.14.1 → 3.16.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schukai/monster",
3
- "version": "3.14.1",
3
+ "version": "3.16.0",
4
4
  "description": "Monster is a simple library for creating fast, robust and lightweight websites.",
5
5
  "keywords": [
6
6
  "framework",
@@ -5,6 +5,7 @@
5
5
  * License text available at https://www.gnu.org/licenses/agpl-3.0.en.html
6
6
  */
7
7
 
8
+ import {getLocaleOfDocument} from "../dom/locale.mjs";
8
9
  import {Base} from "../types/base.mjs";
9
10
  import {getGlobal, getGlobalObject} from "../types/global.mjs";
10
11
  import {ID} from "../types/id.mjs";
@@ -169,6 +170,11 @@ function transform(value) {
169
170
  let element;
170
171
  let attribute;
171
172
  let translations;
173
+ let date;
174
+ let locale;
175
+ let timestamp;
176
+ let map;
177
+ let keyValue;
172
178
 
173
179
  switch (this.command) {
174
180
  case "static":
@@ -405,25 +411,25 @@ function transform(value) {
405
411
  if (key === undefined) {
406
412
  throw new Error("missing key parameter");
407
413
  }
408
-
414
+
409
415
  // add empty strings
410
- if (isString(key)&&key.trim()==="") {
411
- concat += key;
416
+ if (isString(key) && key.trim() === "") {
417
+ concat += key;
412
418
  continue;
413
419
  }
414
-
420
+
415
421
  if (!pf2.exists(key)) {
416
422
  concat += key;
417
423
  continue;
418
424
  }
419
425
  let v = pf2.getVia(key);
420
- if(!isPrimitive(v)) {
426
+ if (!isPrimitive(v)) {
421
427
  throw new Error("value is not primitive");
422
428
  }
423
429
 
424
430
  concat += v;
425
431
  }
426
-
432
+
427
433
  return concat;
428
434
  case "path":
429
435
  key = args.shift();
@@ -491,6 +497,117 @@ function transform(value) {
491
497
 
492
498
  throw new Error("type not supported");
493
499
 
500
+
501
+ case "map":
502
+ map = new Map();
503
+ while (args.length > 0) {
504
+ keyValue = args.shift();
505
+ if (keyValue === undefined) {
506
+ throw new Error("missing key parameter");
507
+ }
508
+
509
+ keyValue = keyValue.split("=");
510
+ map.set(keyValue[0], keyValue[1]);
511
+ }
512
+
513
+ return map.get(value);
514
+
515
+ case "timestamp":
516
+ date = new Date(value);
517
+ timestamp = date.getTime();
518
+ if (isNaN(timestamp)) {
519
+ throw new Error("invalid date");
520
+ }
521
+ return timestamp;
522
+
523
+ case "time":
524
+ date = new Date(value);
525
+ if (isNaN(date.getTime())) {
526
+ throw new Error("invalid date");
527
+ }
528
+
529
+ try {
530
+ locale = getLocaleOfDocument();
531
+ return date.toLocaleTimeString(locale);
532
+
533
+ } catch (e) {
534
+ throw new Error("unsupported locale or missing format (" + e.message + ")");
535
+ }
536
+
537
+
538
+ case "year":
539
+ date = new Date(value);
540
+ if (isNaN(date.getTime())) {
541
+ throw new Error("invalid date");
542
+ }
543
+
544
+ return date.getFullYear();
545
+
546
+ case "month":
547
+ date = new Date(value);
548
+ if (isNaN(date.getTime())) {
549
+ throw new Error("invalid date");
550
+ }
551
+
552
+ return date.getMonth() + 1;
553
+
554
+ case "day":
555
+ date = new Date(value);
556
+ if (isNaN(date.getTime())) {
557
+ throw new Error("invalid date");
558
+ }
559
+
560
+ return date.getDate();
561
+
562
+ case "weekday":
563
+ date = new Date(value);
564
+ if (isNaN(date.getTime())) {
565
+ throw new Error("invalid date");
566
+ }
567
+
568
+ return date.getDay();
569
+
570
+ case "hour":
571
+ case "hours":
572
+ date = new Date(value);
573
+ if (isNaN(date.getTime())) {
574
+ throw new Error("invalid date");
575
+ }
576
+
577
+ return date.getHours();
578
+
579
+ case "minute":
580
+ case "minutes":
581
+ date = new Date(value);
582
+ if (isNaN(date.getTime())) {
583
+ throw new Error("invalid date");
584
+ }
585
+
586
+ return date.getMinutes();
587
+
588
+ case "second":
589
+ case "seconds":
590
+ date = new Date(value);
591
+ if (isNaN(date.getTime())) {
592
+ throw new Error("invalid date");
593
+ }
594
+
595
+ return date.getSeconds();
596
+
597
+ case "date":
598
+ date = new Date(value);
599
+ if (isNaN(date.getTime())) {
600
+ throw new Error("invalid date");
601
+ }
602
+
603
+ try {
604
+ locale = getLocaleOfDocument();
605
+ return date.toLocaleDateString(locale);
606
+
607
+ } catch (e) {
608
+ throw new Error("unsupported locale or missing format (" + e.message + ")");
609
+ }
610
+
494
611
  case "i18n":
495
612
  case "translation":
496
613
  translations = getDocumentTranslations();
@@ -354,7 +354,7 @@ class CustomElement extends HTMLElement {
354
354
  static getCSSStyleSheet() {
355
355
  return undefined;
356
356
  }
357
-
357
+
358
358
  /**
359
359
  * attach a new observer
360
360
  *
@@ -6,8 +6,9 @@
6
6
  */
7
7
 
8
8
  import { extend } from "../data/extend.mjs";
9
- import { BaseWithOptions } from "../types/basewithoptions.mjs";
9
+ import { Base } from "../types/base.mjs";
10
10
  import { getGlobalObject } from "../types/global.mjs";
11
+ import {equipWithInternal} from "../types/internal.mjs";
11
12
  import { isArray } from "../types/is.mjs";
12
13
  import { ATTRIBUTE_HREF, ATTRIBUTE_SRC } from "./constants.mjs";
13
14
  import { Resource } from "./resource.mjs";
@@ -26,7 +27,7 @@ export { ResourceManager };
26
27
  * @memberOf Monster.DOM
27
28
  * @summary A Resource class
28
29
  */
29
- class ResourceManager extends BaseWithOptions {
30
+ class ResourceManager extends Base {
30
31
  /**
31
32
  *
32
33
  * @param {Object} options
@@ -34,12 +35,21 @@ class ResourceManager extends BaseWithOptions {
34
35
  */
35
36
  constructor(options) {
36
37
  super(options);
38
+ equipWithInternal.call(this);
37
39
 
38
40
  if (!(this.getOption("document") instanceof Document)) {
39
41
  throw new Error("unsupported document type");
40
42
  }
41
43
  }
42
44
 
45
+ /**
46
+ * @deprecated since 3.15.0 use getInternal instead
47
+ * @property {string} baseurl
48
+ */
49
+ getOption(key) {
50
+ return this.getInternal(key);
51
+ }
52
+
43
53
  /**
44
54
  * @property {string} baseurl
45
55
  */
@@ -47,6 +57,14 @@ class ResourceManager extends BaseWithOptions {
47
57
  this.getOption("document")?.baseURL;
48
58
  }
49
59
 
60
+ /**
61
+ * @property {string} baseurl
62
+ * @deprecated since 3.15.0 use internalDefaults instead
63
+ */
64
+ get defaults() {
65
+ return this.internalDefaults;
66
+ }
67
+
50
68
  /**
51
69
  *
52
70
  * @property {HTMLDocument} document=document Document
@@ -55,8 +73,8 @@ class ResourceManager extends BaseWithOptions {
55
73
  * @property {Array} resources.stylesheets=[] array with {@link Monster.DOM.Resource.Link.Stylesheet} objects
56
74
  * @property {Array} resources.data=[] array with {@link Monster.DOM.Resource.Data} objects
57
75
  */
58
- get defaults() {
59
- return Object.assign({}, super.defaults, {
76
+ get internalDefaults() {
77
+ return Object.assign({}, {
60
78
  document: getGlobalObject("document"),
61
79
  resources: {
62
80
  scripts: [],
@@ -10,14 +10,14 @@ import { instanceSymbol } from "../constants.mjs";
10
10
  export { Base };
11
11
 
12
12
  /**
13
- * This is the base class from which all monster classes are derived.
13
+ * This is the base class from which the most classes are derived.
14
14
  *
15
15
  * This class has besides a `toString` which returns the json representation of the object
16
16
  * also a functionality to check if an object is an instance of a class.
17
17
  *
18
18
  * Therefor the class has a static method ` [Symbol.hasInstance](that)` which returns true if the object
19
19
  * is an instance of the class.
20
- * F
20
+ *
21
21
  * @see [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/hasInstance](developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/hasInstance)
22
22
  *
23
23
  * Derived classes should implement a static getter `instanceSymbol` which returns a unique symbol.
@@ -26,6 +26,7 @@ export { BaseWithOptions };
26
26
  * @since 1.13.0
27
27
  * @copyright schukai GmbH
28
28
  * @memberOf Monster.Types
29
+ * @deprecated since 3.15.0 use {@link Monster.Types.Base} with {@link Monster.Types.equipWithInternal} instead.
29
30
  */
30
31
  class BaseWithOptions extends Base {
31
32
  /**
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Copyright schukai GmbH and contributors 2022. All Rights Reserved.
3
+ * Node module: @schukai/monster
4
+ * This file is licensed under the AGPLv3 License.
5
+ * License text available at https://www.gnu.org/licenses/agpl-3.0.en.html
6
+ */
7
+ import {internalSymbol} from "../constants.mjs";
8
+ import {extend} from "../data/extend.mjs";
9
+ import {Pathfinder} from "../data/pathfinder.mjs";
10
+ import {parseDataURL} from "./dataurl.mjs";
11
+ import {isString} from "./is.mjs";
12
+ import {Observer} from "./observer.mjs";
13
+ import {ProxyObserver} from "./proxyobserver.mjs";
14
+ import {validateObject} from "./validate.mjs";
15
+ import {isObject} from "./is.mjs";
16
+
17
+ export {equipWithInternal}
18
+
19
+ /**
20
+ * @private
21
+ * @type {string}
22
+ */
23
+ const propertyName = 'internalDefaults'
24
+
25
+ /**
26
+ * This function extends the given object with the following methods:
27
+ *
28
+ * - attachInternalObserver
29
+ * - detachInternalObserver
30
+ * - containsInternalObserver
31
+ * - setInternal
32
+ * - setInternals
33
+ * - getInternal
34
+ *
35
+ * @license AGPLv3
36
+ * @since 3.15.0
37
+ * @copyright schukai GmbH
38
+ * @memberOf Monster.Types
39
+ */
40
+ function equipWithInternal() {
41
+ const self = this;
42
+ validateObject(self);
43
+
44
+ if (!hasGetter(self, propertyName)) {
45
+ Object.defineProperty(self, propertyName, {
46
+ get: function () {
47
+ return {};
48
+ }
49
+ });
50
+ }
51
+
52
+ const defaults = extend({}, self[propertyName] || {});
53
+ self[internalSymbol] = new ProxyObserver(defaults);
54
+
55
+ /**
56
+ * Attach a new observer
57
+ *
58
+ * @param {Observer} observer
59
+ * @returns {ProxyObserver}
60
+ */
61
+ self["attachInternalObserver"] = (observer) => {
62
+ self[internalSymbol].attachObserver(observer);
63
+ return self;
64
+ }
65
+
66
+ /**
67
+ * Detach a observer
68
+ *
69
+ * @param {Observer} observer
70
+ * @returns {ProxyObserver}
71
+ */
72
+ self["detachInternalObserver"] = (observer) => {
73
+ self[internalSymbol].detachObserver(observer);
74
+ return self;
75
+ }
76
+
77
+ /**
78
+ * Check if a observer is attached
79
+ *
80
+ * @param {Observer} observer
81
+ * @returns {boolean}
82
+ */
83
+ self["containsInternalObserver"] = (observer) => {
84
+ return self[internalSymbol].containsObserver(observer);
85
+ }
86
+
87
+
88
+ /**
89
+ * Set an internal value, nested internals can be specified by path `a.b.c`
90
+ *
91
+ * @param {string} path
92
+ * @param {*} value
93
+ * @return {Datasource}
94
+ */
95
+ self["setInternal"] = (path, value) => {
96
+ new Pathfinder(self[internalSymbol].getSubject()).setVia(path, value);
97
+ return self;
98
+ }
99
+
100
+ /**
101
+ * set multiple internals at once
102
+ *
103
+ * @param {string|object} options
104
+ * @return {Datasource}
105
+ * @throws {Error} the options does not contain a valid json definition
106
+ */
107
+ self["setInternals"] = (options) => {
108
+ if (isString(options)) {
109
+ options = parseOptionsJSON(options);
110
+ }
111
+
112
+ extend(self[internalSymbol].getSubject(), defaults, options);
113
+ return self;
114
+ }
115
+
116
+ /**
117
+ * nested internals can be specified by path `a.b.c`
118
+ *
119
+ * @param {string} path
120
+ * @param {*} defaultValue
121
+ * @return {*}
122
+ */
123
+ self["getInternal"] = (path, defaultValue) => {
124
+ let value;
125
+
126
+ try {
127
+ value = new Pathfinder(self[internalSymbol]
128
+ .getRealSubject()).getVia(path);
129
+ } catch (e) {
130
+ }
131
+
132
+ if (value === undefined) return defaultValue;
133
+ return value;
134
+ }
135
+ }
136
+
137
+ /**
138
+ * @private
139
+ * @param obj
140
+ * @param prop
141
+ * @return {boolean}
142
+ */
143
+ function hasGetter(obj, prop) {
144
+
145
+ while (isObject(obj)) {
146
+ if (Object.getOwnPropertyDescriptor(obj, prop)?.['get']) {
147
+ return true;
148
+ }
149
+ obj = Object.getPrototypeOf(obj);
150
+ }
151
+
152
+ return false;
153
+ }
154
+
155
+ /**
156
+ * @private
157
+ * @param data
158
+ * @return {Object}
159
+ */
160
+ function parseOptionsJSON(data) {
161
+ let obj = {};
162
+
163
+ if (!isString(data)) {
164
+ return obj;
165
+ }
166
+
167
+ // the configuration can be specified as a data url.
168
+ try {
169
+ let dataUrl = parseDataURL(data);
170
+ data = dataUrl.content;
171
+ } catch (e) {
172
+ }
173
+
174
+ try {
175
+ obj = JSON.parse(data);
176
+ } catch (e) {
177
+ throw e;
178
+ }
179
+
180
+ return validateObject(obj);
181
+ }
@@ -142,7 +142,7 @@ function getMonsterVersion() {
142
142
  }
143
143
 
144
144
  /** don't touch, replaced by make with package.json version */
145
- monsterVersion = new Version("3.14.1");
145
+ monsterVersion = new Version("3.16.0");
146
146
 
147
147
  return monsterVersion;
148
148
  }
@@ -27,6 +27,17 @@ describe('Transformer', function () {
27
27
  describe('Transformer.run()', function () {
28
28
 
29
29
  [
30
+ ['map:a=4:b=5:c=6', "a", "4"],
31
+ ['date', "2023-02-14", "14.2.2023"],
32
+ ['year', "2023-02-14", 2023],
33
+ ['month', "2023-02-14", 2],
34
+ ['day', "2023-02-14", 14],
35
+ ['weekday', "2023-02-14", 2],
36
+ ['minutes', "2023-02-14 06:12:21", 12],
37
+ ['seconds', "2023-02-14 06:12:21", 21],
38
+ ['hours', "2023-02-14 06:12:21", 6],
39
+ ['time', "2023-02-14 06:12:21", "06:12:21"],
40
+ ['timestamp', "2023-02-14", 1676332800000],
30
41
  ['concat:a.b.c:test:a.b.d', {a: {b: {c: 4, d: 6}}}, "4test6"],
31
42
  ['concat:a.b.c:\\ \\ :a.b.d', {a: {b: {c: 4, d: 6}}}, "4 6"],
32
43
  ['concat:a.b.c:,:a.b.d', {a: {b: {c: 4, d: 6}}}, "4,6"],
@@ -7,7 +7,7 @@ describe('Monster', function () {
7
7
  let monsterVersion
8
8
 
9
9
  /** don´t touch, replaced by make with package.json version */
10
- monsterVersion = new Version("3.14.1")
10
+ monsterVersion = new Version("3.16.0")
11
11
 
12
12
  let m = getMonsterVersion();
13
13
 
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+
3
+ import {expect} from "chai"
4
+ import {equipWithInternal} from "../../../../application/source/types/internal.mjs";
5
+ import {Observer} from "../../../../application/source/types/observer.mjs";
6
+
7
+ class SomeRandomClass1 extends Object {
8
+
9
+ doit() {
10
+ return "done";
11
+ }
12
+ }
13
+
14
+ class SomeRandomClass2 extends Object {
15
+
16
+ constructor() {
17
+ super();
18
+ equipWithInternal.call(this);
19
+ }
20
+
21
+ get defaultInternal() {
22
+ return {
23
+ test: "test"
24
+ }
25
+ }
26
+
27
+ }
28
+
29
+ describe('Base inject with options', function () {
30
+
31
+ describe('new SomeRandomClass', function () {
32
+
33
+ it('is instance of SomeRandomClass1', function () {
34
+ expect(new SomeRandomClass2).not.to.be.instanceOf(SomeRandomClass1);
35
+ expect(new SomeRandomClass2).to.be.instanceOf(SomeRandomClass2);
36
+ });
37
+
38
+ it('is instance of SomeRandomClass2', function () {
39
+ expect(new SomeRandomClass1).to.be.instanceOf(SomeRandomClass1);
40
+ expect(new SomeRandomClass1).not.to.be.instanceOf(SomeRandomClass2);
41
+ });
42
+
43
+ })
44
+
45
+ describe('Extends SomeRandomClass with internals', function () {
46
+
47
+ it('attach and notify internal observer', function (done) {
48
+ const c = new SomeRandomClass2;
49
+ c.attachInternalObserver(new Observer(() => {
50
+ done();
51
+ }));
52
+
53
+ c.setInternal("test", "test");
54
+
55
+ });
56
+
57
+ it('attach and remove internal observer', function () {
58
+ const c = new SomeRandomClass2;
59
+
60
+
61
+ const observer = new Observer(() => {
62
+
63
+ });
64
+
65
+ expect(c.containsInternalObserver(observer)).to.be.false;
66
+ c.attachInternalObserver(observer);
67
+ expect(c.containsInternalObserver(observer)).to.be.true;
68
+ c.detachInternalObserver(observer);
69
+ expect(c.containsInternalObserver(observer)).to.be.false;
70
+
71
+ });
72
+
73
+ it("getInternal and setInternal", function () {
74
+ const c = new SomeRandomClass2;
75
+ expect(c.setInternal("test", "yeah")).to.be.instanceOf(SomeRandomClass2);
76
+ expect(c.getInternal("test")).to.be.equal("yeah");
77
+ });
78
+
79
+ it("deal with default values", function () {
80
+ const testClass = class extends Object {
81
+ constructor() {
82
+ super();
83
+ equipWithInternal.call(this);
84
+ }
85
+
86
+ get internalDefaults() {
87
+ return {
88
+ test: "xyz"
89
+ }
90
+ }
91
+ }
92
+
93
+
94
+ const c = new testClass;
95
+ expect(c.getInternal("test")).to.be.equal("xyz");
96
+ expect(c.getInternal("test2", "abc")).to.be.equal("abc");
97
+ });
98
+
99
+ it("deal with defaults from defaults", function () {
100
+ const testClass = class extends Object {
101
+ constructor() {
102
+ super();
103
+ equipWithInternal.call(this);
104
+ }
105
+
106
+ get internalDefaults() {
107
+ return {
108
+ test: "xyz"
109
+ }
110
+ }
111
+ }
112
+
113
+ const testClass2 = class extends testClass {
114
+ constructor() {
115
+ super();
116
+ equipWithInternal.call(this);
117
+ }
118
+
119
+ get internalDefaults() {
120
+ return Object.assign({}, super.internalDefaults, {
121
+ test2: "abc"
122
+ })
123
+ }
124
+ }
125
+
126
+ const c = new testClass2;
127
+ expect(c.getInternal("test")).to.be.equal("xyz");
128
+ expect(c.getInternal("test2")).to.be.equal("abc");
129
+ });
130
+
131
+ it("set multiple values", function () {
132
+ const c = new SomeRandomClass2;
133
+ expect(c.setInternals({
134
+ test: "yeah",
135
+ test2: "yeah2"
136
+ })).to.be.instanceOf(SomeRandomClass2);
137
+ expect(c.getInternal("test")).to.be.equal("yeah");
138
+ expect(c.getInternal("test2")).to.be.equal("yeah2");
139
+
140
+ c.setInternals({
141
+ test2: "yeah2-new",
142
+ test3: "yeah3"
143
+ });
144
+
145
+ expect(c.getInternal("test")).to.be.equal("yeah");
146
+ expect(c.getInternal("test2")).to.be.equal("yeah2-new");
147
+ expect(c.getInternal("test3")).to.be.equal("yeah3");
148
+ });
149
+
150
+ });
151
+
152
+
153
+ })