Skip to content

Commit

Permalink
Merge pull request #376 from ppfeufer/better-js-option-merge
Browse files Browse the repository at this point in the history
[CHANGE] Better way to merge JS options
  • Loading branch information
ppfeufer authored Nov 28, 2024
2 parents 87ae097 + bd3417c commit a408198
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 18 deletions.
70 changes: 55 additions & 15 deletions afat/static/afat/javascript/afat.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,63 @@
/* global afatJsSettingsOverride, afatJsSettingsDefaults */

/* jshint -W097 */
'use strict';

/**
* Checks if the given item is a plain object, excluding arrays and dates.
*
* @param {*} item - The item to check.
* @returns {boolean} True if the item is a plain object, false otherwise.
*/
function isObject (item) {
return (
item && typeof item === 'object' && !Array.isArray(item) && !(item instanceof Date)
);
}

/**
* Recursively merges properties from source objects into a target object. If a property at the current level is an object,
* and both target and source have it, the property is merged. Otherwise, the source property overwrites the target property.
* This function does not modify the source objects and prevents prototype pollution by not allowing __proto__, constructor,
* and prototype property names.
*
* @param {Object} target - The target object to merge properties into.
* @param {...Object} sources - One or more source objects from which to merge properties.
* @returns {Object} The target object after merging properties from sources.
*/
function deepMerge (target, ...sources) {
if (!sources.length) {
return target;
}

// Iterate through each source object without modifying the `sources` array.
sources.forEach(source => {
if (isObject(target) && isObject(source)) {
for (const key in source) {
if (isObject(source[key])) {
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
continue; // Skip potentially dangerous keys to prevent prototype pollution.
}

if (!target[key] || !isObject(target[key])) {
target[key] = {};
}

deepMerge(target[key], source[key]);
} else {
target[key] = source[key];
}
}
}
});

return target;
}

// Build the settings object
let afatSettings = afatJsSettingsDefaults;
if (typeof afatJsSettingsOverride !== 'undefined') {
afatSettings = Object.assign(
{},
afatJsSettingsDefaults,
afatJsSettingsOverride
);
afatSettings = deepMerge(afatJsSettingsDefaults, afatJsSettingsOverride);
}

/**
Expand All @@ -24,8 +74,6 @@ const AFAT_DATETIME_FORMAT = afatSettings.datetimeFormat; // eslint-disable-line
* @returns {Promise<any>} The fetched data
*/
const fetchAjaxData = async (url) => { // eslint-disable-line no-unused-vars
'use strict';

return await fetch(url)
.then(response => {
if (response.ok) {
Expand All @@ -49,8 +97,6 @@ const fetchAjaxData = async (url) => { // eslint-disable-line no-unused-vars
* @returns {string}
*/
const convertStringToSlug = (text) => { // eslint-disable-line no-unused-vars
'use strict';

return text.toLowerCase()
.replace(/[^\w ]+/g, '')
.replace(/ +/g, '-');
Expand All @@ -62,8 +108,6 @@ const convertStringToSlug = (text) => { // eslint-disable-line no-unused-vars
* @param {string} order
*/
const sortTable = (table, order) => { // eslint-disable-line no-unused-vars
'use strict';

const asc = order === 'asc';
const tbody = table.find('tbody');

Expand All @@ -81,8 +125,6 @@ const sortTable = (table, order) => { // eslint-disable-line no-unused-vars
* @param {element} modalElement
*/
const manageModal = (modalElement) => { // eslint-disable-line no-unused-vars
'use strict';

/**
* Set modal buttons
*
Expand Down Expand Up @@ -163,8 +205,6 @@ const manageModal = (modalElement) => { // eslint-disable-line no-unused-vars
* Prevent double form submits
*/
document.querySelectorAll('form').forEach((form) => {
'use strict';

form.addEventListener('submit', (e) => {
// Prevent if already submitting
if (form.classList.contains('is-submitting')) {
Expand Down
2 changes: 1 addition & 1 deletion afat/static/afat/javascript/afat.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion afat/static/afat/javascript/afat.min.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion afat/templates/afat/bundles/afat-js.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

<script
src="{% afat_static 'afat/javascript/afat.min.js' %}"
integrity="sha512-bbibwloWigl/JVDH9rSfUaWhaYNbPuNk9bz1kyuG0Quz6ThojVuhVetpMHglhkfgjUgZ7Pijexu3cj5FuTAsYg=="
integrity="sha512-ogpd4OZl6w+qpRnIDZHYAiVsC/PiVofRcKw1zv2/9fhW0Yq8/LpFnC1wow0pJ7YD+ZUlN3sTjA/ZaP/5R3WR7A=="
crossorigin="anonymous"
></script>

0 comments on commit a408198

Please sign in to comment.