@schukai/monster
Version:
Monster is a simple library for creating fast, robust and lightweight websites.
115 lines (103 loc) • 4.17 kB
JavaScript
/**
* Copyright © Volker Schukai and all contributing authors, {{copyRightYear}}. All rights reserved.
* Node module: @schukai/monster
*
* This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3).
* The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html
*
* For those who do not wish to adhere to the AGPLv3, a commercial license is available.
* Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms.
* For more information about purchasing a commercial license, please contact Volker Schukai.
*
* SPDX-License-Identifier: AGPL-3.0
*/
import { Pathfinder } from "../../data/pathfinder.mjs";
import {
isFunction,
isBoolean,
isString,
isObject,
isNumber,
isArray,
isInteger,
} from "../../types/is.mjs";
import { attributeObserverSymbol } from "../customelement.mjs";
import { extractKeys } from "./extract-keys.mjs";
export { setOptionFromAttribute };
/**
* Set the given options object based on the attributes of the current DOM element.
* The function looks for attributes with the prefix 'data-monster-option-', and maps them to
* properties in the options object. It replaces the dashes with dots to form the property path.
* For example, the attribute 'data-monster-option-url' maps to the 'url' property in the options object.
*
* With the mapping parameter, the attribute value can be mapped to a different value.
* For example, the attribute 'data-monster-option-foo' maps to the 'bar' property in the options object.
*
* The mapping object would look like this:
* {
* 'foo': (value) => value + 'bar'
* // the value of the attribute 'data-monster-option-foo' is appended with 'bar'
* // and assigned to the 'bar' property in the options object.
* // e.g. <div data-monster-option-foo="foo"></div>
* 'bar.baz': (value) => value + 'bar'
* // the value of the attribute 'data-monster-option-bar-baz' is appended with 'bar'
* // and assigned to the 'bar.baz' property in the options object.
* // e.g. <div data-monster-option-bar-baz="foo"></div>
* }
*
* @since 3.45.0
* @param {HTMLElement} element - The DOM element to be used as the source of the attributes.
* @param {Object} name - The attribute object to be used as the source of the attributes.
* @param {Object} options - The options object to be initialized.
* @param {Object} mapping - A mapping between the attribute value and the property value.
* @param {string} prefix - The prefix of the attributes to be considered.
* @return {Object} - The initialized options object.
* @this HTMLElement - The context of the DOM element.
*/
function setOptionFromAttribute(
element,
name,
options,
mapping = {},
prefix = "data-monster-option-",
) {
if (!(element instanceof HTMLElement)) return options;
if (!element.hasAttributes()) return options;
const keyMap = extractKeys(options);
const finder = new Pathfinder(options);
// check if the attribute name is a valid option.
// the mapping between the attribute is simple. The dash is replaced by a dot.
// e.g. data-monster-url => url
const optionName = keyMap.get(name.substring(prefix.length).toLowerCase());
if (!finder.exists(optionName)) return;
if (!element.hasAttribute(name)) {
return options;
}
let value = element.getAttribute(name);
if (mapping.hasOwnProperty(optionName) && isFunction(mapping[optionName])) {
value = mapping[optionName](value);
}
let optionValue = finder.getVia(optionName);
if (optionValue === null || optionValue === undefined) {
optionValue = value;
}
if (optionValue === null || optionValue === undefined) {
value = null;
} else if (isBoolean(optionValue)) {
value = value === "true";
} else if (isInteger(optionValue)) {
value = Number(value);
} else if (isNumber(optionValue)) {
value = Number(value);
} else if (isString(optionValue)) {
value = String(value);
} else if (isObject(optionValue)) {
value = JSON.parse(value);
} else if (isArray(optionValue)) {
value = value.split("::");
} else {
value = optionValue;
}
finder.setVia(optionName, value);
return options;
}