@schukai/monster 3.38.0 → 3.38.1
Sign up to get free protection for your applications and to get access to all the features.
package/package.json
CHANGED
@@ -30,6 +30,7 @@ import { addObjectWithUpdaterToElement } from "./updater.mjs";
|
|
30
30
|
import { instanceSymbol } from "../constants.mjs";
|
31
31
|
import { getDocumentTranslations, Translations } from "../i18n/translations.mjs";
|
32
32
|
import { getSlottedElements } from "./slotted.mjs";
|
33
|
+
import {initOptionsFromAttributes} from "./util/init-options-from-attributes.mjs";
|
33
34
|
|
34
35
|
export {
|
35
36
|
CustomElement,
|
@@ -197,8 +198,9 @@ class CustomElement extends HTMLElement {
|
|
197
198
|
*/
|
198
199
|
constructor() {
|
199
200
|
super();
|
201
|
+
|
200
202
|
this[internalSymbol] = new ProxyObserver({
|
201
|
-
options: extend({}, this.defaults),
|
203
|
+
options: initOptionsFromAttributes(this, extend({}, this.defaults)),
|
202
204
|
});
|
203
205
|
this[attributeObserverSymbol] = {};
|
204
206
|
initOptionObserver.call(this);
|
@@ -8,17 +8,17 @@
|
|
8
8
|
import {Pathfinder} from '../../data/pathfinder.mjs';
|
9
9
|
import {isFunction} from '../../types/is.mjs';
|
10
10
|
|
11
|
-
export {initOptionsFromAttributes
|
11
|
+
export {initOptionsFromAttributes};
|
12
12
|
|
13
13
|
/**
|
14
14
|
* Initializes the given options object based on the attributes of the current DOM element.
|
15
15
|
* The function looks for attributes with the prefix 'data-monster-option-', and maps them to
|
16
16
|
* properties in the options object. It replaces the dashes with dots to form the property path.
|
17
17
|
* For example, the attribute 'data-monster-option-url' maps to the 'url' property in the options object.
|
18
|
-
*
|
18
|
+
*
|
19
19
|
* With the mapping parameter, the attribute value can be mapped to a different value.
|
20
20
|
* For example, the attribute 'data-monster-option-foo' maps to the 'bar' property in the options object.
|
21
|
-
*
|
21
|
+
*
|
22
22
|
* The mapping object would look like this:
|
23
23
|
* {
|
24
24
|
* 'foo': (value) => value + 'bar'
|
@@ -31,6 +31,7 @@ export {initOptionsFromAttributes };
|
|
31
31
|
* // e.g. <div data-monster-option-bar-baz="foo"></div>
|
32
32
|
* }
|
33
33
|
*
|
34
|
+
* @since 3.38.0
|
34
35
|
* @param {HTMLElement} element - The DOM element to be used as the source of the attributes.
|
35
36
|
* @param {Object} options - The options object to be initialized.
|
36
37
|
* @param {Object} mapping - A mapping between the attribute value and the property value.
|
@@ -38,10 +39,12 @@ export {initOptionsFromAttributes };
|
|
38
39
|
* @returns {Object} - The initialized options object.
|
39
40
|
* @this HTMLElement - The context of the DOM element.
|
40
41
|
*/
|
41
|
-
function initOptionsFromAttributes(element, options, mapping={},prefix = 'data-monster-option-') {
|
42
|
+
function initOptionsFromAttributes(element, options, mapping = {}, prefix = 'data-monster-option-') {
|
42
43
|
if (!(element instanceof HTMLElement)) return options;
|
43
44
|
if (!element.hasAttributes()) return options;
|
44
45
|
|
46
|
+
const keyMap = extractKeys(options);
|
47
|
+
|
45
48
|
const finder = new Pathfinder(options);
|
46
49
|
|
47
50
|
element.getAttributeNames().forEach((name) => {
|
@@ -50,15 +53,15 @@ function initOptionsFromAttributes(element, options, mapping={},prefix = 'data-m
|
|
50
53
|
// check if the attribute name is a valid option.
|
51
54
|
// the mapping between the attribute is simple. The dash is replaced by a dot.
|
52
55
|
// e.g. data-monster-url => url
|
53
|
-
const optionName = name.
|
56
|
+
const optionName = keyMap.get(name.substring(prefix.length).toLowerCase());
|
54
57
|
if (!finder.exists(optionName)) return;
|
55
58
|
|
56
59
|
if (element.hasAttribute(name)) {
|
57
60
|
let value = element.getAttribute(name);
|
58
|
-
if (mapping.hasOwnProperty(optionName)&&isFunction(mapping[optionName])) {
|
61
|
+
if (mapping.hasOwnProperty(optionName) && isFunction(mapping[optionName])) {
|
59
62
|
value = mapping[optionName](value);
|
60
63
|
}
|
61
|
-
|
64
|
+
|
62
65
|
const typeOfOptionValue = typeof finder.getVia(optionName);
|
63
66
|
if (typeOfOptionValue === 'boolean') {
|
64
67
|
value = value === 'true';
|
@@ -69,10 +72,41 @@ function initOptionsFromAttributes(element, options, mapping={},prefix = 'data-m
|
|
69
72
|
} else if (typeOfOptionValue === 'object') {
|
70
73
|
value = JSON.parse(value);
|
71
74
|
}
|
72
|
-
|
75
|
+
|
73
76
|
finder.setVia(optionName, value);
|
74
77
|
}
|
75
78
|
})
|
76
79
|
|
77
80
|
return options;
|
78
|
-
}
|
81
|
+
}
|
82
|
+
|
83
|
+
/**
|
84
|
+
* Extracts the keys from the given object and returns a map with the keys and values.
|
85
|
+
*
|
86
|
+
* @private
|
87
|
+
* @param {object} obj
|
88
|
+
* @param {string} keyPrefix
|
89
|
+
* @param {string} keySeparator
|
90
|
+
* @param {string} valueSeparator
|
91
|
+
* @returns {Map<any, any>}
|
92
|
+
*/
|
93
|
+
function extractKeys(obj, keyPrefix = '', keySeparator = '-', valueSeparator = '.') {
|
94
|
+
const resultMap = new Map();
|
95
|
+
|
96
|
+
function helper(currentObj, currentKeyPrefix, currentValuePrefix) {
|
97
|
+
for (const key in currentObj) {
|
98
|
+
if (typeof currentObj[key] === 'object' && !Array.isArray(currentObj[key])) {
|
99
|
+
const newKeyPrefix = currentKeyPrefix ? currentKeyPrefix + keySeparator + key.toLowerCase() : key.toLowerCase();
|
100
|
+
const newValuePrefix = currentValuePrefix ? currentValuePrefix + valueSeparator + key : key;
|
101
|
+
helper(currentObj[key], newKeyPrefix, newValuePrefix);
|
102
|
+
} else {
|
103
|
+
const finalKey = currentKeyPrefix ? currentKeyPrefix + keySeparator + key.toLowerCase() : key.toLowerCase();
|
104
|
+
const finalValue = currentValuePrefix ? currentValuePrefix + valueSeparator + key : key;
|
105
|
+
resultMap.set(finalKey, finalValue);
|
106
|
+
}
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
helper(obj, keyPrefix, keyPrefix);
|
111
|
+
return resultMap;
|
112
|
+
}
|
package/source/types/version.mjs
CHANGED
@@ -12,13 +12,13 @@ describe('initOptionsFromAttributes', () => {
|
|
12
12
|
})
|
13
13
|
|
14
14
|
beforeEach(() => {
|
15
|
-
options = { url: "", key: { subkey: "" } };
|
15
|
+
options = { url: "", key: { subkey: "", caseSensitive: true } };
|
16
16
|
element = document.createElement('div');
|
17
17
|
});
|
18
18
|
|
19
19
|
it('should initialize options with matching attributes', () => {
|
20
20
|
element.setAttribute('data-monster-option-url', 'https://example.com');
|
21
|
-
element.setAttribute('data-monster-option-key
|
21
|
+
element.setAttribute('data-monster-option-key-subkey', 'test');
|
22
22
|
|
23
23
|
const result = initOptionsFromAttributes(element, options);
|
24
24
|
|
@@ -73,7 +73,7 @@ describe('initOptionsFromAttributes', () => {
|
|
73
73
|
|
74
74
|
it('should apply multiple mappings', () => {
|
75
75
|
element.setAttribute('data-monster-option-url', 'example');
|
76
|
-
element.setAttribute('data-monster-option-key
|
76
|
+
element.setAttribute('data-monster-option-key-subkey', '123');
|
77
77
|
const mapping = {
|
78
78
|
'url': (value) => 'https://' + value + '.com',
|
79
79
|
'key.subkey': (value) => parseInt(value, 10) * 2
|
@@ -108,7 +108,7 @@ describe('initOptionsFromAttributes', () => {
|
|
108
108
|
|
109
109
|
it('should apply mapping only to specified attributes', () => {
|
110
110
|
element.setAttribute('data-monster-option-url', 'example');
|
111
|
-
element.setAttribute('data-monster-option-key
|
111
|
+
element.setAttribute('data-monster-option-key-subkey', '123');
|
112
112
|
const mapping = {
|
113
113
|
'url': (value) => 'https://' + value + '.com'
|
114
114
|
};
|
@@ -152,4 +152,11 @@ describe('initOptionsFromAttributes', () => {
|
|
152
152
|
expect(result.url).to.equal('');
|
153
153
|
});
|
154
154
|
|
155
|
+
it('should apply case sensitive mapping', () => {
|
156
|
+
element.setAttribute('data-monster-option-key-caseSensitive', 'false');
|
157
|
+
const result = initOptionsFromAttributes(element, options);
|
158
|
+
|
159
|
+
expect(result.key.caseSensitive).to.equal(false);
|
160
|
+
});
|
161
|
+
|
155
162
|
});
|
package/test/cases/monster.mjs
CHANGED