FEATURE: add swipe detection for dismissing mobile topic scroller
This commit is contained in:
parent
c33ee13c4c
commit
8bdb62ca01
|
@ -1,9 +1,11 @@
|
||||||
import { observes } from "ember-addons/ember-computed-decorators";
|
import { observes } from "ember-addons/ember-computed-decorators";
|
||||||
import showModal from "discourse/lib/show-modal";
|
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,
|
composerOpen: null,
|
||||||
info: null,
|
info: null,
|
||||||
|
isPanning: false,
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super();
|
this._super();
|
||||||
|
@ -91,7 +93,7 @@ export default Ember.Component.extend({
|
||||||
_collapseFullscreen() {
|
_collapseFullscreen() {
|
||||||
if (this.get("info.topicProgressExpanded")) {
|
if (this.get("info.topicProgressExpanded")) {
|
||||||
$(".timeline-fullscreen").removeClass("show");
|
$(".timeline-fullscreen").removeClass("show");
|
||||||
setTimeout(() => {
|
Ember.run.later(() => {
|
||||||
this.set("info.topicProgressExpanded", false);
|
this.set("info.topicProgressExpanded", false);
|
||||||
this._checkSize();
|
this._checkSize();
|
||||||
}, 500);
|
}, 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() {
|
didInsertElement() {
|
||||||
this._super();
|
this._super();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
Loading…
Reference in New Issue