UX: Docking back button on topic timeline
This commit is contained in:
parent
05e99a68ce
commit
36449aa2f2
|
@ -56,12 +56,12 @@ let _dragging;
|
||||||
const DRAG_NAME = "mousemove.discourse-widget-drag";
|
const DRAG_NAME = "mousemove.discourse-widget-drag";
|
||||||
const DRAG_NAME_TOUCH = "touchmove.discourse-widget-drag";
|
const DRAG_NAME_TOUCH = "touchmove.discourse-widget-drag";
|
||||||
|
|
||||||
function cancelDrag() {
|
function cancelDrag(e) {
|
||||||
$('body').removeClass('widget-dragging');
|
$('body').removeClass('widget-dragging');
|
||||||
$(document).off(DRAG_NAME).off(DRAG_NAME_TOUCH);
|
$(document).off(DRAG_NAME).off(DRAG_NAME_TOUCH);
|
||||||
|
|
||||||
if (_dragging) {
|
if (_dragging) {
|
||||||
if (_dragging.dragEnd) { _dragging.dragEnd(); }
|
if (_dragging.dragEnd) { _dragging.dragEnd(e); }
|
||||||
_dragging = null;
|
_dragging = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ WidgetClickHook.setupDocumentCallback = function() {
|
||||||
if (_watchingDocument) { return; }
|
if (_watchingDocument) { return; }
|
||||||
|
|
||||||
$(document).on('mousedown.discource-widget-drag, touchstart.discourse-widget-drag', e => {
|
$(document).on('mousedown.discource-widget-drag, touchstart.discourse-widget-drag', e => {
|
||||||
cancelDrag();
|
cancelDrag(e);
|
||||||
const widget = findWidget(e.target, DRAG_ATTRIBUTE_NAME);
|
const widget = findWidget(e.target, DRAG_ATTRIBUTE_NAME);
|
||||||
if (widget) {
|
if (widget) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
@ -87,7 +87,7 @@ WidgetClickHook.setupDocumentCallback = function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on('mouseup.discourse-widget-drag, touchend.discourse-widget-drag', () => cancelDrag());
|
$(document).on('mouseup.discourse-widget-drag, touchend.discourse-widget-drag', e => cancelDrag(e));
|
||||||
|
|
||||||
$(document).on('click.discourse-widget', e => {
|
$(document).on('click.discourse-widget', e => {
|
||||||
nodeCallback(e.target, CLICK_ATTRIBUTE_NAME, w => w.click(e));
|
nodeCallback(e.target, CLICK_ATTRIBUTE_NAME, w => w.click(e));
|
||||||
|
|
|
@ -12,6 +12,15 @@ function clamp(p, min=0.0, max=1.0) {
|
||||||
return Math.max(Math.min(p, max), min);
|
return Math.max(Math.min(p, max), min);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function attachBackButton(widget) {
|
||||||
|
return widget.attach('button', {
|
||||||
|
className: 'btn btn-primary btn-small back-button',
|
||||||
|
label: 'topic.timeline.back',
|
||||||
|
title: 'topic.timeline.back_description',
|
||||||
|
action: 'goBack'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
createWidget('timeline-last-read', {
|
createWidget('timeline-last-read', {
|
||||||
tagName: 'div.timeline-last-read',
|
tagName: 'div.timeline-last-read',
|
||||||
|
|
||||||
|
@ -22,20 +31,12 @@ createWidget('timeline-last-read', {
|
||||||
html(attrs) {
|
html(attrs) {
|
||||||
const result = [ iconNode('minus', { class: 'progress' }) ];
|
const result = [ iconNode('minus', { class: 'progress' }) ];
|
||||||
if (attrs.showButton) {
|
if (attrs.showButton) {
|
||||||
result.push(this.attach('button', {
|
result.push(attachBackButton(this));
|
||||||
className: 'btn btn-primary btn-small',
|
|
||||||
label: 'topic.timeline.back',
|
|
||||||
title: 'topic.timeline.back_description',
|
|
||||||
action: 'goBack'
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
goBack() {
|
|
||||||
this.sendWidgetAction('jumpToPost', this.attrs.lastRead);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function timelineDate(date) {
|
function timelineDate(date) {
|
||||||
|
@ -61,6 +62,9 @@ createWidget('timeline-scroller', {
|
||||||
contents.push(h('div.timeline-ago', timelineDate(date)));
|
contents.push(h('div.timeline-ago', timelineDate(date)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (attrs.showDockedButton) {
|
||||||
|
contents.push(attachBackButton(this));
|
||||||
|
}
|
||||||
let result = [ h('div.timeline-handle'), h('div.timeline-scroller-content', contents) ];
|
let result = [ h('div.timeline-handle'), h('div.timeline-scroller-content', contents) ];
|
||||||
|
|
||||||
if (attrs.fullScreen) {
|
if (attrs.fullScreen) {
|
||||||
|
@ -74,8 +78,10 @@ createWidget('timeline-scroller', {
|
||||||
this.sendWidgetAction('updatePercentage', e.pageY);
|
this.sendWidgetAction('updatePercentage', e.pageY);
|
||||||
},
|
},
|
||||||
|
|
||||||
dragEnd() {
|
dragEnd(e) {
|
||||||
this.sendWidgetAction('commit');
|
if (!$(e.target).is('button')) {
|
||||||
|
this.sendWidgetAction('commit');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -153,21 +159,35 @@ createWidget('timeline-scrollarea', {
|
||||||
const before = SCROLLAREA_REMAINING * percentage;
|
const before = SCROLLAREA_REMAINING * percentage;
|
||||||
const after = (SCROLLAREA_HEIGHT - before) - SCROLLER_HEIGHT;
|
const after = (SCROLLAREA_HEIGHT - before) - SCROLLER_HEIGHT;
|
||||||
|
|
||||||
|
let showButton = false;
|
||||||
|
const hasBackPosition =
|
||||||
|
position.lastRead > 3 &&
|
||||||
|
Math.abs(position.lastRead - position.current) > 3 &&
|
||||||
|
(position.lastRead && position.lastRead !== position.total);
|
||||||
|
|
||||||
|
if (hasBackPosition) {
|
||||||
|
const lastReadTop = Math.round(position.lastReadPercentage * SCROLLAREA_HEIGHT);
|
||||||
|
showButton = ((lastReadTop < before - (SCROLLER_HEIGHT * 0.5)) ||
|
||||||
|
(lastReadTop > (before + SCROLLER_HEIGHT))) &&
|
||||||
|
(lastReadTop < (SCROLLAREA_HEIGHT - SCROLLER_HEIGHT));
|
||||||
|
}
|
||||||
|
|
||||||
const result = [
|
const result = [
|
||||||
this.attach('timeline-padding', { height: before }),
|
this.attach('timeline-padding', { height: before }),
|
||||||
this.attach('timeline-scroller', _.merge(position, {fullScreen: attrs.fullScreen})),
|
this.attach('timeline-scroller', _.merge(position, {
|
||||||
|
showDockedButton: hasBackPosition && !showButton,
|
||||||
|
fullScreen: attrs.fullScreen
|
||||||
|
})),
|
||||||
this.attach('timeline-padding', { height: after })
|
this.attach('timeline-padding', { height: after })
|
||||||
];
|
];
|
||||||
|
|
||||||
if (position.lastRead && position.lastRead !== position.total) {
|
if (hasBackPosition) {
|
||||||
const lastReadTop = Math.round(position.lastReadPercentage * SCROLLAREA_HEIGHT);
|
const lastReadTop = Math.round(position.lastReadPercentage * SCROLLAREA_HEIGHT);
|
||||||
if (lastReadTop > (before + SCROLLER_HEIGHT * 0.5)) {
|
result.push(this.attach('timeline-last-read', {
|
||||||
result.push(this.attach('timeline-last-read', {
|
top: lastReadTop,
|
||||||
top: lastReadTop,
|
lastRead: position.lastRead,
|
||||||
lastRead: position.lastRead,
|
showButton
|
||||||
showButton: (lastReadTop > (before + SCROLLER_HEIGHT)) && (lastReadTop < (SCROLLAREA_HEIGHT - SCROLLER_HEIGHT))
|
}));
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -196,6 +216,10 @@ createWidget('timeline-scrollarea', {
|
||||||
_percentFor(topic, postIndex) {
|
_percentFor(topic, postIndex) {
|
||||||
const total = topic.get('postStream.filteredPostsCount');
|
const total = topic.get('postStream.filteredPostsCount');
|
||||||
return clamp(parseFloat(postIndex - 1.0) / total);
|
return clamp(parseFloat(postIndex - 1.0) / total);
|
||||||
|
},
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.sendWidgetAction('jumpToPost', this.position().lastRead);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -253,6 +253,10 @@
|
||||||
cursor: ns-resize;
|
cursor: ns-resize;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
.back-button {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.timeline-replies {
|
.timeline-replies {
|
||||||
|
@ -263,10 +267,6 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
margin-left: -0.35em;
|
margin-left: -0.35em;
|
||||||
|
|
||||||
.btn-small {
|
|
||||||
padding: 2px 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.progress {
|
i.progress {
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
color: $tertiary;
|
color: $tertiary;
|
||||||
|
@ -274,6 +274,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.back-button {
|
||||||
|
padding: 2px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.now-date {
|
.now-date {
|
||||||
@include unselectable;
|
@include unselectable;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
Loading…
Reference in New Issue