123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644 |
- import jquery from 'jquery';
- const $ = jquery || window.jQuery || window.$;
- function getClasses(options, id) {
- const { state, size, disabled, readonly, indeterminate, inverse } = options;
- return [
- state ? 'on' : 'off',
- size,
- disabled ? 'disabled' : undefined,
- readonly ? 'readonly' : undefined,
- indeterminate ? 'indeterminate' : undefined,
- inverse ? 'inverse' : undefined,
- id ? `id-${id}` : undefined,
- ].filter(v => v !== undefined);
- }
- function prvgetElementOptions() {
- const valueType = [
- 'text',
- 'on-off',
- 'boolean',
- ];
- return {
- state: this.$element.is(':checked'),
- size: this.$element.data('size'),
- animate: this.$element.data('animate'),
- disabled: this.$element.is(':disabled'),
- readonly: this.$element.is('[readonly]'),
- indeterminate: this.$element.data('indeterminate'),
- inverse: this.$element.data('inverse'),
- radioAllOff: this.$element.data('radio-all-off'),
- onColor: this.$element.data('on-color'),
- offColor: this.$element.data('off-color'),
- onText: this.$element.data('on-text'),
- offText: this.$element.data('off-text'),
- labelText: this.$element.data('label-text'),
- handleWidth: this.$element.data('handle-width'),
- labelWidth: this.$element.data('label-width'),
- baseClass: this.$element.data('base-class'),
- wrapperClass: this.$element.data('wrapper-class'),
- hookElement: null,
- hookNext: this.$element.data('hook-next') === 'true',
- valueType: valueType.indexOf(this.$element.data('value-type')) >= 0 ? this.$element.data('value-type') : 'on-off',
- };
- }
- function prvwidth() {
- const $handles = this.$on
- .add(this.$off)
- .add(this.$label)
- .css('width', '');
- const handleWidth = this.options.handleWidth === 'auto'
- ? Math.round(Math.max(this.$on.width(), this.$off.width()))
- : this.options.handleWidth;
- $handles.width(handleWidth);
- this.$label.width((index, width) => {
- if (this.options.labelWidth !== 'auto') { return this.options.labelWidth; }
- if (width < handleWidth) { return handleWidth; }
- return width;
- });
- this.privateHandleWidth = this.$on.outerWidth();
- this.privateLabelWidth = this.$label.outerWidth();
- this.$container.width((this.privateHandleWidth * 2) + this.privateLabelWidth);
- return this.$wrapper.width(this.privateHandleWidth + this.privateLabelWidth);
- }
- function prvcontainerPosition(state = this.options.state) {
- this.$container.css('margin-left', () => {
- const values = [0, `-${this.privateHandleWidth}px`];
- if (this.options.indeterminate) {
- return `-${this.privateHandleWidth / 2}px`;
- }
- if (state) {
- if (this.options.inverse) {
- return values[1];
- }
- return values[0];
- }
- if (this.options.inverse) {
- return values[0];
- }
- return values[1];
- });
- }
- function prvgetClass(name) {
- return `${this.options.baseClass}-${name}`;
- }
- function prvinit() {
- const init = () => {
- this.setPrevOptions();
- this::prvwidth();
- this::prvcontainerPosition();
- setTimeout(() => (
- this.options.animate &&
- this.$wrapper.addClass(this::prvgetClass('animate'),
- )), 50);
- };
- if (this.$wrapper.is(':visible')) {
- init();
- return;
- }
- const initInterval = window.setInterval(
- () => (
- this.$wrapper.is(':visible') &&
- (init() || true) &&
- window.clearInterval(initInterval)
- ), 50);
- }
- function prvelementHandlers() {
- return this.$element.on({
- 'setPreviousOptions.bootstrapSwitch': () => this.setPrevOptions(),
- 'previousState.bootstrapSwitch': () => {
- this.options = this.prevOptions;
- if (this.options.indeterminate) {
- this.$wrapper.addClass(this::prvgetClass('indeterminate'));
- }
- this.$element
- .prop('checked', this.options.state)
- .trigger('change.bootstrapSwitch', true);
- },
- 'change.bootstrapSwitch': (event, skip) => {
- event.preventDefault();
- event.stopImmediatePropagation();
- const state = this.$element.is(':checked');
- this::prvcontainerPosition(state);
- if (state === this.options.state) {
- return;
- }
- this.options.state = state;
- this.$wrapper
- .toggleClass(this::prvgetClass('off'))
- .toggleClass(this::prvgetClass('on'));
- if (!skip) {
- if (this.$element.is(':radio')) {
- $(`[name="${this.$element.attr('name')}"]`)
- .not(this.$element)
- .prop('checked', false)
- .trigger('change.bootstrapSwitch', true);
- }
- this.$element.trigger('switchChange.bootstrapSwitch', [state]);
- }
- },
- 'focus.bootstrapSwitch': (event) => {
- event.preventDefault();
- this.$wrapper.addClass(this::prvgetClass('focused'));
- },
- 'blur.bootstrapSwitch': (event) => {
- event.preventDefault();
- this.$wrapper.removeClass(this::prvgetClass('focused'));
- },
- 'keydown.bootstrapSwitch': (event) => {
- if (!event.which || this.options.disabled || this.options.readonly) {
- return;
- }
- if (event.which === 37 || event.which === 39) {
- event.preventDefault();
- event.stopImmediatePropagation();
- this.state(event.which === 39);
- }
- },
- });
- }
- function prvhandleHandlers() {
- this.$on.on('click.bootstrapSwitch', (event) => {
- event.preventDefault();
- event.stopPropagation();
- this.state(false);
- return this.$element.trigger('focus.bootstrapSwitch');
- });
- return this.$off.on('click.bootstrapSwitch', (event) => {
- event.preventDefault();
- event.stopPropagation();
- this.state(true);
- return this.$element.trigger('focus.bootstrapSwitch');
- });
- }
- function prvlabelHandlers() {
- let dragStart;
- let dragEnd;
- const handlers = {
- click(event) { event.stopPropagation(); },
- 'mousedown.bootstrapSwitch touchstart.bootstrapSwitch': (event) => {
- if (dragStart || this.options.disabled || this.options.readonly) {
- return;
- }
- event.preventDefault();
- event.stopPropagation();
- dragStart = (event.pageX || event.originalEvent.touches[0].pageX) - parseInt(this.$container.css('margin-left'), 10);
- if (this.options.animate) {
- this.$wrapper.removeClass(this::prvgetClass('animate'));
- }
- this.$element.trigger('focus.bootstrapSwitch');
- },
- 'mousemove.bootstrapSwitch touchmove.bootstrapSwitch': (event) => {
- if (dragStart == null) { return; }
- const difference = (event.pageX || event.originalEvent.touches[0].pageX) - dragStart;
- event.preventDefault();
- if (difference < -this.privateHandleWidth || difference > 0) { return; }
- dragEnd = difference;
- this.$container.css('margin-left', `${dragEnd}px`);
- },
- 'mouseup.bootstrapSwitch touchend.bootstrapSwitch': (event) => {
- if (!dragStart) { return; }
- event.preventDefault();
- if (this.options.animate) {
- this.$wrapper.addClass(this::prvgetClass('animate'));
- }
- if (dragEnd) {
- const state = dragEnd > -(this.privateHandleWidth / 2);
- dragEnd = false;
- this.state(this.options.inverse ? !state : state);
- } else {
- this.state(!this.options.state);
- }
- dragStart = false;
- },
- 'mouseleave.bootstrapSwitch': () => {
- this.$label.trigger('mouseup.bootstrapSwitch');
- },
- };
- this.$label.on(handlers);
- }
- function prvexternalLabelHandler() {
- const $externalLabel = this.$element.closest('label');
- $externalLabel.on('click', (event) => {
- event.preventDefault();
- event.stopImmediatePropagation();
- if (event.target === $externalLabel[0]) {
- this.toggleState();
- }
- });
- }
- function prvformHandler() {
- function isBootstrapSwitch() {
- return $(this).data('bootstrap-switch');
- }
- function performReset() {
- return $(this).bootstrapSwitch('state', this.checked);
- }
- const $form = this.$element.closest('form');
- if ($form.data('bootstrap-switch')) {
- return;
- }
- $form
- .on('reset.bootstrapSwitch', () => {
- window.setTimeout(() => {
- $form.find('input')
- .filter(isBootstrapSwitch)
- .each(performReset);
- }, 1);
- })
- .data('bootstrap-switch', true);
- }
- function prvgetClasses(classes) {
- if (!Array.isArray(classes)) {
- return [this::prvgetClass(classes)];
- }
- return classes.map(v => this::prvgetClass(v));
- }
- class BootstrapSwitch {
- constructor(element, options = {}) {
- this.$element = $(element);
- this.options = $.extend(
- {},
- $.fn.bootstrapSwitch.defaults,
- this::prvgetElementOptions(),
- options,
- );
- this.prevOptions = {};
- this.options.hookElement = this.options.hookNext
- ? this.$element.next() : this.options.hookElement;
- if (this.options.hookElement) {
- this.setHookValue(this.state());
- }
- this.$wrapper = $('<div>', {
- class: () => getClasses(this.options, this.$element.attr('id'))
- .map(v => this::prvgetClass(v))
- .concat([this.options.baseClass], this::prvgetClasses(this.options.wrapperClass))
- .join(' '),
- });
- this.$container = $('<div>', { class: this::prvgetClass('container') });
- this.$on = $('<span>', {
- html: this.options.onText,
- class: `${this::prvgetClass('handle-on')} ${this::prvgetClass(this.options.onColor)}`,
- });
- this.$off = $('<span>', {
- html: this.options.offText,
- class: `${this::prvgetClass('handle-off')} ${this::prvgetClass(this.options.offColor)}`,
- });
- this.$label = $('<span>', {
- html: this.options.labelText,
- class: this::prvgetClass('label'),
- });
- this.$element.on('init.bootstrapSwitch', () => {
- if (this.options.hookElement) {
- this.options.hookElement.attr('disabled', this.$element.attr('disabled'));
- }
- return this.options.onInit(element);
- });
- this.$element.on('switchChange.bootstrapSwitch', (...args) => {
- const changeState = this.options.onSwitchChange.apply(element, args);
- if (this.options.hookElement) {
- this.setHookValue(args[1]).change();
- }
- if (changeState === false) {
- if (this.$element.is(':radio')) {
- $(`[name="${this.$element.attr('name')}"]`).trigger('previousState.bootstrapSwitch', true);
- } else {
- this.$element.trigger('previousState.bootstrapSwitch', true);
- }
- }
- });
- this.$container = this.$element.wrap(this.$container).parent();
- this.$wrapper = this.$container.wrap(this.$wrapper).parent();
- this.$element
- .before(this.options.inverse ? this.$off : this.$on)
- .before(this.$label)
- .before(this.options.inverse ? this.$on : this.$off);
- if (this.options.indeterminate) {
- this.$element.prop('indeterminate', true);
- }
- this::prvinit();
- this::prvelementHandlers();
- this::prvhandleHandlers();
- this::prvlabelHandlers();
- this::prvformHandler();
- this::prvexternalLabelHandler();
- this.$element.trigger('init.bootstrapSwitch', this.options.state);
- }
- setPrevOptions() {
- this.prevOptions = { ...this.options };
- }
- state(value, skip) {
- if (typeof value === 'undefined') { return this.options.state; }
- if (
- (this.options.disabled || this.options.readonly) ||
- (this.options.state && !this.options.radioAllOff && this.$element.is(':radio'))
- ) { return this.$element; }
- if (this.$element.is(':radio')) {
- $(`[name="${this.$element.attr('name')}"]`).trigger('setPreviousOptions.bootstrapSwitch');
- } else {
- this.$element.trigger('setPreviousOptions.bootstrapSwitch');
- }
- if (this.options.indeterminate) {
- this.indeterminate(false);
- }
- this.$element
- .prop('checked', Boolean(value))
- .trigger('change.bootstrapSwitch', skip);
- return this.$element;
- }
- toggleState(skip) {
- if (this.options.disabled || this.options.readonly) { return this.$element; }
- if (this.options.indeterminate) {
- this.indeterminate(false);
- return this.state(true);
- }
- return this.$element.prop('checked', !this.options.state).trigger('change.bootstrapSwitch', skip);
- }
- size(value) {
- if (typeof value === 'undefined') { return this.options.size; }
- if (this.options.size != null) {
- this.$wrapper.removeClass(this::prvgetClass(this.options.size));
- }
- if (value) {
- this.$wrapper.addClass(this::prvgetClass(value));
- }
- this::prvwidth();
- this::prvcontainerPosition();
- this.options.size = value;
- return this.$element;
- }
- animate(value) {
- if (typeof value === 'undefined') { return this.options.animate; }
- if (this.options.animate === Boolean(value)) { return this.$element; }
- return this.toggleAnimate();
- }
- toggleAnimate() {
- this.options.animate = !this.options.animate;
- this.$wrapper.toggleClass(this::prvgetClass('animate'));
- return this.$element;
- }
- disabled(value) {
- if (typeof value === 'undefined') { return this.options.disabled; }
- if (this.options.disabled === Boolean(value)) { return this.$element; }
- return this.toggleDisabled();
- }
- toggleDisabled() {
- this.options.disabled = !this.options.disabled;
- this.$element.prop('disabled', this.options.disabled);
- if (this.options.hookElement) { this.options.hookElement.prop('disabled', this.options.disabled); }
- this.$wrapper.toggleClass(this::prvgetClass('disabled'));
- return this.$element;
- }
- readonly(value) {
- if (typeof value === 'undefined') { return this.options.readonly; }
- if (this.options.readonly === Boolean(value)) { return this.$element; }
- return this.toggleReadonly();
- }
- toggleReadonly() {
- this.options.readonly = !this.options.readonly;
- this.$element.prop('readonly', this.options.readonly);
- this.$wrapper.toggleClass(this::prvgetClass('readonly'));
- return this.$element;
- }
- indeterminate(value) {
- if (typeof value === 'undefined') { return this.options.indeterminate; }
- if (this.options.indeterminate === Boolean(value)) { return this.$element; }
- return this.toggleIndeterminate();
- }
- toggleIndeterminate() {
- this.options.indeterminate = !this.options.indeterminate;
- this.$element.prop('indeterminate', this.options.indeterminate);
- this.$wrapper.toggleClass(this::prvgetClass('indeterminate'));
- this::prvcontainerPosition();
- return this.$element;
- }
- inverse(value) {
- if (typeof value === 'undefined') { return this.options.inverse; }
- if (this.options.inverse === Boolean(value)) { return this.$element; }
- return this.toggleInverse();
- }
- toggleInverse() {
- this.$wrapper.toggleClass(this::prvgetClass('inverse'));
- const $on = this.$on.clone(true);
- const $off = this.$off.clone(true);
- this.$on.replaceWith($off);
- this.$off.replaceWith($on);
- this.$on = $off;
- this.$off = $on;
- this.options.inverse = !this.options.inverse;
- return this.$element;
- }
- onColor(value) {
- if (typeof value === 'undefined') { return this.options.onColor; }
- if (this.options.onColor) {
- this.$on.removeClass(this::prvgetClass(this.options.onColor));
- }
- this.$on.addClass(this::prvgetClass(value));
- this.options.onColor = value;
- return this.$element;
- }
- offColor(value) {
- if (typeof value === 'undefined') { return this.options.offColor; }
- if (this.options.offColor) {
- this.$off.removeClass(this::prvgetClass(this.options.offColor));
- }
- this.$off.addClass(this::prvgetClass(value));
- this.options.offColor = value;
- return this.$element;
- }
- onText(value) {
- if (typeof value === 'undefined') { return this.options.onText; }
- this.$on.html(value);
- this::prvwidth();
- this::prvcontainerPosition();
- this.options.onText = value;
- return this.$element;
- }
- offText(value) {
- if (typeof value === 'undefined') { return this.options.offText; }
- this.$off.html(value);
- this::prvwidth();
- this::prvcontainerPosition();
- this.options.offText = value;
- return this.$element;
- }
- labelText(value) {
- if (typeof value === 'undefined') { return this.options.labelText; }
- this.$label.html(value);
- this::prvwidth();
- this.options.labelText = value;
- return this.$element;
- }
- handleWidth(value) {
- if (typeof value === 'undefined') { return this.options.handleWidth; }
- this.options.handleWidth = value;
- this::prvwidth();
- this::prvcontainerPosition();
- return this.$element;
- }
- labelWidth(value) {
- if (typeof value === 'undefined') { return this.options.labelWidth; }
- this.options.labelWidth = value;
- this::prvwidth();
- this::prvcontainerPosition();
- return this.$element;
- }
- baseClass() {
- return this.options.baseClass;
- }
- wrapperClass(value) {
- if (typeof value === 'undefined') { return this.options.wrapperClass; }
- const wrapperClass = value || $.fn.bootstrapSwitch.defaults.wrapperClass;
- this.$wrapper.removeClass(this::prvgetClasses(this.options.wrapperClass).join(' '));
- this.$wrapper.addClass(this::prvgetClasses(wrapperClass).join(' '));
- this.options.wrapperClass = wrapperClass;
- return this.$element;
- }
- radioAllOff(value) {
- if (typeof value === 'undefined') { return this.options.radioAllOff; }
- const val = Boolean(value);
- if (this.options.radioAllOff === val) { return this.$element; }
- this.options.radioAllOff = val;
- return this.$element;
- }
- onInit(value) {
- if (typeof value === 'undefined') { return this.options.onInit; }
- this.options.onInit = value || $.fn.bootstrapSwitch.defaults.onInit;
- return this.$element;
- }
- onSwitchChange(value) {
- if (typeof value === 'undefined') {
- return this.options.onSwitchChange;
- }
- this.options.onSwitchChange =
- value || $.fn.bootstrapSwitch.defaults.onSwitchChange;
- return this.$element;
- }
- destroy() {
- const $form = this.$element.closest('form');
- if ($form.length) {
- $form.off('reset.bootstrapSwitch').removeData('bootstrap-switch');
- }
- this.$container
- .children()
- .not(this.$element)
- .remove();
- this.$element
- .unwrap()
- .unwrap()
- .off('.bootstrapSwitch')
- .removeData('bootstrap-switch');
- return this.$element;
- }
- setHookValue(boolean) {
- if (this.options.valueType === 'on-off') {
- this.options.hookElement.val(boolean ? 'on' : 'off');
- } else if (this.options.valueType === 'text') {
- this.options.hookElement.val(this.options[boolean ? 'onText' : 'offText']);
- } else {
- this.options.hookElement.val(boolean);
- }
- return this.options.hookElement;
- }
- }
- function bootstrapSwitch(option, ...args) {
- function reducer(ret, next) {
- const $this = $(next);
- const existingData = $this.data('bootstrap-switch');
- const data = existingData || new BootstrapSwitch(next, option);
- if (!existingData) {
- $this.data('bootstrap-switch', data);
- }
- if (typeof option === 'string') {
- return data[option](...args);
- }
- return ret;
- }
- return Array.prototype.reduce.call(this, reducer, this);
- }
- $.fn.bootstrapSwitch = bootstrapSwitch;
- $.fn.bootstrapSwitch.Constructor = BootstrapSwitch;
- $.fn.bootstrapSwitch.defaults = {
- state: true,
- size: null,
- animate: true,
- disabled: false,
- readonly: false,
- indeterminate: false,
- inverse: false,
- radioAllOff: false,
- onColor: 'primary',
- offColor: 'default',
- onText: 'ON',
- offText: 'OFF',
- labelText: ' ',
- handleWidth: 'auto',
- labelWidth: 'auto',
- baseClass: 'bootstrap-switch',
- wrapperClass: 'wrapper',
- onInit: () => {},
- onSwitchChange: () => {},
- hookElement: null,
- hookNext: false,
- valueType: 'on-off', // text|on-off|boolean
- };
|