Current File : /home/pacjaorg/.trash/media.1/system/js/core.js |
(function () {
'use strict';
function _extends() {
return _extends = Object.assign ? Object.assign.bind() : function (n) {
for (var e = 1; e < arguments.length; e++) {
var t = arguments[e];
for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
}
return n;
}, _extends.apply(null, arguments);
}
/**
* --------------------------------------------------------------------------
* Bootstrap util/sanitizer.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
// js-docs-end allow-list
const uriAttributes = new Set(['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']);
/**
* A pattern that recognizes URLs that are safe wrt. XSS in URL navigation
* contexts.
*
* Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38
*/
// eslint-disable-next-line unicorn/better-regex
const SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i;
const allowedAttribute = (attribute, allowedAttributeList) => {
const attributeName = attribute.nodeName.toLowerCase();
if (allowedAttributeList.includes(attributeName)) {
if (uriAttributes.has(attributeName)) {
return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue));
}
return true;
}
// Check if a regular expression validates the attribute.
return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp).some(regex => regex.test(attributeName));
};
function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {
if (!unsafeHtml.length) {
return unsafeHtml;
}
if (sanitizeFunction && typeof sanitizeFunction === 'function') {
return sanitizeFunction(unsafeHtml);
}
const domParser = new window.DOMParser();
const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html');
const elements = [].concat(...createdDocument.body.querySelectorAll('*'));
for (const element of elements) {
const elementName = element.nodeName.toLowerCase();
if (!Object.keys(allowList).includes(elementName)) {
element.remove();
continue;
}
const attributeList = [].concat(...element.attributes);
const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || []);
for (const attribute of attributeList) {
if (!allowedAttribute(attribute, allowedAttributes)) {
element.removeAttribute(attribute.nodeName);
}
}
}
return createdDocument.body.innerHTML;
}
/**
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i;
const DATA_ATTRIBUTE_PATTERN = /^data-[\w-]*$/i;
const DefaultAllowlist = {
// Global attributes allowed on any supplied element below.
'*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN, DATA_ATTRIBUTE_PATTERN],
a: ['target', 'href', 'title', 'rel'],
area: [],
b: [],
br: [],
col: [],
code: [],
div: [],
em: [],
hr: [],
h1: [],
h2: [],
h3: [],
h4: [],
h5: [],
h6: [],
i: [],
img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],
li: [],
ol: [],
p: [],
pre: [],
s: [],
small: [],
span: [],
sub: [],
sup: [],
strong: [],
u: [],
ul: [],
button: ['type'],
input: ['accept', 'alt', 'autocomplete', 'autofocus', 'capture', 'checked', 'dirname', 'disabled', 'height', 'list', 'max', 'maxlength', 'min', 'minlength', 'multiple', 'type', 'name', 'pattern', 'placeholder', 'readonly', 'required', 'size', 'src', 'step', 'value', 'width', 'inputmode'],
select: ['name'],
textarea: ['name'],
option: ['value', 'selected']
};
// Only define the Joomla namespace if not defined.
window.Joomla = window.Joomla || {};
// Only define editors if not defined
Joomla.editors = Joomla.editors || {};
// An object to hold each editor instance on page, only define if not defined.
Joomla.editors.instances = Joomla.editors.instances || {
/**
* *****************************************************************
* All Editors MUST register, per instance, the following callbacks:
* *****************************************************************
*
* getValue Type Function Should return the complete data from the editor
* Example: () => { return this.element.value; }
* setValue Type Function Should replace the complete data of the editor
* Example: (text) => { return this.element.value = text; }
* getSelection Type Function Should return the selected text from the editor
* Example: function () { return this.selectedText; }
* disable Type Function Toggles the editor into disabled mode. When the editor is
* active then everything should be usable. When inactive the
* editor should be unusable AND disabled for form validation
* Example: (bool) => { return this.disable = value; }
* replaceSelection Type Function Should replace the selected text of the editor
* If nothing selected, will insert the data at the cursor
* Example:
* (text) => {
* return insertAtCursor(this.element, text);
* }
*
* USAGE (assuming that jform_articletext is the textarea id)
* {
* To get the current editor value:
* Joomla.editors.instances['jform_articletext'].getValue();
* To set the current editor value:
* Joomla.editors.instances['jform_articletext'].setValue('Joomla! rocks');
* To replace(selection) or insert a value at the current editor cursor (replaces the J3
* jInsertEditorText API):
* replaceSelection:
* Joomla.editors.instances['jform_articletext'].replaceSelection('Joomla! rocks')
* }
*
* *********************************************************
* ANY INTERACTION WITH THE EDITORS SHOULD USE THE ABOVE API
* *********************************************************
*/
};
Joomla.Modal = Joomla.Modal || {
/**
* *****************************************************************
* Modals should implement
* *****************************************************************
*
* getCurrent Type Function Should return the modal element
* setCurrent Type Function Should set the modal element
* current Type {node} The modal element
*
* USAGE (assuming that exampleId is the modal id)
* To get the current modal element:
* Joomla.Modal.getCurrent(); // Returns node element, eg: document.getElementById('exampleId')
* To set the current modal element:
* Joomla.Modal.setCurrent(document.getElementById('exampleId'));
*
* *************************************************************
* Joomla's UI modal uses `element.close();` to close the modal
* and `element.open();` to open the modal
* If you are using another modal make sure the same
* functionality is bound to the modal element
* @see media/legacy/bootstrap.init.js
* *************************************************************
*/
current: '',
setCurrent: element => {
Joomla.Modal.current = element;
},
getCurrent: () => Joomla.Modal.current
};
/**
* Method to Extend Objects
*
* @param {Object} destination
* @param {Object} source
*
* @return Object
*/
Joomla.extend = (destination, source) => {
let newDestination = destination;
/**
* Technically null is an object, but trying to treat the destination as one in this
* context will error out.
* So emulate jQuery.extend(), and treat a destination null as an empty object.
*/
if (destination === null) {
newDestination = {};
}
Object.keys(source).forEach(key => {
newDestination[key] = source[key];
});
return destination;
};
/**
* Joomla options storage
*
* @type {{}}
*
* @since 3.7.0
*/
Joomla.optionsStorage = Joomla.optionsStorage || null;
/**
* Get script(s) options
*
* @param {String} key Name in Storage
* @param {mixed} def Default value if nothing found
*
* @return {mixed}
*
* @since 3.7.0
*/
Joomla.getOptions = (key, def) => {
// Load options if they not exists
if (!Joomla.optionsStorage) {
Joomla.loadOptions();
}
return Joomla.optionsStorage[key] !== undefined ? Joomla.optionsStorage[key] : def;
};
/**
* Load new options from given options object or from Element
*
* @param {Object|undefined} options The options object to load.
* Eg {"com_foobar" : {"option1": 1, "option2": 2}}
*
* @since 3.7.0
*/
Joomla.loadOptions = options => {
// Load form the script container
if (!options) {
let counter = 0;
document.querySelectorAll('.joomla-script-options.new').forEach(element => {
const str = element.text || element.textContent;
const option = JSON.parse(str);
if (option) {
Joomla.loadOptions(option);
counter += 1;
}
element.className = element.className.replace(' new', ' loaded');
});
if (counter) {
return;
}
}
// Initial loading
if (!Joomla.optionsStorage) {
Joomla.optionsStorage = options || {};
} else if (options) {
// Merge with existing
Object.keys(options).forEach(key => {
/**
* If both existing and new options are objects, merge them with Joomla.extend().
* But test for new option being null, as null is an object, but we want to allow
* clearing of options with ...
*
* Joomla.loadOptions({'joomla.jtext': null});
*/
if (options[key] !== null && typeof Joomla.optionsStorage[key] === 'object' && typeof options[key] === 'object') {
Joomla.optionsStorage[key] = Joomla.extend(Joomla.optionsStorage[key], options[key]);
} else {
Joomla.optionsStorage[key] = options[key];
}
});
}
};
/**
* Custom behavior for JavaScript I18N in Joomla! 1.6
*
* @type {{}}
*
* Allows you to call Joomla.Text._() to get a translated JavaScript string
* pushed in with Text::script() in Joomla.
*/
Joomla.Text = {
strings: {},
/**
* Translates a string into the current language.
*
* @param {String} key The string to translate
* @param {String} def Default string
*
* @returns {String}
*/
_: (key, def) => {
let newKey = key;
let newDef = def;
// Check for new strings in the optionsStorage, and load them
const newStrings = Joomla.getOptions('joomla.jtext');
if (newStrings) {
Joomla.Text.load(newStrings);
// Clean up the optionsStorage from useless data
Joomla.loadOptions({
'joomla.jtext': null
});
}
newDef = newDef === undefined ? newKey : newDef;
newKey = newKey.toUpperCase();
return Joomla.Text.strings[newKey] !== undefined ? Joomla.Text.strings[newKey] : newDef;
},
/**
* Load new strings in to Joomla.Text
*
* @param {Object} object Object with new strings
* @returns {Joomla.Text}
*/
load: object => {
Object.keys(object).forEach(key => {
Joomla.Text.strings[key.toUpperCase()] = object[key];
});
return Joomla.Text;
}
};
/**
* For B/C we still support Joomla.JText
*
* @type {{}}
*
* @deprecated 4.0 will be removed in 6.0
* Example: Joomla.Text._('...');
* Joomla.Text.load(...);
*/
Joomla.JText = Joomla.Text;
/**
* Generic submit form
*
* @param {String} task The given task
* @param {node} form The form element
* @param {bool} validate The form element
*
* @returns {void}
*/
Joomla.submitform = (task, form, validate) => {
let newForm = form;
const newTask = task;
if (!newForm) {
newForm = document.getElementById('adminForm');
}
if (newTask) {
newForm.task.value = newTask;
}
// Toggle HTML5 validation
newForm.noValidate = !validate;
if (!validate) {
newForm.setAttribute('novalidate', '');
} else if (newForm.hasAttribute('novalidate')) {
newForm.removeAttribute('novalidate');
}
// Submit the form.
// Create the input type="submit"
const button = document.createElement('input');
button.classList.add('hidden');
button.type = 'submit';
// Append it and click it
newForm.appendChild(button).click();
// If "submit" was prevented, make sure we don't get a build up of buttons
newForm.removeChild(button);
};
/**
* Default function. Can be overridden by the component to add custom logic
*
* @param {String} task The given task
* @param {String} formSelector The form selector eg '#adminForm'
* @param {bool} validate The form element
*
* @returns {void}
*/
Joomla.submitbutton = (task, formSelector, validate) => {
let form = document.querySelector(formSelector || 'form.form-validate');
let newValidate = validate;
if (typeof formSelector === 'string' && form === null) {
form = document.querySelector(`#${formSelector}`);
}
if (form) {
if (newValidate === undefined || newValidate === null) {
const pressbutton = task.split('.');
let cancelTask = form.getAttribute('data-cancel-task');
if (!cancelTask) {
cancelTask = `${pressbutton[0]}.cancel`;
}
newValidate = task !== cancelTask;
}
if (!newValidate || document.formvalidator.isValid(form)) {
Joomla.submitform(task, form);
}
} else {
Joomla.submitform(task);
}
};
/**
* USED IN: all list forms.
*
* Toggles the check state of a group of boxes
*
* Checkboxes must have an id attribute in the form cb0, cb1...
*
* @param {mixed} checkbox The number of box to 'check', for a checkbox element
* @param {string} stub An alternative field name
*
* @return {boolean}
*/
Joomla.checkAll = (checkbox, stub) => {
if (!checkbox.form) {
return false;
}
const currentStab = stub || 'cb';
const elements = [].slice.call(checkbox.form.elements);
let state = 0;
elements.forEach(element => {
if (element.type === checkbox.type && element.id.indexOf(currentStab) === 0) {
element.checked = checkbox.checked;
state += element.checked ? 1 : 0;
}
});
if (checkbox.form.boxchecked) {
checkbox.form.boxchecked.value = state;
checkbox.form.boxchecked.dispatchEvent(new CustomEvent('change', {
bubbles: true,
cancelable: true
}));
}
return true;
};
/**
* USED IN: administrator/components/com_cache/views/cache/tmpl/default.php
* administrator/components/com_installer/views/discover/tmpl/default_item.php
* administrator/components/com_installer/views/update/tmpl/default_item.php
* administrator/components/com_languages/helpers/html/languages.php
* libraries/joomla/html/html/grid.php
*
* @param {boolean} isitchecked Flag for checked
* @param {node} form The form
*
* @return {void}
*/
Joomla.isChecked = (isitchecked, form) => {
let newForm = form;
if (typeof newForm === 'undefined') {
newForm = document.getElementById('adminForm');
} else if (typeof form === 'string') {
newForm = document.getElementById(form);
}
newForm.boxchecked.value = isitchecked ? parseInt(newForm.boxchecked.value, 10) + 1 : parseInt(newForm.boxchecked.value, 10) - 1;
newForm.boxchecked.dispatchEvent(new CustomEvent('change', {
bubbles: true,
cancelable: true
}));
// If we don't have a checkall-toggle, done.
if (!newForm.elements['checkall-toggle']) {
return;
}
// Toggle main toggle checkbox depending on checkbox selection
let c = true;
let i;
let e;
let n;
// eslint-disable-next-line no-plusplus
for (i = 0, n = newForm.elements.length; i < n; i++) {
e = newForm.elements[i];
if (e.type === 'checkbox' && e.name !== 'checkall-toggle' && !e.checked) {
c = false;
break;
}
}
newForm.elements['checkall-toggle'].checked = c;
};
/**
* USED IN: libraries/joomla/html/html/grid.php
* In other words, on any reorderable table
*
* @param {string} order The order value
* @param {string} dir The direction
* @param {string} task The task
* @param {node} form The form
*
* return {void}
*/
Joomla.tableOrdering = (order, dir, task, form) => {
let newForm = form;
if (typeof newForm === 'undefined') {
newForm = document.getElementById('adminForm');
} else if (typeof form === 'string') {
newForm = document.getElementById(form);
}
newForm.filter_order.value = order;
newForm.filter_order_Dir.value = dir;
Joomla.submitform(task, newForm);
};
/**
* USED IN: all over :)
*
* @param {string} id The id
* @param {string} task The task
* @param {string} form The optional form
*
* @return {boolean}
*/
Joomla.listItemTask = (id, task, form = null) => {
let newForm = form;
if (form !== null) {
newForm = document.getElementById(form);
} else {
newForm = document.adminForm;
}
const cb = newForm[id];
let i = 0;
let cbx;
if (!cb) {
return false;
}
// eslint-disable-next-line no-constant-condition
while (true) {
cbx = newForm[`cb${i}`];
if (!cbx) {
break;
}
cbx.checked = false;
i += 1;
}
cb.checked = true;
newForm.boxchecked.value = 1;
Joomla.submitform(task, newForm);
return false;
};
/**
* Method to replace all request tokens on the page with a new one.
*
* @param {String} newToken The token
*
* Used in Joomla Installation
*/
Joomla.replaceTokens = newToken => {
if (!/^[0-9A-F]{32}$/i.test(newToken)) {
return;
}
document.querySelectorAll('input[type="hidden"]').forEach(element => {
if (element.value === '1' && element.name.length === 32) {
element.name = newToken;
}
});
};
/**
* Method to perform AJAX request
*
* @param {Object} options Request options:
* {
* url: 'index.php', Request URL
* method: 'GET', Request method GET (default), POST
* data: null, Data to be sent, see
* https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/send
* perform: true, Perform the request immediately
* or return XMLHttpRequest instance and perform it later
* headers: null, Object of custom headers, eg {'X-Foo': 'Bar', 'X-Bar': 'Foo'}
* promise: false Whether return a Promise instance.
* When true then next options is ignored: perform, onSuccess, onError, onComplete
*
* onBefore: (xhr) => {} // Callback on before the request
* onSuccess: (response, xhr) => {}, // Callback on the request success
* onError: (xhr) => {}, // Callback on the request error
* onComplete: (xhr) => {}, // Callback on the request completed, with/without error
* }
*
* @return XMLHttpRequest|Boolean
*
* @example
*
* Joomla.request({
* url: 'index.php?option=com_example&view=example',
* onSuccess: (response, xhr) => {
* JSON.parse(response);
* }
* })
*
* @see https://developer.mozilla.org/docs/Web/API/XMLHttpRequest
*/
Joomla.request = options => {
// Prepare the options
const newOptions = Joomla.extend({
url: '',
method: 'GET',
data: null,
perform: true,
promise: false
}, options);
// Setup XMLHttpRequest instance
const createRequest = (onSuccess, onError) => {
const xhr = new XMLHttpRequest();
xhr.open(newOptions.method, newOptions.url, true);
// Set the headers
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.setRequestHeader('X-Ajax-Engine', 'Joomla!');
if (newOptions.method !== 'GET') {
const token = Joomla.getOptions('csrf.token', '');
// Use the CSRF only on the site's domain
if (token && (!newOptions.url.startsWith('http:') && !newOptions.url.startsWith('https:') || newOptions.url.startsWith(window.location.origin))) {
xhr.setRequestHeader('X-CSRF-Token', token);
}
if (typeof newOptions.data === 'string' && (!newOptions.headers || !newOptions.headers['Content-Type'])) {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
}
}
// Custom headers
if (newOptions.headers) {
Object.keys(newOptions.headers).forEach(key => {
// Allow request without Content-Type
// eslint-disable-next-line no-empty
if (key === 'Content-Type' && newOptions.headers['Content-Type'] === 'false') ; else {
xhr.setRequestHeader(key, newOptions.headers[key]);
}
});
}
xhr.onreadystatechange = () => {
// Request not finished
if (xhr.readyState !== 4) {
return;
}
// Request finished and response is ready
if (xhr.status === 200) {
if (newOptions.promise) {
// A Promise accepts only one argument
onSuccess.call(window, xhr);
} else {
onSuccess.call(window, xhr.responseText, xhr);
}
} else {
onError.call(window, xhr);
}
if (newOptions.onComplete && !newOptions.promise) {
newOptions.onComplete.call(window, xhr);
}
};
// Do request
if (newOptions.perform) {
if (newOptions.onBefore && newOptions.onBefore.call(window, xhr) === false) {
// Request interrupted
if (newOptions.promise) {
onSuccess.call(window, xhr);
}
return xhr;
}
xhr.send(newOptions.data);
}
return xhr;
};
// Return a Promise
if (newOptions.promise) {
return new Promise((resolve, reject) => {
newOptions.perform = true;
createRequest(resolve, reject);
});
}
// Return a Request
try {
return createRequest(newOptions.onSuccess || (() => {}), newOptions.onError || (() => {}));
} catch (error) {
// eslint-disable-next-line no-unused-expressions,no-console
console.error(error);
return false;
}
};
let lastRequestPromise;
/**
* Joomla Request queue.
*
* A FIFO queue of requests to execute serially. Used to prevent simultaneous execution of
* multiple requests against the server which could trigger its Denial of Service protection.
*
* @param {object} options Options for Joomla.request()
* @returns {Promise}
*/
Joomla.enqueueRequest = options => {
if (!options.promise) {
throw new Error('Joomla.enqueueRequest supports only Joomla.request as Promise');
}
if (!lastRequestPromise) {
lastRequestPromise = Joomla.request(options);
} else {
lastRequestPromise = lastRequestPromise.then(() => Joomla.request(options));
}
return lastRequestPromise;
};
/**
*
* @param {string} unsafeHtml The html for sanitization
* @param {object} allowList The list of HTMLElements with an array of allowed attributes
* @param {function} sanitizeFn A custom sanitization function
*
* @return string
*/
Joomla.sanitizeHtml = (unsafeHtml, allowList, sanitizeFn) => {
const allowed = allowList === undefined || allowList === null ? DefaultAllowlist : _extends({}, DefaultAllowlist, allowList);
return sanitizeHtml(unsafeHtml, allowed, sanitizeFn);
};
/**
* Treat AJAX errors.
* Used by some javascripts such as sendtestmail.js and permissions.js
*
* @param {object} xhr XHR object.
* @param {string} textStatus Type of error that occurred.
* @param {string} error Textual portion of the HTTP status.
*
* @return {object} JavaScript object containing the system error message.
*
* @since 3.6.0
*/
Joomla.ajaxErrorsMessages = (xhr, textStatus) => {
const msg = {};
if (textStatus === 'parsererror') {
// For jQuery jqXHR
const buf = [];
// Html entity encode.
let encodedJson = xhr.responseText.trim();
// eslint-disable-next-line no-plusplus
for (let i = encodedJson.length - 1; i >= 0; i--) {
buf.unshift(['&#', encodedJson[i].charCodeAt(), ';'].join(''));
}
encodedJson = buf.join('');
msg.error = [Joomla.Text._('JLIB_JS_AJAX_ERROR_PARSE').replace('%s', encodedJson)];
} else if (textStatus === 'nocontent') {
msg.error = [Joomla.Text._('JLIB_JS_AJAX_ERROR_NO_CONTENT')];
} else if (textStatus === 'timeout') {
msg.error = [Joomla.Text._('JLIB_JS_AJAX_ERROR_TIMEOUT')];
} else if (textStatus === 'abort') {
msg.error = [Joomla.Text._('JLIB_JS_AJAX_ERROR_CONNECTION_ABORT')];
} else if (xhr.responseJSON && xhr.responseJSON.message) {
// For vanilla XHR
msg.error = [`${Joomla.Text._('JLIB_JS_AJAX_ERROR_OTHER').replace('%s', xhr.status)} <em>${xhr.responseJSON.message}</em>`];
} else if (xhr.statusText) {
msg.error = [`${Joomla.Text._('JLIB_JS_AJAX_ERROR_OTHER').replace('%s', xhr.status)} <em>${xhr.statusText}</em>`];
} else {
msg.error = [Joomla.Text._('JLIB_JS_AJAX_ERROR_OTHER').replace('%s', xhr.status)];
}
return msg;
};
})();