@schukai/monster 3.38.0 → 3.38.1
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
@@ -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