123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- /**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- define([
- 'underscore',
- 'jquery',
- 'text!mage/multiselect.html',
- 'Magento_Ui/js/modal/alert',
- 'jquery/ui',
- 'jquery/editableMultiselect/js/jquery.multiselect'
- ], function (_, $, searchTemplate, alert) {
- 'use strict';
- $.widget('mage.multiselect2', {
- options: {
- mselectContainer: 'section.mselect-list',
- mselectItemsWrapperClass: 'mselect-items-wrapper',
- mselectCheckedClass: 'mselect-checked',
- containerClass: 'paginated',
- searchInputClass: 'admin__action-multiselect-search',
- selectedItemsCountClass: 'admin__action-multiselect-items-selected',
- currentPage: 1,
- lastAppendValue: 0,
- updateDelay: 1000,
- optionsLoaded: false
- },
- /** @inheritdoc */
- _create: function () {
- $.fn.multiselect.call(this.element, this.options);
- },
- /** @inheritdoc */
- _init: function () {
- this.domElement = this.element.get(0);
- this.$container = $(this.options.mselectContainer);
- this.$wrapper = this.$container.find('.' + this.options.mselectItemsWrapperClass);
- this.$item = this.$wrapper.find('div').first();
- this.selectedValues = [];
- this.values = {};
- this.$container.addClass(this.options.containerClass).prepend(searchTemplate);
- this.$input = this.$container.find('.' + this.options.searchInputClass);
- this.$selectedCounter = this.$container.find('.' + this.options.selectedItemsCountClass);
- this.filter = '';
- if (this.domElement.options.length) {
- this._setLastAppendOption(this.domElement.options[this.domElement.options.length - 1].value);
- }
- this._initElement();
- this._events();
- },
- /**
- * Leave only saved/selected options in select element.
- *
- * @private
- */
- _initElement: function () {
- this.element.empty();
- _.each(this.options.selectedValues, function (value) {
- this._createSelectedOption({
- value: value,
- label: value
- });
- }, this);
- },
- /**
- * Attach required events.
- *
- * @private
- */
- _events: function () {
- var onKeyUp = _.debounce(this.onKeyUp, this.options.updateDelay);
- _.bindAll(this, 'onScroll', 'onCheck', 'onOptionsChange');
- this.$wrapper.on('scroll', this.onScroll);
- this.$wrapper.on('change.mselectCheck', '[type=checkbox]', this.onCheck);
- this.$input.on('keyup', _.bind(onKeyUp, this));
- this.element.on('change.hiddenSelect', this.onOptionsChange);
- },
- /**
- * Behaves multiselect scroll.
- */
- onScroll: function () {
- var height = this.$wrapper.height(),
- scrollHeight = this.$wrapper.prop('scrollHeight'),
- scrollTop = Math.ceil(this.$wrapper.prop('scrollTop'));
- if (!this.options.optionsLoaded && scrollHeight - height <= scrollTop) {
- this.loadOptions();
- }
- },
- /**
- * Behaves keyup event on input search
- */
- onKeyUp: function () {
- if (this.getSearchCriteria() === this.filter) {
- return false;
- }
- this.setFilter();
- this.clearMultiselectOptions();
- this.setCurrentPage(0);
- this.loadOptions();
- },
- /**
- * Callback for select change event
- */
- onOptionsChange: function () {
- this.selectedValues = _.map(this.domElement.options, function (option) {
- this.values[option.value] = true;
- return option.value;
- }, this);
- this._updateSelectedCounter();
- },
- /**
- * Overrides native check behaviour.
- *
- * @param {Event} event
- */
- onCheck: function (event) {
- var checkbox = event.target,
- option = {
- value: checkbox.value,
- label: $(checkbox).parent('label').text()
- };
- checkbox.checked ? this._createSelectedOption(option) : this._removeSelectedOption(option);
- event.stopPropagation();
- },
- /**
- * Show error message.
- *
- * @param {String} message
- */
- onError: function (message) {
- alert({
- content: message
- });
- },
- /**
- * Updates current filter state.
- */
- setFilter: function () {
- this.filter = this.getSearchCriteria() || '';
- },
- /**
- * Reads search input value.
- *
- * @return {String}
- */
- getSearchCriteria: function () {
- return $.trim(this.$input.val());
- },
- /**
- * Load options data.
- */
- loadOptions: function () {
- var nextPage = this.getCurrentPage() + 1;
- this.$wrapper.trigger('processStart');
- this.$input.prop('disabled', true);
- $.get(this.options.nextPageUrl, {
- p: nextPage,
- s: this.filter
- })
- .done(function (response) {
- if (response.success) {
- this.appendOptions(response.result);
- this.setCurrentPage(nextPage);
- } else {
- this.onError(response.errorMessage);
- }
- }.bind(this))
- .always(function () {
- this.$wrapper.trigger('processStop');
- this.$input.prop('disabled', false);
- if (this.filter) {
- this.$input.focus();
- }
- }.bind(this));
- },
- /**
- * Append loaded options
- *
- * @param {Array} options
- */
- appendOptions: function (options) {
- var divOptions = [];
- if (!options.length) {
- return false;
- }
- if (this.isOptionsLoaded(options)) {
- return;
- }
- options.forEach(function (option) {
- if (!this.values[option.value]) {
- this.values[option.value] = true;
- option.selected = this._isOptionSelected(option);
- divOptions.push(this._createMultiSelectOption(option));
- this._setLastAppendOption(option.value);
- }
- }, this);
- this.$wrapper.append(divOptions);
- },
- /**
- * Clear multiselect options
- */
- clearMultiselectOptions: function () {
- this._setLastAppendOption(0);
- this.values = {};
- this.$wrapper.empty();
- },
- /**
- * Checks if all options are already loaded
- *
- * @return {Boolean}
- */
- isOptionsLoaded: function (options) {
- this.options.optionsLoaded = this.options.lastAppendValue === options[options.length - 1].value;
- return this.options.optionsLoaded;
- },
- /**
- * Setter for current page.
- *
- * @param {Number} page
- */
- setCurrentPage: function (page) {
- this.options.currentPage = page;
- },
- /**
- * Getter for current page.
- *
- * @return {Number}
- */
- getCurrentPage: function () {
- return this.options.currentPage;
- },
- /**
- * Creates new selected option for select element
- *
- * @param {Object} option - option object
- * @param {String} option.value - option value
- * @param {String} option.label - option label
- * @private
- */
- _createSelectedOption: function (option) {
- var selectOption = new Option(option.label, option.value, false, true);
- this.element.append(selectOption);
- this.selectedValues.push(option.value);
- this._updateSelectedCounter();
- return selectOption;
- },
- /**
- * Remove passed option from select element
- *
- * @param {Object} option - option object
- * @param {String} option.value - option value
- * @param {String} option.label - option label
- * @return {Object} option
- * @private
- */
- _removeSelectedOption: function (option) {
- var unselectedOption = _.findWhere(this.domElement.options, {
- value: option.value
- });
- if (!_.isUndefined(unselectedOption)) {
- this.domElement.remove(unselectedOption.index);
- this.selectedValues.splice(_.indexOf(this.selectedValues, option.value), 1);
- this._updateSelectedCounter();
- }
- return unselectedOption;
- },
- /**
- * Creates new DIV option for multiselect widget
- *
- * @param {Object} option - option object
- * @param {String} option.value - option value
- * @param {String} option.label - option label
- * @param {Boolean} option.selected - is option selected
- * @private
- */
- _createMultiSelectOption: function (option) {
- var item = this.$item.clone(),
- checkbox = item.find('input'),
- isSelected = !!option.selected;
- checkbox.val(option.value)
- .prop('checked', isSelected)
- .toggleClass(this.options.mselectCheckedClass, isSelected);
- item.find('label > span').text(option.label);
- return item;
- },
- /**
- * Checks if passed option should be selected
- *
- * @param {Object} option - option object
- * @param {String} option.value - option value
- * @param {String} option.label - option label
- * @param {Boolean} option.selected - is option selected
- * @return {Boolean}
- * @private
- */
- _isOptionSelected: function (option) {
- return !!~this.selectedValues.indexOf(option.value);
- },
- /**
- * Saves last added option value.
- *
- * @param {Number} value
- * @private
- */
- _setLastAppendOption: function (value) {
- this.options.lastAppendValue = value;
- },
- /**
- * Updates counter of selected items.
- *
- * @private
- */
- _updateSelectedCounter: function () {
- this.$selectedCounter.text(this.selectedValues.length);
- }
- });
- return $.mage.multiselect2;
- });
|