@schukai/monster 3.14.1 → 3.15.0

Sign up to get free protection for your applications and to get access to all the features.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schukai/monster",
3
- "version": "3.14.1",
3
+ "version": "3.15.0",
4
4
  "description": "Monster is a simple library for creating fast, robust and lightweight websites.",
5
5
  "keywords": [
6
6
  "framework",
@@ -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.15.0");
146
146
 
147
147
  return monsterVersion;
148
148
  }
@@ -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.15.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
+ })