[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/media/system/js/ -> core-es5.js (source)

   1  (function () {
   2    'use strict';
   3  
   4    /**
   5     * --------------------------------------------------------------------------
   6     * Bootstrap (v5.1.3): util/sanitizer.js
   7     * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
   8     * --------------------------------------------------------------------------
   9     */
  10    const uriAttributes = new Set(['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']);
  11    /**
  12     * A pattern that recognizes a commonly useful subset of URLs that are safe.
  13     *
  14     * Shoutout to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts
  15     */
  16  
  17    const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i;
  18    /**
  19     * A pattern that matches safe data URLs. Only matches image, video and audio types.
  20     *
  21     * Shoutout to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts
  22     */
  23  
  24    const DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i;
  25  
  26    const allowedAttribute = (attribute, allowedAttributeList) => {
  27      const attributeName = attribute.nodeName.toLowerCase();
  28  
  29      if (allowedAttributeList.includes(attributeName)) {
  30        if (uriAttributes.has(attributeName)) {
  31          return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue) || DATA_URL_PATTERN.test(attribute.nodeValue));
  32        }
  33  
  34        return true;
  35      }
  36  
  37      const regExp = allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp); // Check if a regular expression validates the attribute.
  38  
  39      for (let i = 0, len = regExp.length; i < len; i++) {
  40        if (regExp[i].test(attributeName)) {
  41          return true;
  42        }
  43      }
  44  
  45      return false;
  46    };
  47    function sanitizeHtml(unsafeHtml, allowList, sanitizeFn) {
  48      if (!unsafeHtml.length) {
  49        return unsafeHtml;
  50      }
  51  
  52      if (sanitizeFn && typeof sanitizeFn === 'function') {
  53        return sanitizeFn(unsafeHtml);
  54      }
  55  
  56      const domParser = new window.DOMParser();
  57      const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html');
  58      const elements = [].concat(...createdDocument.body.querySelectorAll('*'));
  59  
  60      for (let i = 0, len = elements.length; i < len; i++) {
  61        const element = elements[i];
  62        const elementName = element.nodeName.toLowerCase();
  63  
  64        if (!Object.keys(allowList).includes(elementName)) {
  65          element.remove();
  66          continue;
  67        }
  68  
  69        const attributeList = [].concat(...element.attributes);
  70        const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || []);
  71        attributeList.forEach(attribute => {
  72          if (!allowedAttribute(attribute, allowedAttributes)) {
  73            element.removeAttribute(attribute.nodeName);
  74          }
  75        });
  76      }
  77  
  78      return createdDocument.body.innerHTML;
  79    }
  80  
  81    /**
  82     * @copyright  (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
  83     * @license    GNU General Public License version 2 or later; see LICENSE.txt
  84     */
  85    const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i;
  86    const DATA_ATTRIBUTE_PATTERN = /^data-[\w-]*$/i;
  87    const DefaultAllowlist = {
  88      // Global attributes allowed on any supplied element below.
  89      '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN, DATA_ATTRIBUTE_PATTERN],
  90      a: ['target', 'href', 'title', 'rel'],
  91      area: [],
  92      b: [],
  93      br: [],
  94      col: [],
  95      code: [],
  96      div: [],
  97      em: [],
  98      hr: [],
  99      h1: [],
 100      h2: [],
 101      h3: [],
 102      h4: [],
 103      h5: [],
 104      h6: [],
 105      i: [],
 106      img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],
 107      li: [],
 108      ol: [],
 109      p: [],
 110      pre: [],
 111      s: [],
 112      small: [],
 113      span: [],
 114      sub: [],
 115      sup: [],
 116      strong: [],
 117      u: [],
 118      ul: [],
 119      button: ['type'],
 120      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'],
 121      select: ['name'],
 122      textarea: ['name'],
 123      option: ['value', 'selected']
 124    }; // Only define the Joomla namespace if not defined.
 125  
 126    window.Joomla = window.Joomla || {}; // Only define editors if not defined
 127  
 128    window.Joomla.editors = window.Joomla.editors || {}; // An object to hold each editor instance on page, only define if not defined.
 129  
 130    window.Joomla.editors.instances = window.Joomla.editors.instances || {
 131      /**
 132       * *****************************************************************
 133       * All Editors MUST register, per instance, the following callbacks:
 134       * *****************************************************************
 135       *
 136       * getValue         Type  Function  Should return the complete data from the editor
 137       *                                  Example: () => { return this.element.value; }
 138       * setValue         Type  Function  Should replace the complete data of the editor
 139       *                                  Example: (text) => { return this.element.value = text; }
 140       * getSelection     Type  Function  Should return the selected text from the editor
 141       *                                  Example: function () { return this.selectedText; }
 142       * disable          Type  Function  Toggles the editor into disabled mode. When the editor is
 143       *                                  active then everything should be usable. When inactive the
 144       *                                  editor should be unusable AND disabled for form validation
 145       *                                  Example: (bool) => { return this.disable = value; }
 146       * replaceSelection Type  Function  Should replace the selected text of the editor
 147       *                                  If nothing selected, will insert the data at the cursor
 148       *                                  Example:
 149       *                                  (text) => {
 150       *                                    return insertAtCursor(this.element, text);
 151       *                                    }
 152       *
 153       * USAGE (assuming that jform_articletext is the textarea id)
 154       * {
 155       * To get the current editor value:
 156       *  Joomla.editors.instances['jform_articletext'].getValue();
 157       * To set the current editor value:
 158       *  Joomla.editors.instances['jform_articletext'].setValue('Joomla! rocks');
 159       * To replace(selection) or insert a value at  the current editor cursor (replaces the J3
 160       * jInsertEditorText API):
 161       *  replaceSelection:
 162       *  Joomla.editors.instances['jform_articletext'].replaceSelection('Joomla! rocks')
 163       * }
 164       *
 165       * *********************************************************
 166       * ANY INTERACTION WITH THE EDITORS SHOULD USE THE ABOVE API
 167       * *********************************************************
 168       */
 169    };
 170    window.Joomla.Modal = window.Joomla.Modal || {
 171      /**
 172       * *****************************************************************
 173       * Modals should implement
 174       * *****************************************************************
 175       *
 176       * getCurrent  Type  Function  Should return the modal element
 177       * setCurrent  Type  Function  Should set the modal element
 178       * current     Type  {node}    The modal element
 179       *
 180       * USAGE (assuming that exampleId is the modal id)
 181       * To get the current modal element:
 182       *   Joomla.Modal.current; // Returns node element, eg: document.getElementById('exampleId')
 183       * To set the current modal element:
 184       *   Joomla.Modal.setCurrent(document.getElementById('exampleId'));
 185       *
 186       * *************************************************************
 187       * Joomla's UI modal uses `element.close();` to close the modal
 188       * and `element.open();` to open the modal
 189       * If you are using another modal make sure the same
 190       * functionality is bound to the modal element
 191       * @see media/legacy/bootstrap.init.js
 192       * *************************************************************
 193       */
 194      current: '',
 195      setCurrent: element => {
 196        window.Joomla.current = element;
 197      },
 198      getCurrent: () => window.Joomla.current
 199    };
 200  
 201    (Joomla => {
 202      /**
 203       * Method to Extend Objects
 204       *
 205       * @param  {Object}  destination
 206       * @param  {Object}  source
 207       *
 208       * @return Object
 209       */
 210  
 211      Joomla.extend = (destination, source) => {
 212        let newDestination = destination;
 213        /**
 214         * Technically null is an object, but trying to treat the destination as one in this
 215         * context will error out.
 216         * So emulate jQuery.extend(), and treat a destination null as an empty object.
 217         */
 218  
 219        if (destination === null) {
 220          newDestination = {};
 221        }
 222  
 223        [].slice.call(Object.keys(source)).forEach(key => {
 224          newDestination[key] = source[key];
 225        });
 226        return destination;
 227      };
 228      /**
 229       * Joomla options storage
 230       *
 231       * @type {{}}
 232       *
 233       * @since 3.7.0
 234       */
 235  
 236  
 237      Joomla.optionsStorage = Joomla.optionsStorage || null;
 238      /**
 239       * Get script(s) options
 240       *
 241       * @param  {String}  key  Name in Storage
 242       * @param  {mixed}   def  Default value if nothing found
 243       *
 244       * @return {mixed}
 245       *
 246       * @since 3.7.0
 247       */
 248  
 249      Joomla.getOptions = (key, def) => {
 250        // Load options if they not exists
 251        if (!Joomla.optionsStorage) {
 252          Joomla.loadOptions();
 253        }
 254  
 255        return Joomla.optionsStorage[key] !== undefined ? Joomla.optionsStorage[key] : def;
 256      };
 257      /**
 258       * Load new options from given options object or from Element
 259       *
 260       * @param  {Object|undefined}  options  The options object to load.
 261       * Eg {"com_foobar" : {"option1": 1, "option2": 2}}
 262       *
 263       * @since 3.7.0
 264       */
 265  
 266  
 267      Joomla.loadOptions = options => {
 268        // Load form the script container
 269        if (!options) {
 270          const elements = [].slice.call(document.querySelectorAll('.joomla-script-options.new'));
 271          let counter = 0;
 272          elements.forEach(element => {
 273            const str = element.text || element.textContent;
 274            const option = JSON.parse(str);
 275  
 276            if (option) {
 277              Joomla.loadOptions(option);
 278              counter += 1;
 279            }
 280  
 281            element.className = element.className.replace(' new', ' loaded');
 282          });
 283  
 284          if (counter) {
 285            return;
 286          }
 287        } // Initial loading
 288  
 289  
 290        if (!Joomla.optionsStorage) {
 291          Joomla.optionsStorage = options || {};
 292        } else if (options) {
 293          // Merge with existing
 294          [].slice.call(Object.keys(options)).forEach(key => {
 295            /**
 296             * If both existing and new options are objects, merge them with Joomla.extend().
 297             * But test for new option being null, as null is an object, but we want to allow
 298             * clearing of options with ...
 299             *
 300             * Joomla.loadOptions({'joomla.jtext': null});
 301             */
 302            if (options[key] !== null && typeof Joomla.optionsStorage[key] === 'object' && typeof options[key] === 'object') {
 303              Joomla.optionsStorage[key] = Joomla.extend(Joomla.optionsStorage[key], options[key]);
 304            } else {
 305              Joomla.optionsStorage[key] = options[key];
 306            }
 307          });
 308        }
 309      };
 310      /**
 311       * Custom behavior for JavaScript I18N in Joomla! 1.6
 312       *
 313       * @type {{}}
 314       *
 315       * Allows you to call Joomla.Text._() to get a translated JavaScript string
 316       * pushed in with Text::script() in Joomla.
 317       */
 318  
 319  
 320      Joomla.Text = {
 321        strings: {},
 322  
 323        /**
 324         * Translates a string into the current language.
 325         *
 326         * @param {String} key   The string to translate
 327         * @param {String} def   Default string
 328         *
 329         * @returns {String}
 330         */
 331        _: (key, def) => {
 332          let newKey = key;
 333          let newDef = def; // Check for new strings in the optionsStorage, and load them
 334  
 335          const newStrings = Joomla.getOptions('joomla.jtext');
 336  
 337          if (newStrings) {
 338            Joomla.Text.load(newStrings); // Clean up the optionsStorage from useless data
 339  
 340            Joomla.loadOptions({
 341              'joomla.jtext': null
 342            });
 343          }
 344  
 345          newDef = newDef === undefined ? newKey : newDef;
 346          newKey = newKey.toUpperCase();
 347          return Joomla.Text.strings[newKey] !== undefined ? Joomla.Text.strings[newKey] : newDef;
 348        },
 349  
 350        /**
 351         * Load new strings in to Joomla.Text
 352         *
 353         * @param {Object} object  Object with new strings
 354         * @returns {Joomla.Text}
 355         */
 356        load: object => {
 357          [].slice.call(Object.keys(object)).forEach(key => {
 358            Joomla.Text.strings[key.toUpperCase()] = object[key];
 359          });
 360          return Joomla.Text;
 361        }
 362      };
 363      /**
 364       * For B/C we still support Joomla.JText
 365       *
 366       * @type {{}}
 367       *
 368       * @deprecated 5.0
 369       */
 370  
 371      Joomla.JText = Joomla.Text;
 372      /**
 373       * Generic submit form
 374       *
 375       * @param  {String}  task      The given task
 376       * @param  {node}    form      The form element
 377       * @param  {bool}    validate  The form element
 378       *
 379       * @returns  {void}
 380       */
 381  
 382      Joomla.submitform = (task, form, validate) => {
 383        let newForm = form;
 384        const newTask = task;
 385  
 386        if (!newForm) {
 387          newForm = document.getElementById('adminForm');
 388        }
 389  
 390        if (newTask) {
 391          newForm.task.value = newTask;
 392        } // Toggle HTML5 validation
 393  
 394  
 395        newForm.noValidate = !validate;
 396  
 397        if (!validate) {
 398          newForm.setAttribute('novalidate', '');
 399        } else if (newForm.hasAttribute('novalidate')) {
 400          newForm.removeAttribute('novalidate');
 401        } // Submit the form.
 402        // Create the input type="submit"
 403  
 404  
 405        const button = document.createElement('input');
 406        button.classList.add('hidden');
 407        button.type = 'submit'; // Append it and click it
 408  
 409        newForm.appendChild(button).click(); // If "submit" was prevented, make sure we don't get a build up of buttons
 410  
 411        newForm.removeChild(button);
 412      };
 413      /**
 414       * Default function. Can be overridden by the component to add custom logic
 415       *
 416       * @param  {String}  task            The given task
 417       * @param  {String}  formSelector    The form selector eg '#adminForm'
 418       * @param  {bool}    validate        The form element
 419       *
 420       * @returns {void}
 421       */
 422  
 423  
 424      Joomla.submitbutton = (task, formSelector, validate) => {
 425        let form = document.querySelector(formSelector || 'form.form-validate');
 426        let newValidate = validate;
 427  
 428        if (typeof formSelector === 'string' && form === null) {
 429          form = document.querySelector(`#$formSelector}`);
 430        }
 431  
 432        if (form) {
 433          if (newValidate === undefined || newValidate === null) {
 434            const pressbutton = task.split('.');
 435            let cancelTask = form.getAttribute('data-cancel-task');
 436  
 437            if (!cancelTask) {
 438              cancelTask = `$pressbutton[0]}.cancel`;
 439            }
 440  
 441            newValidate = task !== cancelTask;
 442          }
 443  
 444          if (!newValidate || document.formvalidator.isValid(form)) {
 445            Joomla.submitform(task, form);
 446          }
 447        } else {
 448          Joomla.submitform(task);
 449        }
 450      };
 451      /**
 452       * USED IN: all list forms.
 453       *
 454       * Toggles the check state of a group of boxes
 455       *
 456       * Checkboxes must have an id attribute in the form cb0, cb1...
 457       *
 458       * @param {mixed}  checkbox The number of box to 'check', for a checkbox element
 459       * @param {string} stub     An alternative field name
 460       *
 461       * @return {boolean}
 462       */
 463  
 464  
 465      Joomla.checkAll = (checkbox, stub) => {
 466        if (!checkbox.form) {
 467          return false;
 468        }
 469  
 470        const currentStab = stub || 'cb';
 471        const elements = [].slice.call(checkbox.form.elements);
 472        let state = 0;
 473        elements.forEach(element => {
 474          if (element.type === checkbox.type && element.id.indexOf(currentStab) === 0) {
 475            element.checked = checkbox.checked;
 476            state += element.checked ? 1 : 0;
 477          }
 478        });
 479  
 480        if (checkbox.form.boxchecked) {
 481          checkbox.form.boxchecked.value = state;
 482          checkbox.form.boxchecked.dispatchEvent(new CustomEvent('change', {
 483            bubbles: true,
 484            cancelable: true
 485          }));
 486        }
 487  
 488        return true;
 489      };
 490      /**
 491       * USED IN: administrator/components/com_cache/views/cache/tmpl/default.php
 492       * administrator/components/com_installer/views/discover/tmpl/default_item.php
 493       * administrator/components/com_installer/views/update/tmpl/default_item.php
 494       * administrator/components/com_languages/helpers/html/languages.php
 495       * libraries/joomla/html/html/grid.php
 496       *
 497       * @param  {boolean}  isitchecked  Flag for checked
 498       * @param  {node}     form         The form
 499       *
 500       * @return  {void}
 501       */
 502  
 503  
 504      Joomla.isChecked = (isitchecked, form) => {
 505        let newForm = form;
 506  
 507        if (typeof newForm === 'undefined') {
 508          newForm = document.getElementById('adminForm');
 509        } else if (typeof form === 'string') {
 510          newForm = document.getElementById(form);
 511        }
 512  
 513        newForm.boxchecked.value = isitchecked ? parseInt(newForm.boxchecked.value, 10) + 1 : parseInt(newForm.boxchecked.value, 10) - 1;
 514        newForm.boxchecked.dispatchEvent(new CustomEvent('change', {
 515          bubbles: true,
 516          cancelable: true
 517        })); // If we don't have a checkall-toggle, done.
 518  
 519        if (!newForm.elements['checkall-toggle']) {
 520          return;
 521        } // Toggle main toggle checkbox depending on checkbox selection
 522  
 523  
 524        let c = true;
 525        let i;
 526        let e;
 527        let n; // eslint-disable-next-line no-plusplus
 528  
 529        for (i = 0, n = newForm.elements.length; i < n; i++) {
 530          e = newForm.elements[i];
 531  
 532          if (e.type === 'checkbox' && e.name !== 'checkall-toggle' && !e.checked) {
 533            c = false;
 534            break;
 535          }
 536        }
 537  
 538        newForm.elements['checkall-toggle'].checked = c;
 539      };
 540      /**
 541       * USED IN: libraries/joomla/html/html/grid.php
 542       * In other words, on any reorderable table
 543       *
 544       * @param  {string}  order  The order value
 545       * @param  {string}  dir    The direction
 546       * @param  {string}  task   The task
 547       * @param  {node}    form   The form
 548       *
 549       * return  {void}
 550       */
 551  
 552  
 553      Joomla.tableOrdering = (order, dir, task, form) => {
 554        let newForm = form;
 555  
 556        if (typeof newForm === 'undefined') {
 557          newForm = document.getElementById('adminForm');
 558        } else if (typeof form === 'string') {
 559          newForm = document.getElementById(form);
 560        }
 561  
 562        newForm.filter_order.value = order;
 563        newForm.filter_order_Dir.value = dir;
 564        Joomla.submitform(task, newForm);
 565      };
 566      /**
 567       * USED IN: all over :)
 568       *
 569       * @param  {string}  id    The id
 570       * @param  {string}  task  The task
 571       * @param  {string}  form  The optional form
 572       *
 573       * @return {boolean}
 574       */
 575  
 576  
 577      Joomla.listItemTask = (id, task, form = null) => {
 578        let newForm = form;
 579  
 580        if (form !== null) {
 581          newForm = document.getElementById(form);
 582        } else {
 583          newForm = document.adminForm;
 584        }
 585  
 586        const cb = newForm[id];
 587        let i = 0;
 588        let cbx;
 589  
 590        if (!cb) {
 591          return false;
 592        } // eslint-disable-next-line no-constant-condition
 593  
 594  
 595        while (true) {
 596          cbx = newForm[`cb$i}`];
 597  
 598          if (!cbx) {
 599            break;
 600          }
 601  
 602          cbx.checked = false;
 603          i += 1;
 604        }
 605  
 606        cb.checked = true;
 607        newForm.boxchecked.value = 1;
 608        Joomla.submitform(task, newForm);
 609        return false;
 610      };
 611      /**
 612       * Method to replace all request tokens on the page with a new one.
 613       *
 614       * @param {String}  newToken  The token
 615       *
 616       * Used in Joomla Installation
 617       */
 618  
 619  
 620      Joomla.replaceTokens = newToken => {
 621        if (!/^[0-9A-F]{32}$/i.test(newToken)) {
 622          return;
 623        }
 624  
 625        const elements = [].slice.call(document.getElementsByTagName('input'));
 626        elements.forEach(element => {
 627          if (element.type === 'hidden' && element.value === '1' && element.name.length === 32) {
 628            element.name = newToken;
 629          }
 630        });
 631      };
 632      /**
 633       * Method to perform AJAX request
 634       *
 635       * @param {Object} options   Request options:
 636       * {
 637       *    url:     'index.php', Request URL
 638       *    method:  'GET',       Request method GET (default), POST
 639       *    data:    null,        Data to be sent, see
 640       *                https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/send
 641       *    perform: true,        Perform the request immediately
 642       *              or return XMLHttpRequest instance and perform it later
 643       *    headers: null,        Object of custom headers, eg {'X-Foo': 'Bar', 'X-Bar': 'Foo'}
 644       *    promise: false        Whether return a Promise instance.
 645       *              When true then next options is ignored: perform, onSuccess, onError, onComplete
 646       *
 647       *    onBefore:  (xhr) => {}            // Callback on before the request
 648       *    onSuccess: (response, xhr) => {}, // Callback on the request success
 649       *    onError:   (xhr) => {},           // Callback on the request error
 650       *    onComplete: (xhr) => {},          // Callback on the request completed, with/without error
 651       * }
 652       *
 653       * @return XMLHttpRequest|Boolean
 654       *
 655       * @example
 656       *
 657       *   Joomla.request({
 658       *    url: 'index.php?option=com_example&view=example',
 659       *    onSuccess: (response, xhr) => {
 660       *     JSON.parse(response);
 661       *    }
 662       *   })
 663       *
 664       * @see    https://developer.mozilla.org/docs/Web/API/XMLHttpRequest
 665       */
 666  
 667  
 668      Joomla.request = options => {
 669        // Prepare the options
 670        const newOptions = Joomla.extend({
 671          url: '',
 672          method: 'GET',
 673          data: null,
 674          perform: true,
 675          promise: false
 676        }, options); // Setup XMLHttpRequest instance
 677  
 678        const createRequest = (onSuccess, onError) => {
 679          const xhr = new XMLHttpRequest();
 680          xhr.open(newOptions.method, newOptions.url, true); // Set the headers
 681  
 682          xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
 683          xhr.setRequestHeader('X-Ajax-Engine', 'Joomla!');
 684  
 685          if (newOptions.method !== 'GET') {
 686            const token = Joomla.getOptions('csrf.token', '');
 687  
 688            if (token) {
 689              xhr.setRequestHeader('X-CSRF-Token', token);
 690            }
 691  
 692            if (typeof newOptions.data === 'string' && (!newOptions.headers || !newOptions.headers['Content-Type'])) {
 693              xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
 694            }
 695          } // Custom headers
 696  
 697  
 698          if (newOptions.headers) {
 699            [].slice.call(Object.keys(newOptions.headers)).forEach(key => {
 700              // Allow request without Content-Type
 701              // eslint-disable-next-line no-empty
 702              if (key === 'Content-Type' && newOptions.headers['Content-Type'] === 'false') ; else {
 703                xhr.setRequestHeader(key, newOptions.headers[key]);
 704              }
 705            });
 706          }
 707  
 708          xhr.onreadystatechange = () => {
 709            // Request not finished
 710            if (xhr.readyState !== 4) {
 711              return;
 712            } // Request finished and response is ready
 713  
 714  
 715            if (xhr.status === 200) {
 716              if (newOptions.promise) {
 717                // A Promise accepts only one argument
 718                onSuccess.call(window, xhr);
 719              } else {
 720                onSuccess.call(window, xhr.responseText, xhr);
 721              }
 722            } else {
 723              onError.call(window, xhr);
 724            }
 725  
 726            if (newOptions.onComplete && !newOptions.promise) {
 727              newOptions.onComplete.call(window, xhr);
 728            }
 729          }; // Do request
 730  
 731  
 732          if (newOptions.perform) {
 733            if (newOptions.onBefore && newOptions.onBefore.call(window, xhr) === false) {
 734              // Request interrupted
 735              if (newOptions.promise) {
 736                onSuccess.call(window, xhr);
 737              }
 738  
 739              return xhr;
 740            }
 741  
 742            xhr.send(newOptions.data);
 743          }
 744  
 745          return xhr;
 746        }; // Return a Promise
 747  
 748  
 749        if (newOptions.promise) {
 750          return new Promise((resolve, reject) => {
 751            newOptions.perform = true;
 752            createRequest(resolve, reject);
 753          });
 754        } // Return a Request
 755  
 756  
 757        try {
 758          return createRequest(newOptions.onSuccess || (() => {}), newOptions.onError || (() => {}));
 759        } catch (error) {
 760          // eslint-disable-next-line no-unused-expressions,no-console
 761          console.error(error);
 762          return false;
 763        }
 764      };
 765  
 766      let lastRequestPromise;
 767      /**
 768       * Joomla Request queue.
 769       *
 770       * A FIFO queue of requests to execute serially. Used to prevent simultaneous execution of
 771       * multiple requests against the server which could trigger its Denial of Service protection.
 772       *
 773       * @param {object} options Options for Joomla.request()
 774       * @returns {Promise}
 775       */
 776  
 777      Joomla.enqueueRequest = options => {
 778        if (!options.promise) {
 779          throw new Error('Joomla.enqueueRequest supports only Joomla.request as Promise');
 780        }
 781  
 782        if (!lastRequestPromise) {
 783          lastRequestPromise = Joomla.request(options);
 784        } else {
 785          lastRequestPromise = lastRequestPromise.then(() => Joomla.request(options));
 786        }
 787  
 788        return lastRequestPromise;
 789      };
 790      /**
 791       *
 792       * @param {string} unsafeHtml The html for sanitization
 793       * @param {object} allowList The list of HTMLElements with an array of allowed attributes
 794       * @param {function} sanitizeFn A custom sanitization function
 795       *
 796       * @return string
 797       */
 798  
 799  
 800      Joomla.sanitizeHtml = (unsafeHtml, allowList, sanitizeFn) => {
 801        const allowed = allowList === undefined || allowList === null ? DefaultAllowlist : { ...DefaultAllowlist,
 802          ...allowList
 803        };
 804        return sanitizeHtml(unsafeHtml, allowed, sanitizeFn);
 805      };
 806      /**
 807       * Treat AJAX errors.
 808       * Used by some javascripts such as sendtestmail.js and permissions.js
 809       *
 810       * @param   {object}  xhr         XHR object.
 811       * @param   {string}  textStatus  Type of error that occurred.
 812       * @param   {string}  error       Textual portion of the HTTP status.
 813       *
 814       * @return  {object}  JavaScript object containing the system error message.
 815       *
 816       * @since  3.6.0
 817       */
 818  
 819  
 820      Joomla.ajaxErrorsMessages = (xhr, textStatus) => {
 821        const msg = {};
 822  
 823        if (textStatus === 'parsererror') {
 824          // For jQuery jqXHR
 825          const buf = []; // Html entity encode.
 826  
 827          let encodedJson = xhr.responseText.trim(); // eslint-disable-next-line no-plusplus
 828  
 829          for (let i = encodedJson.length - 1; i >= 0; i--) {
 830            buf.unshift(['&#', encodedJson[i].charCodeAt(), ';'].join(''));
 831          }
 832  
 833          encodedJson = buf.join('');
 834          msg.error = [Joomla.Text._('JLIB_JS_AJAX_ERROR_PARSE').replace('%s', encodedJson)];
 835        } else if (textStatus === 'nocontent') {
 836          msg.error = [Joomla.Text._('JLIB_JS_AJAX_ERROR_NO_CONTENT')];
 837        } else if (textStatus === 'timeout') {
 838          msg.error = [Joomla.Text._('JLIB_JS_AJAX_ERROR_TIMEOUT')];
 839        } else if (textStatus === 'abort') {
 840          msg.error = [Joomla.Text._('JLIB_JS_AJAX_ERROR_CONNECTION_ABORT')];
 841        } else if (xhr.responseJSON && xhr.responseJSON.message) {
 842          // For vanilla XHR
 843          msg.error = [`$Joomla.Text._('JLIB_JS_AJAX_ERROR_OTHER').replace('%s', xhr.status)} <em>$xhr.responseJSON.message}</em>`];
 844        } else if (xhr.statusText) {
 845          msg.error = [`$Joomla.Text._('JLIB_JS_AJAX_ERROR_OTHER').replace('%s', xhr.status)} <em>$xhr.statusText}</em>`];
 846        } else {
 847          msg.error = [Joomla.Text._('JLIB_JS_AJAX_ERROR_OTHER').replace('%s', xhr.status)];
 848        }
 849  
 850        return msg;
 851      };
 852    })(Joomla);
 853  
 854  })();


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer