mirror of
https://github.com/flarum/core.git
synced 2025-10-11 06:54:26 +02:00
Massive JavaScript cleanup
- Use JSX for templates - Docblock/comment everything - Mostly passes ESLint (still some work to do) - Lots of renaming, refactoring, etc. CSS hasn't been updated yet.
This commit is contained in:
@@ -1,41 +1,68 @@
|
||||
/**
|
||||
* The `slidable` utility adds touch gestures to an element so that it can be
|
||||
* slid away to reveal controls underneath, and then released to activate those
|
||||
* controls.
|
||||
*
|
||||
* It relies on the element having children with particular CSS classes.
|
||||
* TODO: document
|
||||
*
|
||||
* @param {DOMElement} element
|
||||
* @return {Object}
|
||||
* @property {function} reset Revert the slider to its original position. This
|
||||
* should be called, for example, when a controls dropdown is closed.
|
||||
*/
|
||||
export default function slidable(element) {
|
||||
var $slidable = $(element);
|
||||
const $element = $(element);
|
||||
const threshold = 50;
|
||||
|
||||
var startX;
|
||||
var startY;
|
||||
var couldBeSliding = false;
|
||||
var isSliding = false;
|
||||
var threshold = 50;
|
||||
var pos = 0;
|
||||
let $underneathLeft;
|
||||
let $underneathRight;
|
||||
|
||||
var underneathLeft;
|
||||
var underneathRight;
|
||||
let startX;
|
||||
let startY;
|
||||
let couldBeSliding = false;
|
||||
let isSliding = false;
|
||||
let pos = 0;
|
||||
|
||||
var animatePos = function(pos, options) {
|
||||
options = options || {};
|
||||
/**
|
||||
* Animate the slider to a new position.
|
||||
*
|
||||
* @param {Integer} newPos
|
||||
* @param {Object} [options]
|
||||
*/
|
||||
const animatePos = (newPos, options = {}) => {
|
||||
// Since we can't animate the transform property with jQuery, we'll use a
|
||||
// bit of a workaround. We set up the animation with a step function that
|
||||
// will set the transform property, but then we animate an unused property
|
||||
// (background-position-x) with jQuery.
|
||||
options.duration = options.duration || 'fast';
|
||||
options.step = function(pos) {
|
||||
$(this).css('transform', 'translate('+pos+'px, 0)');
|
||||
options.step = function(x) {
|
||||
$(this).css('transform', 'translate(' + x + 'px, 0)');
|
||||
};
|
||||
|
||||
$slidable.find('.slidable-slider').animate({'background-position-x': pos}, options);
|
||||
$element.find('.slidable-slider').animate({'background-position-x': newPos}, options);
|
||||
};
|
||||
|
||||
var reset = function() {
|
||||
/**
|
||||
* Revert the slider to its original position.
|
||||
*/
|
||||
const reset = () => {
|
||||
animatePos(0, {
|
||||
complete: function() {
|
||||
$slidable.removeClass('sliding');
|
||||
underneathLeft.hide();
|
||||
underneathRight.hide();
|
||||
$element.removeClass('sliding');
|
||||
$underneathLeft.hide();
|
||||
$underneathRight.hide();
|
||||
isSliding = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$slidable.find('.slidable-slider')
|
||||
$element.find('.slidable-slider')
|
||||
.on('touchstart', function(e) {
|
||||
underneathLeft = $slidable.find('.slidable-underneath-left:not(.disabled)');
|
||||
underneathRight = $slidable.find('.slidable-underneath-right:not(.disabled)');
|
||||
// Update the references to the elements underneath the slider, provided
|
||||
// they're not disabled.
|
||||
$underneathLeft = $element.find('.slidable-underneath-left:not(.disabled)');
|
||||
$underneathRight = $element.find('.slidable-underneath-right:not(.disabled)');
|
||||
|
||||
startX = e.originalEvent.targetTouches[0].clientX;
|
||||
startY = e.originalEvent.targetTouches[0].clientY;
|
||||
@@ -44,9 +71,13 @@ export default function slidable(element) {
|
||||
})
|
||||
|
||||
.on('touchmove', function(e) {
|
||||
var newX = e.originalEvent.targetTouches[0].clientX;
|
||||
var newY = e.originalEvent.targetTouches[0].clientY;
|
||||
const newX = e.originalEvent.targetTouches[0].clientX;
|
||||
const newY = e.originalEvent.targetTouches[0].clientY;
|
||||
|
||||
// Once the user moves their touch in a direction that's more up/down than
|
||||
// left/right, we'll assume they're scrolling the page. But if they do
|
||||
// move in a horizontal direction at first, then we'll lock their touch
|
||||
// into the slider.
|
||||
if (couldBeSliding && Math.abs(newX - startX) > Math.abs(newY - startY)) {
|
||||
isSliding = true;
|
||||
}
|
||||
@@ -55,45 +86,59 @@ export default function slidable(element) {
|
||||
if (isSliding) {
|
||||
pos = newX - startX;
|
||||
|
||||
if (underneathLeft.length) {
|
||||
if (pos > 0 && underneathLeft.hasClass('elastic')) {
|
||||
pos -= pos * 0.5;
|
||||
// If there are controls underneath the either side, then we'll show/hide
|
||||
// them depending on the slider's position. We also make the controls
|
||||
// icon get a bit bigger the further they slide.
|
||||
const toggle = ($underneath, active) => {
|
||||
if ($underneath.length) {
|
||||
if (active && $underneath.hasClass('elastic')) {
|
||||
pos -= pos * 0.5;
|
||||
}
|
||||
$underneath.toggle(active);
|
||||
|
||||
const scale = Math.max(0, Math.min(1, (Math.abs(pos) - 25) / threshold));
|
||||
$underneath.find('.icon').css('transform', 'scale(' + scale + ')');
|
||||
} else {
|
||||
pos = Math.min(0, pos);
|
||||
}
|
||||
underneathLeft.toggle(pos > 0);
|
||||
underneathLeft.find('.icon').css('transform', 'scale('+Math.max(0, Math.min(1, (Math.abs(pos) - 25) / threshold))+')');
|
||||
} else {
|
||||
pos = Math.min(0, pos);
|
||||
}
|
||||
};
|
||||
|
||||
if (underneathRight.length) {
|
||||
if (pos < 0 && underneathRight.hasClass('elastic')) {
|
||||
pos -= pos * 0.5;
|
||||
}
|
||||
underneathRight.toggle(pos < 0);
|
||||
underneathRight.find('.icon').css('transform', 'scale('+Math.max(0, Math.min(1, (Math.abs(pos) - 25) / threshold))+')');
|
||||
} else {
|
||||
pos = Math.max(0, pos);
|
||||
}
|
||||
toggle($underneathLeft, pos > 0);
|
||||
toggle($underneathRight, pos < 0);
|
||||
|
||||
$(this).css('transform', 'translate('+pos+'px, 0)');
|
||||
$(this).css('background-position-x', pos+'px');
|
||||
$(this).css('transform', 'translate(' + pos + 'px, 0)');
|
||||
$(this).css('background-position-x', pos + 'px');
|
||||
|
||||
$slidable.toggleClass('sliding', !!pos);
|
||||
$element.toggleClass('sliding', !!pos);
|
||||
|
||||
e.preventDefault();
|
||||
}
|
||||
})
|
||||
|
||||
.on('touchend', function(e) {
|
||||
if (underneathRight.length && pos < -threshold) {
|
||||
underneathRight.click();
|
||||
underneathRight.hasClass('elastic') ? reset() : animatePos(-$slidable.width());
|
||||
} else if (underneathLeft.length && pos > threshold) {
|
||||
underneathLeft.click();
|
||||
underneathLeft.hasClass('elastic') ? reset() : animatePos(-$slidable.width());
|
||||
.on('touchend', function() {
|
||||
// If the user releases the touch and the slider is past the threshold
|
||||
// position on either side, then we will activate the control for that
|
||||
// side. We will also animate the slider's position all the way to the
|
||||
// other side, or back to its original position, depending on whether or
|
||||
// not the side is 'elastic'.
|
||||
const activate = $underneath => {
|
||||
$underneath.click();
|
||||
|
||||
if ($underneath.hasClass('elastic')) {
|
||||
reset();
|
||||
} else {
|
||||
animatePos((pos > 0 ? 1 : -1) * $element.width());
|
||||
}
|
||||
};
|
||||
|
||||
if ($underneathRight.length && pos < -threshold) {
|
||||
activate($underneathRight);
|
||||
} else if ($underneathLeft.length && pos > threshold) {
|
||||
activate($underneathLeft);
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
|
||||
couldBeSliding = false;
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user