[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/media/system/js/fields/ -> joomla-field-fancy-select-es5.js (source)

   1  (function () {
   2    'use strict';
   3  
   4    function _defineProperties(target, props) {
   5      for (var i = 0; i < props.length; i++) {
   6        var descriptor = props[i];
   7        descriptor.enumerable = descriptor.enumerable || false;
   8        descriptor.configurable = true;
   9        if ("value" in descriptor) descriptor.writable = true;
  10        Object.defineProperty(target, descriptor.key, descriptor);
  11      }
  12    }
  13  
  14    function _createClass(Constructor, protoProps, staticProps) {
  15      if (protoProps) _defineProperties(Constructor.prototype, protoProps);
  16      if (staticProps) _defineProperties(Constructor, staticProps);
  17      Object.defineProperty(Constructor, "prototype", {
  18        writable: false
  19      });
  20      return Constructor;
  21    }
  22  
  23    function _inheritsLoose(subClass, superClass) {
  24      subClass.prototype = Object.create(superClass.prototype);
  25      subClass.prototype.constructor = subClass;
  26  
  27      _setPrototypeOf(subClass, superClass);
  28    }
  29  
  30    function _getPrototypeOf(o) {
  31      _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
  32        return o.__proto__ || Object.getPrototypeOf(o);
  33      };
  34      return _getPrototypeOf(o);
  35    }
  36  
  37    function _setPrototypeOf(o, p) {
  38      _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
  39        o.__proto__ = p;
  40        return o;
  41      };
  42  
  43      return _setPrototypeOf(o, p);
  44    }
  45  
  46    function _isNativeReflectConstruct() {
  47      if (typeof Reflect === "undefined" || !Reflect.construct) return false;
  48      if (Reflect.construct.sham) return false;
  49      if (typeof Proxy === "function") return true;
  50  
  51      try {
  52        Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
  53        return true;
  54      } catch (e) {
  55        return false;
  56      }
  57    }
  58  
  59    function _construct(Parent, args, Class) {
  60      if (_isNativeReflectConstruct()) {
  61        _construct = Reflect.construct;
  62      } else {
  63        _construct = function _construct(Parent, args, Class) {
  64          var a = [null];
  65          a.push.apply(a, args);
  66          var Constructor = Function.bind.apply(Parent, a);
  67          var instance = new Constructor();
  68          if (Class) _setPrototypeOf(instance, Class.prototype);
  69          return instance;
  70        };
  71      }
  72  
  73      return _construct.apply(null, arguments);
  74    }
  75  
  76    function _isNativeFunction(fn) {
  77      return Function.toString.call(fn).indexOf("[native code]") !== -1;
  78    }
  79  
  80    function _wrapNativeSuper(Class) {
  81      var _cache = typeof Map === "function" ? new Map() : undefined;
  82  
  83      _wrapNativeSuper = function _wrapNativeSuper(Class) {
  84        if (Class === null || !_isNativeFunction(Class)) return Class;
  85  
  86        if (typeof Class !== "function") {
  87          throw new TypeError("Super expression must either be null or a function");
  88        }
  89  
  90        if (typeof _cache !== "undefined") {
  91          if (_cache.has(Class)) return _cache.get(Class);
  92  
  93          _cache.set(Class, Wrapper);
  94        }
  95  
  96        function Wrapper() {
  97          return _construct(Class, arguments, _getPrototypeOf(this).constructor);
  98        }
  99  
 100        Wrapper.prototype = Object.create(Class.prototype, {
 101          constructor: {
 102            value: Wrapper,
 103            enumerable: false,
 104            writable: true,
 105            configurable: true
 106          }
 107        });
 108        return _setPrototypeOf(Wrapper, Class);
 109      };
 110  
 111      return _wrapNativeSuper(Class);
 112    }
 113  
 114    /**
 115     * @copyright  (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 116     * @license    GNU General Public License version 2 or later; see LICENSE.txt
 117     */
 118  
 119    /**
 120     * Fancy select field, which use Choices.js
 121     *
 122     * Example:
 123     * <joomla-field-fancy-select ...attributes>
 124     *   <select>...</select>
 125     * </joomla-field-fancy-select>
 126     *
 127     * Possible attributes:
 128     *
 129     * allow-custom          Whether allow User to dynamically add a new value.
 130     * new-item-prefix=""    Prefix for a dynamically added value.
 131     *
 132     * remote-search         Enable remote search.
 133     * url=""                Url for remote search.
 134     * term-key="term"       Variable key name for searched term, will be appended to Url.
 135     *
 136     * min-term-length="1"   The minimum length a search value should be before choices are searched.
 137     * placeholder=""        The value of the inputs placeholder.
 138     * search-placeholder="" The value of the search inputs placeholder.
 139     *
 140     * data-max-results="30" The maximum amount of search results to be displayed.
 141     * data-max-render="30"  The maximum amount of items to be rendered, critical for large lists.
 142     */
 143    window.customElements.define('joomla-field-fancy-select', /*#__PURE__*/function (_HTMLElement) {
 144      _inheritsLoose(_class, _HTMLElement);
 145  
 146      /**
 147       * Lifecycle
 148       */
 149      function _class() {
 150        var _this;
 151  
 152        _this = _HTMLElement.call(this) || this; // Keycodes
 153  
 154        _this.keyCode = {
 155          ENTER: 13
 156        };
 157  
 158        if (!Joomla) {
 159          throw new Error('Joomla API is not properly initiated');
 160        }
 161  
 162        if (!window.Choices) {
 163          throw new Error('JoomlaFieldFancySelect requires Choices.js to work');
 164        }
 165  
 166        _this.choicesCache = {};
 167        _this.activeXHR = null;
 168        _this.choicesInstance = null;
 169        _this.isDisconnected = false;
 170        return _this;
 171      }
 172      /**
 173       * Lifecycle
 174       */
 175  
 176  
 177      var _proto = _class.prototype;
 178  
 179      _proto.connectedCallback = function connectedCallback() {
 180        var _this2 = this;
 181  
 182        // Make sure Choices are loaded
 183        if (window.Choices || document.readyState === 'complete') {
 184          this.doConnect();
 185        } else {
 186          var callback = function callback() {
 187            _this2.doConnect();
 188  
 189            window.removeEventListener('load', callback);
 190          };
 191  
 192          window.addEventListener('load', callback);
 193        }
 194      };
 195  
 196      _proto.doConnect = function doConnect() {
 197        var _this3 = this;
 198  
 199        // Get a <select> element
 200        this.select = this.querySelector('select');
 201  
 202        if (!this.select) {
 203          throw new Error('JoomlaFieldFancySelect requires <select> element to work');
 204        } // The element was already initialised previously and perhaps was detached from DOM
 205  
 206  
 207        if (this.choicesInstance) {
 208          if (this.isDisconnected) {
 209            // Re init previous instance
 210            this.choicesInstance.init();
 211            this.isDisconnected = false;
 212          }
 213  
 214          return;
 215        }
 216  
 217        this.isDisconnected = false; // Add placeholder option for multiple mode,
 218        // Because it not supported as parameter by Choices for <select> https://github.com/jshjohnson/Choices#placeholder
 219  
 220        if (this.select.multiple && this.placeholder) {
 221          var option = document.createElement('option');
 222          option.setAttribute('placeholder', '');
 223          option.textContent = this.placeholder;
 224          this.select.appendChild(option);
 225        } // Init Choices
 226        // eslint-disable-next-line no-undef
 227  
 228  
 229        this.choicesInstance = new Choices(this.select, {
 230          placeholderValue: this.placeholder,
 231          searchPlaceholderValue: this.searchPlaceholder,
 232          removeItemButton: true,
 233          searchFloor: this.minTermLength,
 234          searchResultLimit: parseInt(this.select.dataset.maxResults, 10) || 10,
 235          renderChoiceLimit: parseInt(this.select.dataset.maxRender, 10) || -1,
 236          shouldSort: false,
 237          fuseOptions: {
 238            threshold: 0.3 // Strict search
 239  
 240          },
 241          noResultsText: Joomla.Text._('JGLOBAL_SELECT_NO_RESULTS_MATCH', 'No results found'),
 242          noChoicesText: Joomla.Text._('JGLOBAL_SELECT_NO_RESULTS_MATCH', 'No results found'),
 243          itemSelectText: Joomla.Text._('JGLOBAL_SELECT_PRESS_TO_SELECT', 'Press to select'),
 244          // Redefine some classes
 245          classNames: {
 246            button: 'choices__button_joomla' // It is need because an original styling use unavailable Icon.svg file
 247  
 248          }
 249        }); // Handle typing of custom Term
 250  
 251        if (this.allowCustom) {
 252          // START Work around for issue https://github.com/joomla/joomla-cms/issues/29459
 253          // The choices.js always auto-highlights the first element
 254          // in the dropdown that not allow to add a custom Term.
 255          //
 256          // This workaround can be removed when choices.js
 257          // will have an option that allow to disable it.
 258          // eslint-disable-next-line no-underscore-dangle, prefer-destructuring
 259          var _highlightChoice = this.choicesInstance._highlightChoice; // eslint-disable-next-line no-underscore-dangle
 260  
 261          this.choicesInstance._highlightChoice = function (el) {
 262            // Prevent auto-highlight of first element, if nothing actually highlighted
 263            if (!el) return; // Call original highlighter
 264  
 265            _highlightChoice.call(_this3.choicesInstance, el);
 266          }; // Unhighlight any highlighted items, when mouse leave the dropdown
 267  
 268  
 269          this.addEventListener('mouseleave', function () {
 270            if (!_this3.choicesInstance.dropdown.isActive) {
 271              return;
 272            }
 273  
 274            var highlighted = Array.from(_this3.choicesInstance.dropdown.element.querySelectorAll("." + _this3.choicesInstance.config.classNames.highlightedState));
 275            highlighted.forEach(function (choice) {
 276              choice.classList.remove(_this3.choicesInstance.config.classNames.highlightedState);
 277              choice.setAttribute('aria-selected', 'false');
 278            }); // eslint-disable-next-line no-underscore-dangle
 279  
 280            _this3.choicesInstance._highlightPosition = 0;
 281          }); // END workaround for issue #29459
 282          // Add custom term on ENTER keydown
 283  
 284          this.addEventListener('keydown', function (event) {
 285            if (event.keyCode !== _this3.keyCode.ENTER || event.target !== _this3.choicesInstance.input.element) {
 286              return;
 287            }
 288  
 289            event.preventDefault(); // eslint-disable-next-line no-underscore-dangle
 290  
 291            if (_this3.choicesInstance._highlightPosition || !event.target.value) {
 292              return;
 293            } // Make sure nothing is highlighted
 294  
 295  
 296            var highlighted = _this3.choicesInstance.dropdown.element.querySelector("." + _this3.choicesInstance.config.classNames.highlightedState);
 297  
 298            if (highlighted) {
 299              return;
 300            } // Check if value already exist
 301  
 302  
 303            var lowerValue = event.target.value.toLowerCase();
 304            var valueInCache = false; // Check if value in existing choices
 305  
 306            _this3.choicesInstance.config.choices.some(function (choiceItem) {
 307              if (choiceItem.value.toLowerCase() === lowerValue || choiceItem.label.toLowerCase() === lowerValue) {
 308                valueInCache = choiceItem.value;
 309                return true;
 310              }
 311  
 312              return false;
 313            });
 314  
 315            if (valueInCache === false) {
 316              // Check if value in cache
 317              Object.keys(_this3.choicesCache).some(function (key) {
 318                if (key.toLowerCase() === lowerValue || _this3.choicesCache[key].toLowerCase() === lowerValue) {
 319                  valueInCache = key;
 320                  return true;
 321                }
 322  
 323                return false;
 324              });
 325            } // Make choice based on existing value
 326  
 327  
 328            if (valueInCache !== false) {
 329              _this3.choicesInstance.setChoiceByValue(valueInCache);
 330  
 331              event.target.value = null;
 332  
 333              _this3.choicesInstance.hideDropdown();
 334  
 335              return;
 336            } // Create and add new
 337  
 338  
 339            _this3.choicesInstance.setChoices([{
 340              value: _this3.newItemPrefix + event.target.value,
 341              label: event.target.value,
 342              selected: true,
 343              customProperties: {
 344                value: event.target.value // Store real value, just in case
 345  
 346              }
 347            }], 'value', 'label', false);
 348  
 349            _this3.choicesCache[event.target.value] = event.target.value;
 350            event.target.value = null;
 351  
 352            _this3.choicesInstance.hideDropdown();
 353          });
 354        } // Handle remote search
 355  
 356  
 357        if (this.remoteSearch && this.url) {
 358          // Cache existing
 359          this.choicesInstance.config.choices.forEach(function (choiceItem) {
 360            _this3.choicesCache[choiceItem.value] = choiceItem.label;
 361          });
 362          var lookupDelay = 300;
 363          var lookupTimeout = null;
 364          this.select.addEventListener('search', function () {
 365            clearTimeout(lookupTimeout);
 366            lookupTimeout = setTimeout(_this3.requestLookup.bind(_this3), lookupDelay);
 367          });
 368        }
 369      }
 370      /**
 371       * Lifecycle
 372       */
 373      ;
 374  
 375      _proto.disconnectedCallback = function disconnectedCallback() {
 376        // Destroy Choices instance, to unbind event listeners
 377        if (this.choicesInstance) {
 378          this.choicesInstance.destroy();
 379          this.isDisconnected = true;
 380        }
 381  
 382        if (this.activeXHR) {
 383          this.activeXHR.abort();
 384          this.activeXHR = null;
 385        }
 386      };
 387  
 388      _proto.requestLookup = function requestLookup() {
 389        var _this4 = this;
 390  
 391        var url = this.url;
 392        url += url.indexOf('?') === -1 ? '?' : '&';
 393        url += encodeURIComponent(this.termKey) + "=" + encodeURIComponent(this.choicesInstance.input.value); // Stop previous request if any
 394  
 395        if (this.activeXHR) {
 396          this.activeXHR.abort();
 397        }
 398  
 399        this.activeXHR = Joomla.request({
 400          url: url,
 401          onSuccess: function onSuccess(response) {
 402            _this4.activeXHR = null;
 403            var items = response ? JSON.parse(response) : [];
 404  
 405            if (!items.length) {
 406              return;
 407            } // Remove duplications
 408  
 409  
 410            var item; // eslint-disable-next-line no-plusplus
 411  
 412            for (var i = items.length - 1; i >= 0; i--) {
 413              // The loop must be form the end !!!
 414              item = items[i]; // eslint-disable-next-line prefer-template
 415  
 416              item.value = '' + item.value; // Make sure the value is a string, choices.js expect a string.
 417  
 418              if (_this4.choicesCache[item.value]) {
 419                items.splice(i, 1);
 420              } else {
 421                _this4.choicesCache[item.value] = item.text;
 422              }
 423            } // Add new options to field, assume that each item is object, eg {value: "foo", text: "bar"}
 424  
 425  
 426            if (items.length) {
 427              _this4.choicesInstance.setChoices(items, 'value', 'text', false);
 428            }
 429          },
 430          onError: function onError() {
 431            _this4.activeXHR = null;
 432          }
 433        });
 434      };
 435  
 436      _proto.disableAllOptions = function disableAllOptions() {
 437        // Choices.js does not offer a public API for accessing the choices
 438        // So we have to access the private store => don't eslint
 439        // eslint-disable-next-line no-underscore-dangle
 440        var choices = this.choicesInstance._store.choices;
 441        choices.forEach(function (elem, index) {
 442          choices[index].disabled = true;
 443          choices[index].selected = false;
 444        });
 445        this.choicesInstance.clearStore();
 446        this.choicesInstance.setChoices(choices, 'value', 'label', true);
 447      };
 448  
 449      _proto.enableAllOptions = function enableAllOptions() {
 450        // Choices.js does not offer a public API for accessing the choices
 451        // So we have to access the private store => don't eslint
 452        // eslint-disable-next-line no-underscore-dangle
 453        var choices = this.choicesInstance._store.choices;
 454        var values = this.choicesInstance.getValue(true);
 455        choices.forEach(function (elem, index) {
 456          choices[index].disabled = false;
 457        });
 458        this.choicesInstance.clearStore();
 459        this.choicesInstance.setChoices(choices, 'value', 'label', true);
 460        this.value = values;
 461      };
 462  
 463      _proto.disableByValue = function disableByValue($val) {
 464        // Choices.js does not offer a public API for accessing the choices
 465        // So we have to access the private store => don't eslint
 466        // eslint-disable-next-line no-underscore-dangle
 467        var choices = this.choicesInstance._store.choices;
 468        var values = this.choicesInstance.getValue(true);
 469        choices.forEach(function (elem, index) {
 470          if (elem.value === $val) {
 471            choices[index].disabled = true;
 472            choices[index].selected = false;
 473          }
 474        });
 475        var index = values.indexOf($val);
 476  
 477        if (index > -1) {
 478          values.slice(index, 1);
 479        }
 480  
 481        this.choicesInstance.clearStore();
 482        this.choicesInstance.setChoices(choices, 'value', 'label', true);
 483        this.value = values;
 484      };
 485  
 486      _proto.enableByValue = function enableByValue($val) {
 487        // Choices.js does not offer a public API for accessing the choices
 488        // So we have to access the private store => don't eslint
 489        // eslint-disable-next-line no-underscore-dangle
 490        var choices = this.choicesInstance._store.choices;
 491        var values = this.choicesInstance.getValue(true);
 492        choices.forEach(function (elem, index) {
 493          if (elem.value === $val) {
 494            choices[index].disabled = false;
 495          }
 496        });
 497        this.choicesInstance.clearStore();
 498        this.choicesInstance.setChoices(choices, 'value', 'label', true);
 499        this.value = values;
 500      };
 501  
 502      _createClass(_class, [{
 503        key: "allowCustom",
 504        get: // Attributes to monitor
 505        function get() {
 506          return this.hasAttribute('allow-custom');
 507        }
 508      }, {
 509        key: "remoteSearch",
 510        get: function get() {
 511          return this.hasAttribute('remote-search');
 512        }
 513      }, {
 514        key: "url",
 515        get: function get() {
 516          return this.getAttribute('url');
 517        }
 518      }, {
 519        key: "termKey",
 520        get: function get() {
 521          return this.getAttribute('term-key') || 'term';
 522        }
 523      }, {
 524        key: "minTermLength",
 525        get: function get() {
 526          return parseInt(this.getAttribute('min-term-length'), 10) || 1;
 527        }
 528      }, {
 529        key: "newItemPrefix",
 530        get: function get() {
 531          return this.getAttribute('new-item-prefix') || '';
 532        }
 533      }, {
 534        key: "placeholder",
 535        get: function get() {
 536          return this.getAttribute('placeholder');
 537        }
 538      }, {
 539        key: "searchPlaceholder",
 540        get: function get() {
 541          return this.getAttribute('search-placeholder');
 542        }
 543      }, {
 544        key: "value",
 545        get: function get() {
 546          return this.choicesInstance.getValue(true);
 547        },
 548        set: function set($val) {
 549          this.choicesInstance.setChoiceByValue($val);
 550        }
 551      }]);
 552  
 553      return _class;
 554    }( /*#__PURE__*/_wrapNativeSuper(HTMLElement)));
 555  
 556  })();


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