# 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}
```

### numberFormatter()

Formats a number according to the specified locale.
Usage:

In your template get the current language code:

```django
{% get_current_language as LANGUAGE_CODE %}
```

Then use it in your JavaScript code:

```javascript
/* global numberFormatter */

const userLocale = '{{ LANGUAGE_CODE }}'; // e.g., 'en-US', 'de-DE'
const number = 1234567.89;

const formattedNumber = numberFormatter({
    value: number,
    locales: userLocale,
    options: {
        style: 'currency',
        currency: 'ISK'
    }
});

console.log(formattedNumber); // e.g. "ISK 1,234,567.89" or "1.234.567,89 ISK" depending on locale
```

#### numberFormatter() Parameters

- `value`: The number to format.
- `locales`: The locale(s) to use for formatting (e.g., `en-US`, `de-DE`, `['en-US',
'de-DE']`). If not provided, the browser's default locale will be used and any
  language settings from the user will be ignored.
- `options`: Additional options for number formatting (see [`Intl.NumberFormat` documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat))
  - `minimumFractionDigits` is set to 0 by default if not provided.
  - `maximumFractionDigits` is set to 2 by default if not provided.
