Source: admin/javascript/engine/widgets/group_check.js

/* --------------------------------------------------------------
 group_check.js 2017-10-10
 Gambio GmbH
 http://www.gambio.de
 Copyright (c) 2017 Gambio GmbH
 Released under the GNU General Public License (Version 2)
 [http://www.gnu.org/licenses/gpl-2.0.html]
 --------------------------------------------------------------
 */

/**
 * ## Group check widget
 *
 * The widget creates a panel with switcher fields for all customer groups. If the options "user" and "section" are
 * provided, the user configuration service will be used to store the panels collapsed/expanded state.
 *
 * ### Options (Required)
 *
 * **User | `data-panel-user` | Integer | Optional**
 *
 * Customer id of user, used by user configuration service to store the collapsed state.
 *
 * **Section | `data-panel-section` | String | Optional**
 *
 * Panel section, used by user configuration service 'configuration_key'. The value get a "**'group_check_'**"-prefix.
 *
 * ### Options (Additional)
 *
 * **Selected | `data-group_check-selected` | String | Additional**
 *
 * Comma separated list of customer status ids. If an switcher value is equal to one of the customer ids, the
 * switcher state is active. Alternatively you can set the value "all" to set all switchers to an active state.
 *
 * **Name | `data-group_check-name` | String | Additional**
 *
 * Name attribute of switchers hidden input:checkbox field. If no value is provided, it defaults to **'group_check'**
 *
 * ### Example
 *
 * * ```html
 * <div data-gx-widget="group_check"
 *      data-group_check-user="{$smarty.session.customer_id}"
 *      data-group_check-section="group-check-sample-section"
 *      data-group_check-active="[1,2,3]|[all]"
 *      data-group_check-name="custom-switcher-name"></div>
 * ```
 *
 * @module Admin/Widgets/group_check
 */
gx.widgets.module(
	'group_check',
	
	['xhr'],
	
	/** @lends module:Widgets/group_check */
	
	function(data) {
		
		'use strict';
		
		// ------------------------------------------------------------------------
		// VARIABLE DEFINITION
		// ------------------------------------------------------------------------
		
		/**
		 * Widget Reference
		 *
		 * @type {object}
		 */
		const $this = $(this);
		
		/**
		 * Default Widget Options
		 *
		 * @type {object}
		 */
		const defaults = {
			name: 'group_check'
		};
		
		/**
		 * Final Widget Options
		 *
		 * @type {object}
		 */
		const options = $.extend(true, {}, defaults, data);
		
		/**
		 * Module Object
		 *
		 * @type {object}
		 */
		const module = {};
		
		/**
		 * Required options.
		 *
		 * @type {[string,string]}
		 */
		const requiredOptions = ['user', 'section'];
		
		/**
		 * Element for whether selecting or deselecting all other switcher.
		 */
		let $allSwitcher;
		
		/**
		 * Renders the group check box.
		 *
		 * @private
		 */
		const _renderGroupCheck = () => {
			jse.libs.xhr.get({
				url: './admin.php?do=JSWidgetsAjax/isGroupCheckEnabled'
			}).done(r => {
				if (r.status) {
					const $container = $('<div/>', {
						'data-gx-widget': 'panel switcher',
						'data-panel-title': jse.core.lang.translate('HEADING_GROUP_CHECK', 'content_manager'),
						'data-panel-user': options.user,
						'data-panel-section': 'group_check_' + options.section,
						'data-panel-container_class': 'group-check'
					});
					
					$container.append(_renderBody(r.customerGroups)).appendTo($this);
					gx.widgets.init($container).then(() => {
						_setEventListener();
						_setSwitcherDefaultStates();
					});
				}
			});
		};
		
		/**
		 * Sets default state of switcher elements.
		 * The "selected" option is used to determine the default state.
		 *
		 * @private
		 */
		const _setSwitcherDefaultStates = () => {
			// just continue if option is not set
			if (undefined === options.selected || options.selected === '') {
				return;
			}
			
			// use bulk switcher action if option value is set to "all"
			if (options.selected === 'all') {
				$allSwitcher.find('input:checkbox').switcher('checked', true);
				_bulkSwitcherAction(true);
				return;
			}
			
			// activate switcher programmatically
			let preselection;
			if (Number.isInteger(options.selected)) {
				preselection = [options.selected];
			} else {
				preselection = options.selected.split(',').map(Number);
			}
			
			const switcher = $this.find('input:checkbox');
			let i = 0;
			
			for (; i < switcher.length; i++) {
				if (switcher[i].value !== 'all') {
					if (preselection.indexOf(parseInt(switcher[i].value, 10)) !== -1) {
						$(switcher[i]).switcher('checked', true);
					}
				}
			}
			_tryActiveAllSwitcher();
		};
		
		/**
		 * Renders the panel body.
		 * @param {Object} customerGroups Serialized customer group collection, provided by ajax request.
		 * @returns {jQuery} Panel body html.
		 * @private
		 */
		const _renderBody = customerGroups => {
			const $gxContainer = $('<div/>', {
				'class': 'gx-container'
			});
			const $fieldSet = $('<fieldset/>');
			
			$allSwitcher = _renderFormGroup(jse.core.lang.translate('LABLE_GROUPCHECK_ALL', 'content_manager'), 'all');
			$fieldSet.append($allSwitcher);
			
			let i = 0;
			for (; i < customerGroups.length; i++) {
				$fieldSet.append(_renderFormGroup(customerGroups[i].names[jse.core.config.get('languageCode')
					.toUpperCase()], customerGroups[i].id));
			}
			$gxContainer.append($fieldSet);
			
			return $gxContainer;
		};
		
		/**
		 * Renders the form group elements of the group check.
		 *
		 * @param {string} label Label name.
		 * @param {string} value Switchers value attribute.
		 * @returns {jQuery} Form group html.
		 * @private
		 */
		const _renderFormGroup = (label, value) => {
			const $formGroup = $('<div/>', {'class': 'form-group'});
			const $label = $('<label/>', {
				'for': 'customer-groups-' + label.toLowerCase(),
				'class': 'col-md-4',
				'text': label
			});
			const $inputContainer = $('<div/>', {
				'class': 'col-md-6'
			});
			const $input = $('<input/>', {
				'type': 'checkbox',
				'id': 'customer-groups-' + label.toLowerCase(),
				'name': options.name + '[]',
				'value': value,
				'checked': options.all_checked
			});
			$inputContainer.append($input);
			
			return $formGroup.append($label).append($inputContainer);
		};
		
		/**
		 * Checks if all required options are passed.
		 *
		 * @private
		 */
		const _checkRequiredOptions = () => {
			let i = 0;
			for (; i < requiredOptions.length; i++) {
				if (undefined === options[requiredOptions[i]]) {
					throw new Error('Required widget option "' + requiredOptions[i] + '" is no set!');
				}
			}
		};
		
		/**
		 * Sets the event listener for the group check widget.
		 *
		 * @private
		 */
		const _setEventListener = () => {
			const switcher = $this.find('input:checkbox');
			
			// check all switcher if the "all" switcher is clicked
			$allSwitcher.on('change', () => {
				if ($allSwitcher.find('input:checkbox').prop('checked')) {
					_bulkSwitcherAction(true);
				} else {
					_bulkSwitcherAction(false);
				}
			});
			
			switcher.on('change', e => {
				if (!$allSwitcher.find('input:checkbox').is(e.currentTarget)) {
					// remove checked attribute from "all" switcher if one is deselected
					if (!$(e.currentTarget).prop('checked')) {
						$allSwitcher.find('input:checkbox').switcher('checked', false);
					}
					
					_tryActiveAllSwitcher();
				}
			});
		};
		
		/**
		 * This method checks if all other switcher fields instead of "all" are active.
		 * If so, the "all" switcher will be activated.
		 *
		 * @private
		 */
		const _tryActiveAllSwitcher = () => {
			const switcher = $this.find('input:checkbox');
			let allChecked = true;
			let i = 0;
			
			for (; i < switcher.length; i++) {
				if (!$allSwitcher.find('input:checkbox').is($(switcher[i]))) {
					allChecked = allChecked && $(switcher[i]).prop('checked');
				}
			}
			if (allChecked) {
				$allSwitcher.find('input:checkbox').switcher('checked', true);
			}
		}
		
		/**
		 * Bulk action for whether selecting or deselecting all switcher elements.
		 *
		 * @param {boolean} checked Status of "checked" property.
		 * @private
		 */
		const _bulkSwitcherAction = checked => {
			const switcher = $this.find('input:checkbox');
			let i = 0;
			for (; i < switcher.length; i++) {
				if (!$allSwitcher.find('input:checkbox').is($(switcher[i]))) {
					$(switcher[i]).switcher('checked', checked);
				}
			}
		};
		
		// ------------------------------------------------------------------------
		// INITIALIZATION
		// ------------------------------------------------------------------------
		
		/**
		 * Initialize method of the widget, called by the engine.
		 */
		module.init = done => {
			_checkRequiredOptions();
			_renderGroupCheck();
			done();
		};
		
		return module;
	});