Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/materialize-css/js/select.js')
-rw-r--r--node_modules/materialize-css/js/select.js432
1 files changed, 432 insertions, 0 deletions
diff --git a/node_modules/materialize-css/js/select.js b/node_modules/materialize-css/js/select.js
new file mode 100644
index 0000000000..2266de8500
--- /dev/null
+++ b/node_modules/materialize-css/js/select.js
@@ -0,0 +1,432 @@
+(function($) {
+ 'use strict';
+
+ let _defaults = {
+ classes: '',
+ dropdownOptions: {}
+ };
+
+ /**
+ * @class
+ *
+ */
+ class FormSelect extends Component {
+ /**
+ * Construct FormSelect instance
+ * @constructor
+ * @param {Element} el
+ * @param {Object} options
+ */
+ constructor(el, options) {
+ super(FormSelect, el, options);
+
+ // Don't init if browser default version
+ if (this.$el.hasClass('browser-default')) {
+ return;
+ }
+
+ this.el.M_FormSelect = this;
+
+ /**
+ * Options for the select
+ * @member FormSelect#options
+ */
+ this.options = $.extend({}, FormSelect.defaults, options);
+
+ this.isMultiple = this.$el.prop('multiple');
+
+ // Setup
+ this.el.tabIndex = -1;
+ this._keysSelected = {};
+ this._valueDict = {}; // Maps key to original and generated option element.
+ this._setupDropdown();
+
+ this._setupEventHandlers();
+ }
+
+ static get defaults() {
+ return _defaults;
+ }
+
+ static init(els, options) {
+ return super.init(this, els, options);
+ }
+
+ /**
+ * Get Instance
+ */
+ static getInstance(el) {
+ let domElem = !!el.jquery ? el[0] : el;
+ return domElem.M_FormSelect;
+ }
+
+ /**
+ * Teardown component
+ */
+ destroy() {
+ this._removeEventHandlers();
+ this._removeDropdown();
+ this.el.M_FormSelect = undefined;
+ }
+
+ /**
+ * Setup Event Handlers
+ */
+ _setupEventHandlers() {
+ this._handleSelectChangeBound = this._handleSelectChange.bind(this);
+ this._handleOptionClickBound = this._handleOptionClick.bind(this);
+ this._handleInputClickBound = this._handleInputClick.bind(this);
+
+ $(this.dropdownOptions)
+ .find('li:not(.optgroup)')
+ .each((el) => {
+ el.addEventListener('click', this._handleOptionClickBound);
+ });
+ this.el.addEventListener('change', this._handleSelectChangeBound);
+ this.input.addEventListener('click', this._handleInputClickBound);
+ }
+
+ /**
+ * Remove Event Handlers
+ */
+ _removeEventHandlers() {
+ $(this.dropdownOptions)
+ .find('li:not(.optgroup)')
+ .each((el) => {
+ el.removeEventListener('click', this._handleOptionClickBound);
+ });
+ this.el.removeEventListener('change', this._handleSelectChangeBound);
+ this.input.removeEventListener('click', this._handleInputClickBound);
+ }
+
+ /**
+ * Handle Select Change
+ * @param {Event} e
+ */
+ _handleSelectChange(e) {
+ this._setValueToInput();
+ }
+
+ /**
+ * Handle Option Click
+ * @param {Event} e
+ */
+ _handleOptionClick(e) {
+ e.preventDefault();
+ let option = $(e.target).closest('li')[0];
+ let key = option.id;
+ if (!$(option).hasClass('disabled') && !$(option).hasClass('optgroup') && key.length) {
+ let selected = true;
+
+ if (this.isMultiple) {
+ // Deselect placeholder option if still selected.
+ let placeholderOption = $(this.dropdownOptions).find('li.disabled.selected');
+ if (placeholderOption.length) {
+ placeholderOption.removeClass('selected');
+ placeholderOption.find('input[type="checkbox"]').prop('checked', false);
+ this._toggleEntryFromArray(placeholderOption[0].id);
+ }
+ selected = this._toggleEntryFromArray(key);
+ } else {
+ $(this.dropdownOptions)
+ .find('li')
+ .removeClass('selected');
+ $(option).toggleClass('selected', selected);
+ }
+
+ // Set selected on original select option
+ // Only trigger if selected state changed
+ let prevSelected = $(this._valueDict[key].el).prop('selected');
+ if (prevSelected !== selected) {
+ $(this._valueDict[key].el).prop('selected', selected);
+ this.$el.trigger('change');
+ }
+ }
+
+ e.stopPropagation();
+ }
+
+ /**
+ * Handle Input Click
+ */
+ _handleInputClick() {
+ if (this.dropdown && this.dropdown.isOpen) {
+ this._setValueToInput();
+ this._setSelectedStates();
+ }
+ }
+
+ /**
+ * Setup dropdown
+ */
+ _setupDropdown() {
+ this.wrapper = document.createElement('div');
+ $(this.wrapper).addClass('select-wrapper ' + this.options.classes);
+ this.$el.before($(this.wrapper));
+ this.wrapper.appendChild(this.el);
+
+ if (this.el.disabled) {
+ this.wrapper.classList.add('disabled');
+ }
+
+ // Create dropdown
+ this.$selectOptions = this.$el.children('option, optgroup');
+ this.dropdownOptions = document.createElement('ul');
+ this.dropdownOptions.id = `select-options-${M.guid()}`;
+ $(this.dropdownOptions).addClass(
+ 'dropdown-content select-dropdown ' + (this.isMultiple ? 'multiple-select-dropdown' : '')
+ );
+
+ // Create dropdown structure.
+ if (this.$selectOptions.length) {
+ this.$selectOptions.each((el) => {
+ if ($(el).is('option')) {
+ // Direct descendant option.
+ let optionEl;
+ if (this.isMultiple) {
+ optionEl = this._appendOptionWithIcon(this.$el, el, 'multiple');
+ } else {
+ optionEl = this._appendOptionWithIcon(this.$el, el);
+ }
+
+ this._addOptionToValueDict(el, optionEl);
+ } else if ($(el).is('optgroup')) {
+ // Optgroup.
+ let selectOptions = $(el).children('option');
+ $(this.dropdownOptions).append(
+ $('<li class="optgroup"><span>' + el.getAttribute('label') + '</span></li>')[0]
+ );
+
+ selectOptions.each((el) => {
+ let optionEl = this._appendOptionWithIcon(this.$el, el, 'optgroup-option');
+ this._addOptionToValueDict(el, optionEl);
+ });
+ }
+ });
+ }
+
+ this.$el.after(this.dropdownOptions);
+
+ // Add input dropdown
+ this.input = document.createElement('input');
+ $(this.input).addClass('select-dropdown dropdown-trigger');
+ this.input.setAttribute('type', 'text');
+ this.input.setAttribute('readonly', 'true');
+ this.input.setAttribute('data-target', this.dropdownOptions.id);
+ if (this.el.disabled) {
+ $(this.input).prop('disabled', 'true');
+ }
+
+ this.$el.before(this.input);
+ this._setValueToInput();
+
+ // Add caret
+ let dropdownIcon = $(
+ '<svg class="caret" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M7 10l5 5 5-5z"/><path d="M0 0h24v24H0z" fill="none"/></svg>'
+ );
+ this.$el.before(dropdownIcon[0]);
+
+ // Initialize dropdown
+ if (!this.el.disabled) {
+ let dropdownOptions = $.extend({}, this.options.dropdownOptions);
+
+ // Add callback for centering selected option when dropdown content is scrollable
+ dropdownOptions.onOpenEnd = (el) => {
+ let selectedOption = $(this.dropdownOptions)
+ .find('.selected')
+ .first();
+
+ if (selectedOption.length) {
+ // Focus selected option in dropdown
+ M.keyDown = true;
+ this.dropdown.focusedIndex = selectedOption.index();
+ this.dropdown._focusFocusedItem();
+ M.keyDown = false;
+
+ // Handle scrolling to selected option
+ if (this.dropdown.isScrollable) {
+ let scrollOffset =
+ selectedOption[0].getBoundingClientRect().top -
+ this.dropdownOptions.getBoundingClientRect().top; // scroll to selected option
+ scrollOffset -= this.dropdownOptions.clientHeight / 2; // center in dropdown
+ this.dropdownOptions.scrollTop = scrollOffset;
+ }
+ }
+ };
+
+ if (this.isMultiple) {
+ dropdownOptions.closeOnClick = false;
+ }
+ this.dropdown = M.Dropdown.init(this.input, dropdownOptions);
+ }
+
+ // Add initial selections
+ this._setSelectedStates();
+ }
+
+ /**
+ * Add option to value dict
+ * @param {Element} el original option element
+ * @param {Element} optionEl generated option element
+ */
+ _addOptionToValueDict(el, optionEl) {
+ let index = Object.keys(this._valueDict).length;
+ let key = this.dropdownOptions.id + index;
+ let obj = {};
+ optionEl.id = key;
+
+ obj.el = el;
+ obj.optionEl = optionEl;
+ this._valueDict[key] = obj;
+ }
+
+ /**
+ * Remove dropdown
+ */
+ _removeDropdown() {
+ $(this.wrapper)
+ .find('.caret')
+ .remove();
+ $(this.input).remove();
+ $(this.dropdownOptions).remove();
+ $(this.wrapper).before(this.$el);
+ $(this.wrapper).remove();
+ }
+
+ /**
+ * Setup dropdown
+ * @param {Element} select select element
+ * @param {Element} option option element from select
+ * @param {String} type
+ * @return {Element} option element added
+ */
+ _appendOptionWithIcon(select, option, type) {
+ // Add disabled attr if disabled
+ let disabledClass = option.disabled ? 'disabled ' : '';
+ let optgroupClass = type === 'optgroup-option' ? 'optgroup-option ' : '';
+ let multipleCheckbox = this.isMultiple
+ ? `<label><input type="checkbox"${disabledClass}"/><span>${option.innerHTML}</span></label>`
+ : option.innerHTML;
+ let liEl = $('<li></li>');
+ let spanEl = $('<span></span>');
+ spanEl.html(multipleCheckbox);
+ liEl.addClass(`${disabledClass} ${optgroupClass}`);
+ liEl.append(spanEl);
+
+ // add icons
+ let iconUrl = option.getAttribute('data-icon');
+ if (!!iconUrl) {
+ let imgEl = $(`<img alt="" src="${iconUrl}">`);
+ liEl.prepend(imgEl);
+ }
+
+ // Check for multiple type.
+ $(this.dropdownOptions).append(liEl[0]);
+ return liEl[0];
+ }
+
+ /**
+ * Toggle entry from option
+ * @param {String} key Option key
+ * @return {Boolean} if entry was added or removed
+ */
+ _toggleEntryFromArray(key) {
+ let notAdded = !this._keysSelected.hasOwnProperty(key);
+ let $optionLi = $(this._valueDict[key].optionEl);
+
+ if (notAdded) {
+ this._keysSelected[key] = true;
+ } else {
+ delete this._keysSelected[key];
+ }
+
+ $optionLi.toggleClass('selected', notAdded);
+
+ // Set checkbox checked value
+ $optionLi.find('input[type="checkbox"]').prop('checked', notAdded);
+
+ // use notAdded instead of true (to detect if the option is selected or not)
+ $optionLi.prop('selected', notAdded);
+
+ return notAdded;
+ }
+
+ /**
+ * Set text value to input
+ */
+ _setValueToInput() {
+ let values = [];
+ let options = this.$el.find('option');
+
+ options.each((el) => {
+ if ($(el).prop('selected')) {
+ let text = $(el).text();
+ values.push(text);
+ }
+ });
+
+ if (!values.length) {
+ let firstDisabled = this.$el.find('option:disabled').eq(0);
+ if (firstDisabled.length && firstDisabled[0].value === '') {
+ values.push(firstDisabled.text());
+ }
+ }
+
+ this.input.value = values.join(', ');
+ }
+
+ /**
+ * Set selected state of dropdown to match actual select element
+ */
+ _setSelectedStates() {
+ this._keysSelected = {};
+
+ for (let key in this._valueDict) {
+ let option = this._valueDict[key];
+ let optionIsSelected = $(option.el).prop('selected');
+ $(option.optionEl)
+ .find('input[type="checkbox"]')
+ .prop('checked', optionIsSelected);
+ if (optionIsSelected) {
+ this._activateOption($(this.dropdownOptions), $(option.optionEl));
+ this._keysSelected[key] = true;
+ } else {
+ $(option.optionEl).removeClass('selected');
+ }
+ }
+ }
+
+ /**
+ * Make option as selected and scroll to selected position
+ * @param {jQuery} collection Select options jQuery element
+ * @param {Element} newOption element of the new option
+ */
+ _activateOption(collection, newOption) {
+ if (newOption) {
+ if (!this.isMultiple) {
+ collection.find('li.selected').removeClass('selected');
+ }
+ let option = $(newOption);
+ option.addClass('selected');
+ }
+ }
+
+ /**
+ * Get Selected Values
+ * @return {Array} Array of selected values
+ */
+ getSelectedValues() {
+ let selectedValues = [];
+ for (let key in this._keysSelected) {
+ selectedValues.push(this._valueDict[key].el.value);
+ }
+ return selectedValues;
+ }
+ }
+
+ M.FormSelect = FormSelect;
+
+ if (M.jQueryLoaded) {
+ M.initializeJqueryWrapper(FormSelect, 'formSelect', 'M_FormSelect');
+ }
+})(cash);