framework7
Version:
Full featured mobile HTML framework for building iOS & Android apps
663 lines (544 loc) • 20.9 kB
JavaScript
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
import $ from '../../shared/dom7';
import { extend, nextTick, deleteProps } from '../../shared/utils';
import Framework7Class from '../../shared/class';
import { getSupport } from '../../shared/get-support';
var Range = /*#__PURE__*/function (_Framework7Class) {
_inheritsLoose(Range, _Framework7Class);
function Range(app, params) {
var _this;
_this = _Framework7Class.call(this, params, [app]) || this;
var range = _assertThisInitialized(_this);
var support = getSupport();
var defaults = {
el: null,
inputEl: null,
dual: false,
step: 1,
label: false,
min: 0,
max: 100,
value: 0,
draggableBar: true,
vertical: false,
verticalReversed: false,
formatLabel: null,
scale: false,
scaleSteps: 5,
scaleSubSteps: 0,
formatScaleLabel: null,
limitKnobPosition: app.theme === 'ios'
}; // Extend defaults with modules params
range.useModulesParams(defaults);
range.params = extend(defaults, params);
var el = range.params.el;
if (!el) return range || _assertThisInitialized(_this);
var $el = $(el);
if ($el.length === 0) return range || _assertThisInitialized(_this);
if ($el[0].f7Range) return $el[0].f7Range || _assertThisInitialized(_this);
var dataset = $el.dataset();
'step min max value scaleSteps scaleSubSteps'.split(' ').forEach(function (paramName) {
if (typeof params[paramName] === 'undefined' && typeof dataset[paramName] !== 'undefined') {
range.params[paramName] = parseFloat(dataset[paramName]);
}
});
'dual label vertical verticalReversed scale'.split(' ').forEach(function (paramName) {
if (typeof params[paramName] === 'undefined' && typeof dataset[paramName] !== 'undefined') {
range.params[paramName] = dataset[paramName];
}
});
if (!range.params.value) {
if (typeof dataset.value !== 'undefined') range.params.value = dataset.value;
if (typeof dataset.valueLeft !== 'undefined' && typeof dataset.valueRight !== 'undefined') {
range.params.value = [parseFloat(dataset.valueLeft), parseFloat(dataset.valueRight)];
}
}
var $inputEl;
if (!range.params.dual) {
if (range.params.inputEl) {
$inputEl = $(range.params.inputEl);
} else if ($el.find('input[type="range"]').length) {
$inputEl = $el.find('input[type="range"]').eq(0);
}
}
var _range$params = range.params,
dual = _range$params.dual,
step = _range$params.step,
label = _range$params.label,
min = _range$params.min,
max = _range$params.max,
value = _range$params.value,
vertical = _range$params.vertical,
verticalReversed = _range$params.verticalReversed,
scale = _range$params.scale,
scaleSteps = _range$params.scaleSteps,
scaleSubSteps = _range$params.scaleSubSteps,
limitKnobPosition = _range$params.limitKnobPosition;
extend(range, {
app: app,
$el: $el,
el: $el[0],
$inputEl: $inputEl,
inputEl: $inputEl ? $inputEl[0] : undefined,
dual: dual,
step: step,
label: label,
min: min,
max: max,
value: value,
previousValue: value,
vertical: vertical,
verticalReversed: verticalReversed,
scale: scale,
scaleSteps: scaleSteps,
scaleSubSteps: scaleSubSteps,
limitKnobPosition: limitKnobPosition
});
if ($inputEl) {
'step min max'.split(' ').forEach(function (paramName) {
if (!params[paramName] && $inputEl.attr(paramName)) {
range.params[paramName] = parseFloat($inputEl.attr(paramName));
range[paramName] = parseFloat($inputEl.attr(paramName));
}
});
if (typeof $inputEl.val() !== 'undefined') {
range.params.value = parseFloat($inputEl.val());
range.value = parseFloat($inputEl.val());
}
} // Dual
if (range.dual) {
$el.addClass('range-slider-dual');
}
if (range.label) {
$el.addClass('range-slider-label');
} // Vertical
if (range.vertical) {
$el.addClass('range-slider-vertical');
if (range.verticalReversed) {
$el.addClass('range-slider-vertical-reversed');
}
} else {
$el.addClass('range-slider-horizontal');
} // Check for layout
var $barEl = $('<div class="range-bar"></div>');
var $barActiveEl = $('<div class="range-bar-active"></div>');
$barEl.append($barActiveEl); // Create Knobs
// prettier-ignore
var knobHTML = "\n <div class=\"range-knob-wrap\">\n <div class=\"range-knob\"></div>\n " + (range.label ? '<div class="range-knob-label"></div>' : '') + "\n </div>\n ";
var knobs = [$(knobHTML)];
if (range.dual) {
knobs.push($(knobHTML));
}
$el.append($barEl);
knobs.forEach(function ($knobEl) {
$el.append($knobEl);
}); // Labels
var labels = [];
if (range.label) {
labels.push(knobs[0].find('.range-knob-label'));
if (range.dual) {
labels.push(knobs[1].find('.range-knob-label'));
}
} // Scale
var $scaleEl;
if (range.scale && range.scaleSteps >= 1) {
$scaleEl = $("\n <div class=\"range-scale\">\n " + range.renderScale() + "\n </div>\n ");
$el.append($scaleEl);
}
extend(range, {
knobs: knobs,
labels: labels,
$barEl: $barEl,
$barActiveEl: $barActiveEl,
$scaleEl: $scaleEl
});
$el[0].f7Range = range; // Touch Events
var isTouched;
var touchesStart = {};
var isScrolling;
var rangeOffset;
var rangeOffsetLeft;
var rangeOffsetTop;
var $touchedKnobEl;
var dualValueIndex;
var valueChangedByTouch;
var targetTouchIdentifier;
function onTouchChange() {
valueChangedByTouch = true;
}
function handleTouchStart(e) {
if (isTouched) return;
if (!range.params.draggableBar) {
if ($(e.target).closest('.range-knob').length === 0) {
return;
}
}
valueChangedByTouch = false;
touchesStart.x = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
touchesStart.y = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
if (e.type === 'touchstart') {
targetTouchIdentifier = e.targetTouches[0].identifier;
}
isTouched = true;
isScrolling = undefined;
rangeOffset = $el.offset();
rangeOffsetLeft = rangeOffset.left;
rangeOffsetTop = rangeOffset.top;
var progress;
if (range.vertical) {
progress = (touchesStart.y - rangeOffsetTop) / range.rangeHeight;
if (!range.verticalReversed) progress = 1 - progress;
} else if (range.app.rtl) {
progress = (rangeOffsetLeft + range.rangeWidth - touchesStart.x) / range.rangeWidth;
} else {
progress = (touchesStart.x - rangeOffsetLeft) / range.rangeWidth;
}
var newValue = progress * (range.max - range.min) + range.min;
if (range.dual) {
if (Math.abs(range.value[0] - newValue) < Math.abs(range.value[1] - newValue)) {
dualValueIndex = 0;
$touchedKnobEl = range.knobs[0];
newValue = [newValue, range.value[1]];
} else {
dualValueIndex = 1;
$touchedKnobEl = range.knobs[1];
newValue = [range.value[0], newValue];
}
} else {
$touchedKnobEl = range.knobs[0];
newValue = progress * (range.max - range.min) + range.min;
}
nextTick(function () {
if (isTouched) $touchedKnobEl.addClass('range-knob-active-state');
}, 70);
range.on('change', onTouchChange);
range.setValue(newValue, true);
}
function handleTouchMove(e) {
if (!isTouched) return;
var pageX;
var pageY;
if (e.type === 'touchmove') {
for (var i = 0; i < e.targetTouches.length; i += 1) {
if (e.targetTouches[i].identifier === targetTouchIdentifier) {
pageX = e.targetTouches[i].pageX;
pageY = e.targetTouches[i].pageY;
}
}
} else {
pageX = e.pageX;
pageY = e.pageY;
}
if (typeof pageX === 'undefined' && typeof pageY === 'undefined') return;
if (typeof isScrolling === 'undefined' && !range.vertical) {
isScrolling = !!(isScrolling || Math.abs(pageY - touchesStart.y) > Math.abs(pageX - touchesStart.x));
}
if (isScrolling) {
isTouched = false;
return;
}
e.preventDefault();
var progress;
if (range.vertical) {
progress = (pageY - rangeOffsetTop) / range.rangeHeight;
if (!range.verticalReversed) progress = 1 - progress;
} else if (range.app.rtl) {
progress = (rangeOffsetLeft + range.rangeWidth - pageX) / range.rangeWidth;
} else {
progress = (pageX - rangeOffsetLeft) / range.rangeWidth;
}
var newValue = progress * (range.max - range.min) + range.min;
if (range.dual) {
var leftValue;
var rightValue;
if (dualValueIndex === 0) {
leftValue = newValue;
rightValue = range.value[1];
if (leftValue > rightValue) {
rightValue = leftValue;
}
} else {
leftValue = range.value[0];
rightValue = newValue;
if (rightValue < leftValue) {
leftValue = rightValue;
}
}
newValue = [leftValue, rightValue];
}
range.setValue(newValue, true);
}
function handleTouchEnd(e) {
if (e.type === 'touchend') {
var touchEnded;
for (var i = 0; i < e.changedTouches.length; i += 1) {
if (e.changedTouches[i].identifier === targetTouchIdentifier) touchEnded = true;
}
if (!touchEnded) return;
}
if (!isTouched) {
if (isScrolling) $touchedKnobEl.removeClass('range-knob-active-state');
isTouched = false;
return;
}
range.off('change', onTouchChange);
isTouched = false;
$touchedKnobEl.removeClass('range-knob-active-state');
if (valueChangedByTouch && range.$inputEl && !range.dual) {
range.$inputEl.trigger('change');
}
valueChangedByTouch = false;
if (typeof range.previousValue !== 'undefined') {
if (range.dual && (range.previousValue[0] !== range.value[0] || range.previousValue[1] !== range.value[1]) || !range.dual && range.previousValue !== range.value) {
range.$el.trigger('range:changed', range.value);
range.emit('local::changed rangeChanged', range, range.value);
}
}
}
function handleResize() {
range.calcSize();
range.layout();
}
var parentModals;
var parentPanel;
var parentPage;
range.attachEvents = function attachEvents() {
var passive = support.passiveListener ? {
passive: true
} : false;
range.$el.on(app.touchEvents.start, handleTouchStart, passive);
app.on('touchmove', handleTouchMove);
app.on('touchend:passive', handleTouchEnd);
app.on('tabShow', handleResize);
app.on('resize', handleResize);
parentModals = range.$el.parents('.sheet-modal, .actions-modal, .popup, .popover, .login-screen, .dialog, .toast');
parentModals.on('modal:open', handleResize);
parentPanel = range.$el.parents('.panel');
parentPanel.on('panel:open panel:resize', handleResize);
parentPage = range.$el.parents('.page').eq(0);
parentPage.on('page:reinit', handleResize);
};
range.detachEvents = function detachEvents() {
var passive = support.passiveListener ? {
passive: true
} : false;
range.$el.off(app.touchEvents.start, handleTouchStart, passive);
app.off('touchmove', handleTouchMove);
app.off('touchend:passive', handleTouchEnd);
app.off('tabShow', handleResize);
app.off('resize', handleResize);
if (parentModals) {
parentModals.off('modal:open', handleResize);
}
if (parentPanel) {
parentPanel.off('panel:open panel:resize', handleResize);
}
if (parentPage) {
parentPage.off('page:reinit', handleResize);
}
parentModals = null;
parentPanel = null;
parentPage = null;
}; // Install Modules
range.useModules(); // Init
range.init();
return range || _assertThisInitialized(_this);
}
var _proto = Range.prototype;
_proto.calcSize = function calcSize() {
var range = this;
if (range.vertical) {
var height = range.$el.outerHeight();
if (height === 0) return;
range.rangeHeight = height;
range.knobHeight = range.knobs[0].outerHeight();
} else {
var width = range.$el.outerWidth();
if (width === 0) return;
range.rangeWidth = width;
range.knobWidth = range.knobs[0].outerWidth();
}
};
_proto.layout = function layout() {
var range = this;
var app = range.app,
knobWidth = range.knobWidth,
knobHeight = range.knobHeight,
rangeWidth = range.rangeWidth,
rangeHeight = range.rangeHeight,
min = range.min,
max = range.max,
knobs = range.knobs,
$barActiveEl = range.$barActiveEl,
value = range.value,
label = range.label,
labels = range.labels,
vertical = range.vertical,
verticalReversed = range.verticalReversed,
limitKnobPosition = range.limitKnobPosition;
var knobSize = vertical ? knobHeight : knobWidth;
var rangeSize = vertical ? rangeHeight : rangeWidth; // eslint-disable-next-line
var positionProperty = vertical ? verticalReversed ? 'top' : 'bottom' : app.rtl ? 'right' : 'left';
if (range.dual) {
var _$barActiveEl$css;
var progress = [(value[0] - min) / (max - min), (value[1] - min) / (max - min)];
$barActiveEl.css((_$barActiveEl$css = {}, _$barActiveEl$css[positionProperty] = progress[0] * 100 + "%", _$barActiveEl$css[vertical ? 'height' : 'width'] = (progress[1] - progress[0]) * 100 + "%", _$barActiveEl$css));
knobs.forEach(function ($knobEl, knobIndex) {
var startPos = rangeSize * progress[knobIndex];
if (limitKnobPosition) {
var realStartPos = rangeSize * progress[knobIndex] - knobSize / 2;
if (realStartPos < 0) startPos = knobSize / 2;
if (realStartPos + knobSize > rangeSize) startPos = rangeSize - knobSize / 2;
}
$knobEl.css(positionProperty, startPos + "px");
if (label) labels[knobIndex].text(range.formatLabel(value[knobIndex], labels[knobIndex][0]));
});
} else {
var _progress = (value - min) / (max - min);
$barActiveEl.css(vertical ? 'height' : 'width', _progress * 100 + "%");
var startPos = rangeSize * _progress;
if (limitKnobPosition) {
var realStartPos = rangeSize * _progress - knobSize / 2;
if (realStartPos < 0) startPos = knobSize / 2;
if (realStartPos + knobSize > rangeSize) startPos = rangeSize - knobSize / 2;
}
knobs[0].css(positionProperty, startPos + "px");
if (label) labels[0].text(range.formatLabel(value, labels[0][0]));
}
if (range.dual && value.indexOf(min) >= 0 || !range.dual && value === min) {
range.$el.addClass('range-slider-min');
} else {
range.$el.removeClass('range-slider-min');
}
if (range.dual && value.indexOf(max) >= 0 || !range.dual && value === max) {
range.$el.addClass('range-slider-max');
} else {
range.$el.removeClass('range-slider-max');
}
};
_proto.setValue = function setValue(newValue, byTouchMove) {
var range = this;
var step = range.step,
min = range.min,
max = range.max;
var valueChanged;
var oldValue;
if (range.dual) {
oldValue = [range.value[0], range.value[1]];
var newValues = newValue;
if (!Array.isArray(newValues)) newValues = [newValue, newValue];
if (newValue[0] > newValue[1]) {
newValues = [newValues[0], newValues[0]];
}
newValues = newValues.map(function (value) {
return Math.max(Math.min(Math.round(value / step) * step, max), min);
});
if (newValues[0] === range.value[0] && newValues[1] === range.value[1]) {
return range;
}
newValues.forEach(function (value, valueIndex) {
range.value[valueIndex] = value;
});
valueChanged = oldValue[0] !== newValues[0] || oldValue[1] !== newValues[1];
range.layout();
} else {
oldValue = range.value;
var value = Math.max(Math.min(Math.round(newValue / step) * step, max), min);
range.value = value;
range.layout();
valueChanged = oldValue !== value;
}
if (valueChanged) {
range.previousValue = oldValue;
} // Events
if (!valueChanged) return range;
range.$el.trigger('range:change', range.value);
if (range.$inputEl && !range.dual) {
range.$inputEl.val(range.value);
if (!byTouchMove) {
range.$inputEl.trigger('input change');
} else {
range.$inputEl.trigger('input');
}
}
if (!byTouchMove) {
range.$el.trigger('range:changed', range.value);
range.emit('local::changed rangeChanged', range, range.value);
}
range.emit('local::change rangeChange', range, range.value);
return range;
};
_proto.getValue = function getValue() {
return this.value;
};
_proto.formatLabel = function formatLabel(value, labelEl) {
var range = this;
if (range.params.formatLabel) return range.params.formatLabel.call(range, value, labelEl);
return value;
};
_proto.formatScaleLabel = function formatScaleLabel(value) {
var range = this;
if (range.params.formatScaleLabel) return range.params.formatScaleLabel.call(range, value);
return value;
};
_proto.renderScale = function renderScale() {
var range = this;
var app = range.app,
verticalReversed = range.verticalReversed,
vertical = range.vertical; // eslint-disable-next-line
var positionProperty = vertical ? verticalReversed ? 'top' : 'bottom' : app.rtl ? 'right' : 'left';
var html = '';
Array.from({
length: range.scaleSteps + 1
}).forEach(function (scaleEl, index) {
var scaleStepValue = (range.max - range.min) / range.scaleSteps;
var scaleValue = range.min + scaleStepValue * index;
var progress = (scaleValue - range.min) / (range.max - range.min);
html += "<div class=\"range-scale-step\" style=\"" + positionProperty + ": " + progress * 100 + "%\">" + range.formatScaleLabel(scaleValue) + "</div>";
if (range.scaleSubSteps && range.scaleSubSteps > 1 && index < range.scaleSteps) {
Array.from({
length: range.scaleSubSteps - 1
}).forEach(function (subStepEl, subIndex) {
var subStep = scaleStepValue / range.scaleSubSteps;
var scaleSubValue = scaleValue + subStep * (subIndex + 1);
var subProgress = (scaleSubValue - range.min) / (range.max - range.min);
html += "<div class=\"range-scale-step range-scale-substep\" style=\"" + positionProperty + ": " + subProgress * 100 + "%\"></div>";
});
}
});
return html;
};
_proto.updateScale = function updateScale() {
var range = this;
if (!range.scale || range.scaleSteps < 1) {
if (range.$scaleEl) range.$scaleEl.remove();
delete range.$scaleEl;
return;
}
if (!range.$scaleEl) {
range.$scaleEl = $('<div class="range-scale"></div>');
range.$el.append(range.$scaleEl);
}
range.$scaleEl.html(range.renderScale());
};
_proto.init = function init() {
var range = this;
range.calcSize();
range.layout();
range.attachEvents();
return range;
};
_proto.destroy = function destroy() {
var range = this;
range.$el.trigger('range:beforedestroy');
range.emit('local::beforeDestroy rangeBeforeDestroy', range);
delete range.$el[0].f7Range;
range.detachEvents();
deleteProps(range);
range = null;
};
return Range;
}(Framework7Class);
export default Range;