@pi0/framework7
Version:
Full featured mobile HTML framework for building iOS & Android apps
183 lines (158 loc) • 5.34 kB
JavaScript
import $ from 'dom7';
import Utils from '../../utils/utils';
import Framework7Class from '../../utils/class';
import Support from '../../utils/support';
class Toggle extends Framework7Class {
constructor(app, params = {}) {
super(params, [app]);
const toggle = this;
const defaults = {};
// Extend defaults with modules params
toggle.useModulesParams(defaults);
toggle.params = Utils.extend(defaults, params);
const el = toggle.params.el;
if (!el) return toggle;
const $el = $(el);
if ($el.length === 0) return toggle;
const $inputEl = $el.children('input[type="checkbox"]');
Utils.extend(toggle, {
$el,
el: $el[0],
$inputEl,
inputEl: $inputEl[0],
disabled: $el.hasClass('disabled') || $inputEl.hasClass('disabled') || $inputEl.attr('disabled') || $inputEl[0].disabled,
});
Object.defineProperty(toggle, 'checked', {
enumerable: true,
configurable: true,
set(checked) {
if (!toggle || typeof toggle.$inputEl === 'undefined') return;
if (toggle.checked === checked) return;
$inputEl[0].checked = checked;
toggle.$inputEl.trigger('change');
},
get() {
return $inputEl[0].checked;
},
});
$el[0].f7Toggle = toggle;
let isTouched;
const touchesStart = {};
let isScrolling;
let touchesDiff;
let toggleWidth;
let touchStartTime;
let touchStartChecked;
function handleTouchStart(e) {
if (isTouched || toggle.disabled) return;
touchesStart.x = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
touchesStart.y = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
touchesDiff = 0;
isTouched = true;
isScrolling = undefined;
touchStartTime = Utils.now();
touchStartChecked = toggle.checked;
toggleWidth = $el[0].offsetWidth;
Utils.nextTick(() => {
if (isTouched) {
$el.addClass('toggle-active-state');
}
});
}
function handleTouchMove(e) {
if (!isTouched || toggle.disabled) return;
const pageX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
const pageY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
const inverter = app.rtl ? -1 : 1;
if (typeof isScrolling === 'undefined') {
isScrolling = !!(isScrolling || Math.abs(pageY - touchesStart.y) > Math.abs(pageX - touchesStart.x));
}
if (isScrolling) {
isTouched = false;
return;
}
e.preventDefault();
touchesDiff = pageX - touchesStart.x;
let changed;
if (touchesDiff * inverter < 0 && Math.abs(touchesDiff) > toggleWidth / 3 && touchStartChecked) {
changed = true;
}
if (touchesDiff * inverter > 0 && Math.abs(touchesDiff) > toggleWidth / 3 && !touchStartChecked) {
changed = true;
}
if (changed) {
touchesStart.x = pageX;
toggle.checked = !touchStartChecked;
touchStartChecked = !touchStartChecked;
}
}
function handleTouchEnd() {
if (!isTouched || toggle.disabled) {
if (isScrolling) $el.removeClass('toggle-active-state');
isTouched = false;
return;
}
const inverter = app.rtl ? -1 : 1;
isTouched = false;
$el.removeClass('toggle-active-state');
let changed;
if ((Utils.now() - touchStartTime) < 300) {
if (touchesDiff * inverter < 0 && touchStartChecked) {
changed = true;
}
if (touchesDiff * inverter > 0 && !touchStartChecked) {
changed = true;
}
if (changed) {
toggle.checked = !touchStartChecked;
}
}
}
function handleInputChange() {
toggle.$el.trigger('toggle:change', toggle);
toggle.emit('local::change toggleChange', toggle);
}
toggle.attachEvents = function attachEvents() {
if (process.env.TARGET !== 'desktop') {
if (!Support.touch) return;
const passive = Support.passiveListener ? { passive: true } : false;
$el.on(app.touchEvents.start, handleTouchStart, passive);
app.on('touchmove', handleTouchMove);
app.on('touchend:passive', handleTouchEnd);
}
toggle.$inputEl.on('change', handleInputChange);
};
toggle.detachEvents = function detachEvents() {
if (process.env.TARGET !== 'desktop') {
if (!Support.touch) return;
const passive = Support.passiveListener ? { passive: true } : false;
$el.off(app.touchEvents.start, handleTouchStart, passive);
app.off('touchmove', handleTouchMove);
app.off('touchend:passive', handleTouchEnd);
}
toggle.$inputEl.off('change', handleInputChange);
};
// Install Modules
toggle.useModules();
// Init
toggle.init();
}
toggle() {
const toggle = this;
toggle.checked = !toggle.checked;
}
init() {
const toggle = this;
toggle.attachEvents();
}
destroy() {
let toggle = this;
toggle.$el.trigger('toggle:beforedestroy', toggle);
toggle.emit('local::beforeDestroy toggleBeforeDestroy', toggle);
delete toggle.$el[0].f7Toggle;
toggle.detachEvents();
Utils.deleteProps(toggle);
toggle = null;
}
}
export default Toggle;