FEATURE: add swipe detection for dismissing mobile topic scroller

This commit is contained in:
Jeff Wong 2018-06-22 15:54:55 -07:00
parent c33ee13c4c
commit 8bdb62ca01
2 changed files with 146 additions and 2 deletions

View File

@ -1,9 +1,11 @@
import { observes } from "ember-addons/ember-computed-decorators";
import showModal from "discourse/lib/show-modal";
import PanEvents from "discourse/mixins/pan-events";
export default Ember.Component.extend({
export default Ember.Component.extend(PanEvents, {
composerOpen: null,
info: null,
isPanning: false,
init() {
this._super();
@ -91,7 +93,7 @@ export default Ember.Component.extend({
_collapseFullscreen() {
if (this.get("info.topicProgressExpanded")) {
$(".timeline-fullscreen").removeClass("show");
setTimeout(() => {
Ember.run.later(() => {
this.set("info.topicProgressExpanded", false);
this._checkSize();
}, 500);
@ -109,6 +111,59 @@ export default Ember.Component.extend({
}
},
_panOpenClose(offset, velocity, direction) {
const $timelineContainer = $(".timeline-container");
const maxOffset = parseInt($timelineContainer.css("height"));
direction === "close" ? offset += velocity : offset -= velocity;
$timelineContainer.css("bottom", -offset);
if(offset > maxOffset) {
this._collapseFullscreen();
}
else if(offset <= 0) {
$timelineContainer.css("bottom", "");
}
else {
Ember.run.later(() => this._panOpenClose(offset, velocity, direction), 20);
}
},
_shouldPanClose(e) {
return (e.deltaY > 200 && e.velocityY > -0.15) || e.velocityY > 0.15;
},
panStart(e) {
const center = e.center;
const $centeredElement = $(document.elementFromPoint(center.x, center.y));
if ($centeredElement.parents(".timeline-scrollarea-wrapper").length) {
this.set("isPanning", false);
}
else {
this.set("isPanning", true);
}
},
panEnd(e) {
if(!this.get("isPanning")) {
return;
}
this.set("isPanning", false);
if(this._shouldPanClose(e)) {
this._panOpenClose(e.deltaY, 40, "close");
}
else {
this._panOpenClose(e.deltaY, 40, "open");
}
},
panMove(e) {
if(!this.get("isPanning")) {
return;
}
$(".timeline-container").css("bottom", Math.min(0, -e.deltaY));
},
didInsertElement() {
this._super();

View File

@ -0,0 +1,89 @@
import {
on,
default as computed
} from "ember-addons/ember-computed-decorators";
export default Ember.Mixin.create({
//velocity is pixels per ms
_panState: null,
didInsertElement() {
this.$().on("pointerdown", (e) => this._panStart(e))
.on("pointermove", (e) => this._panMove(e))
.on("pointerup", (e) => this._panMove(e))
.on("pointercancel", (e) => this._panMove(e));
},
willDestroyElement() {
this.$().off("pointerdown")
.off("pointerup")
.off("pointermove")
.off("pointercancel");
},
_calculateNewPanState(oldState, e) {
if(e.type == "pointerup" || e.type == "pointercancel") {
return oldState;
}
const newTimestamp = new Date().getTime();
const timeDiffSeconds = (newTimestamp - oldState.timestamp);
//calculate delta x, y, distance from START location
const deltaX = Math.round(e.clientX) - oldState.startLocation.x;
const deltaY = Math.round(e.clientY) - oldState.startLocation.y;
const distance = Math.round(Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)));
//calculate velocity from previous event center location
const eventDeltaX = e.clientX - oldState.center.x;
const eventDeltaY = e.clientY - oldState.center.y;
const velocityX = eventDeltaX / timeDiffSeconds;
const velocityY = eventDeltaY / timeDiffSeconds;
const deltaDistance = Math.sqrt(Math.pow(eventDeltaX, 2) + Math.pow(eventDeltaY, 2));
const velocity = deltaDistance / timeDiffSeconds;
return {
startLocation: oldState.startLocation,
center: {x: Math.round(e.clientX), y: Math.round(e.clientY)},
velocity,
velocityX,
velocityY,
deltaX,
deltaY,
distance,
start: false,
timestamp: newTimestamp
};
},
_panStart(e) {
const newState = {
center: {x: Math.round(e.clientX), y: Math.round(e.clientY)},
startLocation: {x: Math.round(e.clientX), y: Math.round(e.clientY)},
velocity: 0,
velocityX: 0,
velocityY: 0,
deltaX: 0,
deltaY: 0,
distance: 0,
start: true,
timestamp: new Date().getTime()
};
this.set("_panState", newState);
},
_panMove(e) {
const previousState = this.get("_panState");
const newState = this._calculateNewPanState(previousState, e);
this.set("_panState", newState);
if(previousState.start && "panStart" in this) {
this.panStart(newState);
}
else if((e.type == "pointerup" || e.type == "pointercancel") && "panEnd" in this) {
this.panEnd(newState);
}
else if(e.type == "pointermove" && "panMove" in this) {
this.panMove(newState);
}
},
});