mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2025-08-24 19:01:42 +02:00
Compare commits
7 Commits
a787a07d57
...
2d39bde8e1
Author | SHA1 | Date | |
---|---|---|---|
|
2d39bde8e1 | ||
|
0360184c2d | ||
|
099a39a2a2 | ||
|
c1cd7ca64f | ||
|
4cc108ab7f | ||
|
0028310aa5 | ||
|
18e9453fed |
@ -15,6 +15,10 @@
|
|||||||
ul#nav-right:has(li) + ul#nav-right-character-control > li:first-child {
|
ul#nav-right:has(li) + ul#nav-right-character-control > li:first-child {
|
||||||
display: list-item !important;
|
display: list-item !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
form.is-submitting button[type="submit"] {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media all and (max-width: 991px) {
|
@media all and (max-width: 991px) {
|
||||||
|
@ -0,0 +1,300 @@
|
|||||||
|
/**
|
||||||
|
* Functions and utilities for the Alliance Auth framework.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* jshint -W097 */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given item is an array.
|
||||||
|
*
|
||||||
|
* @usage
|
||||||
|
* ```javascript
|
||||||
|
* if (isArray(someVariable)) {
|
||||||
|
* console.log('This is an array');
|
||||||
|
* } else {
|
||||||
|
* console.log('This is not an array');
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param {*} item - The item to check.
|
||||||
|
* @returns {boolean} True if the item is an array, false otherwise.
|
||||||
|
*/
|
||||||
|
const isArray = (item) => {
|
||||||
|
return Array.isArray(item);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given item is a plain object, excluding arrays and dates.
|
||||||
|
*
|
||||||
|
* @usage
|
||||||
|
* ```javascript
|
||||||
|
* if (isObject(someVariable)) {
|
||||||
|
* console.log('This is a plain object');
|
||||||
|
* } else {
|
||||||
|
* console.log('This is not a plain object');
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param {*} item - The item to check.
|
||||||
|
* @returns {boolean} True if the item is a plain object, false otherwise.
|
||||||
|
*/
|
||||||
|
const isObject = (item) => {
|
||||||
|
return (
|
||||||
|
item && typeof item === 'object' && !isArray(item) && !(item instanceof Date)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch data from an ajax URL
|
||||||
|
*
|
||||||
|
* Do not call this function directly, use `fetchGet` or `fetchPost` instead.
|
||||||
|
*
|
||||||
|
* @param {string} url The URL to fetch data from
|
||||||
|
* @param {string} method The HTTP method to use for the request (default: 'get')
|
||||||
|
* @param {string|null} csrfToken The CSRF token to include in the request headers (default: null)
|
||||||
|
* @param {string|null} payload The payload (JSON|Object) to send with the request (default: null)
|
||||||
|
* @param {boolean} responseIsJson Whether the response is expected to be JSON or not (default: true)
|
||||||
|
* @returns {Promise<string>} The fetched data
|
||||||
|
* @throws {Error} Throws an error when:
|
||||||
|
* - The method is not valid (only `get` and `post` are allowed).
|
||||||
|
* - The CSRF token is required but not provided for POST requests.
|
||||||
|
* - The payload is not an object when using POST method.
|
||||||
|
* - The response status is not OK (HTTP 200-299).
|
||||||
|
* - There is a network error or if the response cannot be parsed as JSON.
|
||||||
|
*/
|
||||||
|
const _fetchAjaxData = async ({
|
||||||
|
url,
|
||||||
|
method = 'get',
|
||||||
|
csrfToken = null,
|
||||||
|
payload = null,
|
||||||
|
responseIsJson = true
|
||||||
|
}) => {
|
||||||
|
const normalizedMethod = method.toLowerCase();
|
||||||
|
|
||||||
|
// Validate the method
|
||||||
|
const validMethods = ['get', 'post'];
|
||||||
|
|
||||||
|
if (!validMethods.includes(normalizedMethod)) {
|
||||||
|
throw new Error(`Invalid method: ${method}. Valid methods are: get, post`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const headers = {};
|
||||||
|
|
||||||
|
// Set headers based on response type
|
||||||
|
if (responseIsJson) {
|
||||||
|
headers['Accept'] = 'application/json'; // jshint ignore:line
|
||||||
|
headers['Content-Type'] = 'application/json';
|
||||||
|
}
|
||||||
|
|
||||||
|
let requestUrl = url;
|
||||||
|
let body = null;
|
||||||
|
|
||||||
|
if (normalizedMethod === 'post') {
|
||||||
|
if (!csrfToken) {
|
||||||
|
throw new Error('CSRF token is required for POST requests');
|
||||||
|
}
|
||||||
|
|
||||||
|
headers['X-CSRFToken'] = csrfToken;
|
||||||
|
|
||||||
|
if (payload !== null && !isObject(payload)) {
|
||||||
|
throw new Error('Payload must be an object when using POST method');
|
||||||
|
}
|
||||||
|
|
||||||
|
body = payload ? JSON.stringify(payload) : null;
|
||||||
|
} else if (normalizedMethod === 'get' && payload) {
|
||||||
|
const queryParams = new URLSearchParams(payload).toString(); // jshint ignore:line
|
||||||
|
|
||||||
|
requestUrl += (url.includes('?') ? '&' : '?') + queryParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throws an error with a formatted message.
|
||||||
|
*
|
||||||
|
* @param {Response} response The error object containing the message to throw.
|
||||||
|
*/
|
||||||
|
const throwHTTPStatusError = (response) => {
|
||||||
|
throw new Error(`Error: ${response.status} - ${response.statusText}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(requestUrl, {
|
||||||
|
method: method.toUpperCase(),
|
||||||
|
headers: headers,
|
||||||
|
body: body
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throws an error if the response status is not OK (HTTP 200-299).
|
||||||
|
* This is used to handle HTTP errors gracefully.
|
||||||
|
*/
|
||||||
|
if (!response.ok) {
|
||||||
|
throwHTTPStatusError(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
return responseIsJson ? await response.json() : await response.text();
|
||||||
|
} catch (error) {
|
||||||
|
// Log the error message to the console
|
||||||
|
console.log(`Error: ${error.message}`);
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch data from an ajax URL using the GET method.
|
||||||
|
* This function is a wrapper around _fetchAjaxData to simplify GET requests.
|
||||||
|
*
|
||||||
|
* @usage
|
||||||
|
* ```javascript
|
||||||
|
* fetchGet({
|
||||||
|
* url: url,
|
||||||
|
* responseIsJson: false
|
||||||
|
* }).then((data) => {
|
||||||
|
* // Process the fetched data
|
||||||
|
* }).catch((error) => {
|
||||||
|
* console.error(`Error: ${error.message}`);
|
||||||
|
*
|
||||||
|
* // Handle the error appropriately
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param {string} url The URL to fetch data from
|
||||||
|
* @param {string|null} payload The payload (JSON) to send with the request (default: null)
|
||||||
|
* @param {boolean} responseIsJson Whether the response is expected to be JSON or not (default: true)
|
||||||
|
* @return {Promise<string>} The fetched data
|
||||||
|
*/
|
||||||
|
const fetchGet = async ({
|
||||||
|
url,
|
||||||
|
payload = null,
|
||||||
|
responseIsJson = true
|
||||||
|
}) => {
|
||||||
|
return await _fetchAjaxData({
|
||||||
|
url: url,
|
||||||
|
method: 'get',
|
||||||
|
payload: payload,
|
||||||
|
responseIsJson: responseIsJson
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch data from an ajax URL using the POST method.
|
||||||
|
* This function is a wrapper around _fetchAjaxData to simplify POST requests.
|
||||||
|
* It requires a CSRF token for security purposes.
|
||||||
|
*
|
||||||
|
* @usage
|
||||||
|
* ```javascript
|
||||||
|
* fetchPost({
|
||||||
|
* url: url,
|
||||||
|
* csrfToken: csrfToken,
|
||||||
|
* payload: {
|
||||||
|
* key: 'value',
|
||||||
|
* anotherKey: 'anotherValue'
|
||||||
|
* },
|
||||||
|
* responseIsJson: true
|
||||||
|
* }).then((data) => {
|
||||||
|
* // Process the fetched data
|
||||||
|
* }).catch((error) => {
|
||||||
|
* console.error(`Error: ${error.message}`);
|
||||||
|
*
|
||||||
|
* // Handle the error appropriately
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param {string} url The URL to fetch data from
|
||||||
|
* @param {string|null} csrfToken The CSRF token to include in the request headers (default: null)
|
||||||
|
* @param {string|null} payload The payload (JSON) to send with the request (default: null)
|
||||||
|
* @param {boolean} responseIsJson Whether the response is expected to be JSON or not (default: true)
|
||||||
|
* @return {Promise<string>} The fetched data
|
||||||
|
*/
|
||||||
|
const fetchPost = async ({
|
||||||
|
url,
|
||||||
|
csrfToken,
|
||||||
|
payload = null,
|
||||||
|
responseIsJson = true
|
||||||
|
}) => {
|
||||||
|
return await _fetchAjaxData({
|
||||||
|
url: url,
|
||||||
|
method: 'post',
|
||||||
|
csrfToken: csrfToken,
|
||||||
|
payload: payload,
|
||||||
|
responseIsJson: responseIsJson
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @usage
|
||||||
|
* ```javascript
|
||||||
|
* const target = {a: 1, b: {c: 2}};
|
||||||
|
* const source1 = {b: {d: 3}, e: 4 };
|
||||||
|
* const source2 = {a: 5, b: {c: 6}};
|
||||||
|
*
|
||||||
|
* const merged = objectDeepMerge(target, source1, source2);
|
||||||
|
*
|
||||||
|
* console.log(merged); // {a: 5, b: {c: 6, d: 3}, e: 4}
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @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 objectDeepMerge (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] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
objectDeepMerge(target[key], source[key]);
|
||||||
|
} else {
|
||||||
|
target[key] = source[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the document is ready …
|
||||||
|
*/
|
||||||
|
$(document).ready(() => {
|
||||||
|
/**
|
||||||
|
* Prevent double form submits by adding a class to the form
|
||||||
|
* when it is submitted.
|
||||||
|
*
|
||||||
|
* This class can be used to show a visual indicator that the form is being
|
||||||
|
* submitted, such as a spinner.
|
||||||
|
*
|
||||||
|
* This is useful to prevent users from double-clicking the submit button
|
||||||
|
* and submitting the form multiple times.
|
||||||
|
*/
|
||||||
|
document.querySelectorAll('form').forEach((form) => {
|
||||||
|
form.addEventListener('submit', (e) => {
|
||||||
|
// Prevent if already submitting
|
||||||
|
if (form.classList.contains('is-submitting')) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add class to hook our visual indicator on
|
||||||
|
form.classList.add('is-submitting');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -1,4 +1,4 @@
|
|||||||
/* global notificationUpdateSettings */
|
/* global notificationUpdateSettings, fetchGet */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This script refreshed the notification icon in the top menu
|
* This script refreshed the notification icon in the top menu
|
||||||
@ -19,22 +19,9 @@ $(() => {
|
|||||||
* Update the notification icon in the top menu
|
* Update the notification icon in the top menu
|
||||||
*/
|
*/
|
||||||
const updateNotificationIcon = () => {
|
const updateNotificationIcon = () => {
|
||||||
fetch(userNotificationCountViewUrl)
|
fetchGet({url: userNotificationCountViewUrl})
|
||||||
.then((response) => {
|
.then((data) => {
|
||||||
if (response.ok) {
|
elementNotificationIcon.toggleClass('text-danger', data.unread_count > 0);
|
||||||
return response.json();
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error('Something went wrong');
|
|
||||||
})
|
|
||||||
.then((responseJson) => {
|
|
||||||
const unreadCount = responseJson.unread_count;
|
|
||||||
|
|
||||||
if (unreadCount > 0) {
|
|
||||||
elementNotificationIcon.addClass('text-danger');
|
|
||||||
} else {
|
|
||||||
elementNotificationIcon.removeClass('text-danger');
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.log(`Failed to load HTMl to render notifications item. Error: ${error.message}`);
|
console.log(`Failed to load HTMl to render notifications item. Error: ${error.message}`);
|
||||||
|
@ -8,30 +8,22 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const elemCard = document.getElementById("esi-alert");
|
const elemCard = document.getElementById('esi-alert');
|
||||||
const elemMessage = document.getElementById("esi-data");
|
const elemMessage = document.getElementById('esi-data');
|
||||||
const elemCode = document.getElementById("esi-code");
|
const elemCode = document.getElementById('esi-code');
|
||||||
|
|
||||||
fetch('{% url "authentication:esi_check" %}')
|
fetchGet({url: '{% url "authentication:esi_check" %}'})
|
||||||
.then((response) => {
|
.then((data) => {
|
||||||
if (response.ok) {
|
console.log('ESI Check: ', JSON.stringify(data, null, 2));
|
||||||
return response.json();
|
|
||||||
}
|
|
||||||
throw new Error("Something went wrong");
|
|
||||||
})
|
|
||||||
.then((responseJson) => {
|
|
||||||
console.log("ESI Check: ", JSON.stringify(responseJson, null, 2));
|
|
||||||
|
|
||||||
const status = responseJson.status;
|
if (data.status !== 200) {
|
||||||
if (status !== 200) {
|
elemCode.textContent = data.status;
|
||||||
elemCode.textContent = status
|
elemMessage.textContent = data.data.error;
|
||||||
elemMessage.textContent = responseJson.data.error;
|
|
||||||
new bootstrap.Collapse(elemCard, {
|
new bootstrap.Collapse(elemCard, {toggle: true});
|
||||||
toggle: true
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.log(error);
|
console.error('Error fetching ESI check:', error);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -133,34 +133,24 @@
|
|||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const elemRunning = document.getElementById("task-counts");
|
const elemRunning = document.getElementById('task-counts');
|
||||||
const elemQueued = document.getElementById("queued-tasks-count");
|
const elemQueued = document.getElementById('queued-tasks-count');
|
||||||
|
|
||||||
fetch('{% url "authentication:task_counts" %}')
|
fetchGet({url: '{% url "authentication:task_counts" %}'})
|
||||||
.then((response) => {
|
.then((data) => {
|
||||||
if (response.ok) {
|
const running = data.tasks_running;
|
||||||
return response.json();
|
const queued = data.tasks_queued;
|
||||||
}
|
|
||||||
throw new Error("Something went wrong");
|
|
||||||
})
|
|
||||||
.then((responseJson) => {
|
|
||||||
const running = responseJson.tasks_running;
|
|
||||||
if (running == null) {
|
|
||||||
elemRunning.textContent = "N/A";
|
|
||||||
} else {
|
|
||||||
elemRunning.textContent = running.toLocaleString();
|
|
||||||
}
|
|
||||||
|
|
||||||
const queued = responseJson.tasks_queued;
|
const updateTaskCount = (element, value) => {
|
||||||
if (queued == null) {
|
element.textContent = value == null ? 'N/A' : value.toLocaleString();
|
||||||
elemQueued.textContent = "N/A";
|
};
|
||||||
} else {
|
|
||||||
elemQueued.textContent = queued.toLocaleString();
|
updateTaskCount(elemRunning, running);
|
||||||
}
|
updateTaskCount(elemQueued, queued);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.log(error);
|
console.error('Error fetching task queue:', error);
|
||||||
elemRunning.textContent = "ERROR";
|
|
||||||
elemQueued.textContent = "ERROR";
|
[elemRunning, elemQueued].forEach(elem => elem.textContent = 'ERROR');
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
{% include 'bundles/fontawesome.html' %}
|
{% include 'bundles/fontawesome.html' %}
|
||||||
{% include 'bundles/auth-framework-css.html' %}
|
{% include 'bundles/auth-framework-css.html' %}
|
||||||
|
|
||||||
|
{% include 'bundles/jquery-js.html' %}
|
||||||
|
{% include 'bundles/auth-framework-js.html' %}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@media all {
|
@media all {
|
||||||
.nav-padding {
|
.nav-padding {
|
||||||
@ -137,8 +140,6 @@
|
|||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% include 'bundles/jquery-js.html' %}
|
|
||||||
|
|
||||||
{% theme_js %}
|
{% theme_js %}
|
||||||
|
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
|
3
allianceauth/templates/bundles/auth-framework-js.html
Normal file
3
allianceauth/templates/bundles/auth-framework-js.html
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{% load sri %}
|
||||||
|
|
||||||
|
{% sri_static 'allianceauth/framework/js/auth-framework.js' %}
|
@ -13,5 +13,6 @@ The Alliance Auth framework is split into several submodules, each of which is d
|
|||||||
|
|
||||||
framework/api
|
framework/api
|
||||||
framework/css
|
framework/css
|
||||||
|
framework/js
|
||||||
framework/templates
|
framework/templates
|
||||||
:::
|
:::
|
||||||
|
124
docs/development/custom/framework/js.md
Normal file
124
docs/development/custom/framework/js.md
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
# JavaScript Framework
|
||||||
|
|
||||||
|
This contains some simple JavaScript functions that are used throughout Alliance Auth,
|
||||||
|
so they can be used by community app developers as well.
|
||||||
|
|
||||||
|
The JS file is already loaded in the base template, so it is globally available.
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
|
||||||
|
The following functions are available in the JavaScript framework:
|
||||||
|
|
||||||
|
### isArray()
|
||||||
|
|
||||||
|
Checks if the given value is an array.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
/* global isArray */
|
||||||
|
|
||||||
|
if (isArray(someVariable)) {
|
||||||
|
console.log('This is an array');
|
||||||
|
} else {
|
||||||
|
console.log('This is not an array');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### isObject()
|
||||||
|
|
||||||
|
Checks if the given value is an object.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
/* global isObject */
|
||||||
|
|
||||||
|
if (isObject(someVariable)) {
|
||||||
|
console.log('This is a plain object');
|
||||||
|
} else {
|
||||||
|
console.log('This is not a plain object');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### fetchGet()
|
||||||
|
|
||||||
|
Performs a GET request to the given URL and returns a Promise that resolves with the response data.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
/* global fetchGet */
|
||||||
|
|
||||||
|
fetchGet({
|
||||||
|
url: url,
|
||||||
|
responseIsJson: false
|
||||||
|
}).then((data) => {
|
||||||
|
// Process the fetched data
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error(`Error: ${error.message}`);
|
||||||
|
|
||||||
|
// Handle the error appropriately
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### fetchGet() Parameters
|
||||||
|
|
||||||
|
- `url`: The URL to fetch data from.
|
||||||
|
- `payload`: Optional data to send with the request. Can be an object or a string.
|
||||||
|
- `responseIsJson`: Optional boolean indicating if the response should be parsed as JSON (default is `true`).
|
||||||
|
|
||||||
|
### fetchPost()
|
||||||
|
|
||||||
|
Performs a POST request to the given URL with the provided data and returns a Promise that resolves with the response data.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
/* global fetchPost */
|
||||||
|
|
||||||
|
fetchPost({
|
||||||
|
url: url,
|
||||||
|
csrfToken: csrfToken,
|
||||||
|
payload: {
|
||||||
|
key: 'value',
|
||||||
|
anotherKey: 'anotherValue'
|
||||||
|
},
|
||||||
|
responseIsJson: true
|
||||||
|
}).then((data) => {
|
||||||
|
// Process the fetched data
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error(`Error: ${error.message}`);
|
||||||
|
|
||||||
|
// Handle the error appropriately
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### fetchPost() Parameters
|
||||||
|
|
||||||
|
- `url`: The URL to send the POST request to.
|
||||||
|
- `csrfToken`: The CSRF token to include in the request headers.
|
||||||
|
- `payload`: The data as JS object to send with the request.
|
||||||
|
- `responseIsJson`: Optional boolean indicating if the response should be parsed as JSON (default is `true`).
|
||||||
|
|
||||||
|
### objectDeepMerge()
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
/* global objectDeepMerge */
|
||||||
|
|
||||||
|
const target = {a: 1, b: {c: 2}};
|
||||||
|
const source1 = {b: {d: 3}, e: 4 };
|
||||||
|
const source2 = {a: 5, b: {c: 6}};
|
||||||
|
|
||||||
|
const merged = objectDeepMerge(target, source1, source2);
|
||||||
|
|
||||||
|
console.log(merged); // {a: 5, b: {c: 6, d: 3}, e: 4}
|
||||||
|
```
|
Loading…
x
Reference in New Issue
Block a user