UX: On mobile use a dropdown for topic controls instead of many buttons

This commit is contained in:
Robin Ward 2015-12-11 15:07:38 -05:00
parent 4a21c29961
commit b2c73e7045
11 changed files with 124 additions and 45 deletions

View File

@ -76,13 +76,12 @@ export default Ember.Component.extend({
$elem.select2({formatResult: this.comboTemplate, minimumResultsForSearch, width: 'resolve'});
const castInteger = this.get('castInteger');
const self = this;
$elem.on("change", function (e) {
$elem.on("change", e => {
let val = $(e.target).val();
if (val && val.length && castInteger) {
val = parseInt(val, 10);
}
self.set('value', val);
this.set('value', val);
});
$elem.trigger('change');
}.on('didInsertElement'),

View File

@ -0,0 +1,60 @@
import Combobox from 'discourse/components/combo-box';
import { on, observes } from 'ember-addons/ember-computed-decorators';
export default Combobox.extend({
none: "topic.controls",
@on('init')
_createContent() {
const content = [];
const topic = this.get('topic');
const details = topic.get('details');
if (details.get('can_invite_to')) {
content.push({ id: 'invite', name: I18n.t('topic.invite_reply.title') });
}
if (topic.get('bookmarked')) {
content.push({ id: 'bookmark', name: I18n.t('bookmarked.clear_bookmarks') });
} else {
content.push({ id: 'bookmark', name: I18n.t('bookmarked.title') });
}
content.push({ id: 'share', name: I18n.t('topic.share.title') });
if (details.get('can_flag_topic')) {
content.push({ id: 'flag', name: I18n.t('topic.flag_topic.title') });
}
this.set('content', content);
},
@observes('value')
_valueChanged() {
const value = this.get('value');
const controller = this.get('parentView.controller');
const topic = this.get('topic');
const refresh = () => {
this._createContent();
this.set('value', null);
};
switch(value) {
case 'invite':
controller.send('showInvite');
refresh();
break;
case 'bookmark':
topic.toggleBookmark().then(() => refresh());
break;
case 'share':
this.appEvents.trigger('share:url', topic.get('shareUrl'), $('#topic-footer-buttons'));
refresh();
break;
case 'flag':
controller.send('showFlagTopic', topic);
refresh();
break;
}
}
});

View File

@ -1,9 +1,4 @@
/**
An object that is responsible for logic related to mobile devices.
@namespace Discourse
@module Mobile
**/
// An object that is responsible for logic related to mobile devices.
Discourse.Mobile = {
isMobileDevice: false,
mobileView: false,

View File

@ -1,4 +1,5 @@
import ButtonView from 'discourse/views/button';
import { iconHTML } from 'discourse/helpers/fa-icon';
export default ButtonView.extend({
classNames: ['bookmark'],
@ -16,12 +17,12 @@ export default ButtonView.extend({
return this.get("bookmarked") ? "bookmarked.help.unbookmark" : "bookmarked.help.bookmark";
}.property("bookmarked"),
click: function() {
click() {
this.get('controller').send('toggleBookmark');
},
renderIcon: function(buffer) {
var className = this.get("bookmarked") ? "bookmarked" : "";
buffer.push("<i class='fa fa-bookmark " + className + "'></i>");
renderIcon(buffer) {
const className = this.get("bookmarked") ? "bookmarked" : "";
buffer.push(iconHTML('bookmark', { class: className }));
}
});

View File

@ -1,15 +1,16 @@
import ButtonView from 'discourse/views/button';
import { iconHTML } from 'discourse/helpers/fa-icon';
export default ButtonView.extend({
classNames: ['flag-topic'],
textKey: 'topic.flag_topic.title',
helpKey: 'topic.flag_topic.help',
click: function() {
click() {
this.get('controller').send('showFlagTopic', this.get('controller.content'));
},
renderIcon: function(buffer) {
buffer.push("<i class='fa fa-flag'></i>");
renderIcon(buffer) {
buffer.push(iconHTML('flag'));
}
});

View File

@ -1,4 +1,5 @@
import ButtonView from 'discourse/views/button';
import { iconHTML } from 'discourse/helpers/fa-icon';
export default ButtonView.extend({
textKey: 'topic.invite_reply.title',
@ -7,7 +8,7 @@ export default ButtonView.extend({
disabled: Em.computed.or('controller.model.archived', 'controller.model.closed', 'controller.model.deleted'),
renderIcon(buffer) {
buffer.push("<i class='fa fa-users'></i>");
buffer.push(iconHTML('users'));
},
click() {

View File

@ -1,4 +1,5 @@
import ButtonView from 'discourse/views/button';
import { iconHTML } from 'discourse/helpers/fa-icon';
export default ButtonView.extend({
classNames: ['share'],
@ -7,8 +8,7 @@ export default ButtonView.extend({
'data-share-url': Em.computed.alias('topic.shareUrl'),
topic: Em.computed.alias('controller.model'),
renderIcon: function(buffer) {
buffer.push("<i class='fa fa-link'></i>");
renderIcon(buffer) {
buffer.push(iconHTML("link"));
}
});

View File

@ -56,26 +56,17 @@ export default Ember.View.extend({
return true;
});
$html.on('click.discoure-share-link', '[data-share-url]', function(e) {
// if they want to open in a new tab, let it so
if (e.shiftKey || e.metaKey || e.ctrlKey || e.which === 2) { return true; }
e.preventDefault();
var $currentTarget = $(e.currentTarget),
$currentTargetOffset = $currentTarget.offset(),
$shareLink = $('#share-link'),
url = $currentTarget.data('share-url'),
postNumber = $currentTarget.data('post-number'),
date = $currentTarget.children().data('time');
function showPanel($target, url, postNumber, date) {
const $currentTargetOffset = $target.offset();
const $shareLink = $('#share-link');
// Relative urls
if (url.indexOf("/") === 0) {
url = window.location.protocol + "//" + window.location.host + url;
}
var shareLinkWidth = $shareLink.width();
var x = $currentTargetOffset.left - (shareLinkWidth / 2);
const shareLinkWidth = $shareLink.width();
let x = $currentTargetOffset.left - (shareLinkWidth / 2);
if (x < 25) {
x = 25;
}
@ -83,8 +74,8 @@ export default Ember.View.extend({
x -= shareLinkWidth / 2;
}
var header = $('.d-header');
var y = $currentTargetOffset.top - ($shareLink.height() + 20);
const header = $('.d-header');
let y = $currentTargetOffset.top - ($shareLink.height() + 20);
if (y < header.offset().top + header.height()) {
y = $currentTargetOffset.top + 10;
}
@ -98,7 +89,21 @@ export default Ember.View.extend({
self.set('controller.link', url);
self.set('controller.postNumber', postNumber);
self.set('controller.date', date);
}
this.appEvents.on('share:url', (url, $target) => showPanel($target, url));
$html.on('click.discoure-share-link', '[data-share-url]', function(e) {
// if they want to open in a new tab, let it so
if (e.shiftKey || e.metaKey || e.ctrlKey || e.which === 2) { return true; }
e.preventDefault();
const $currentTarget = $(e.currentTarget),
url = $currentTarget.data('share-url'),
postNumber = $currentTarget.data('post-number'),
date = $currentTarget.children().data('time');
showPanel($currentTarget, url, postNumber, date);
return false;
});

View File

@ -6,22 +6,30 @@ export default ContainerView.extend({
@on('init')
createButtons() {
if (this.currentUser.get('staff')) {
const mobileView = Discourse.Mobile.mobileView;
if (!mobileView && this.currentUser.get('staff')) {
const viewArgs = {action: 'showTopicAdminMenu', title: 'topic_admin_menu', icon: 'wrench', position: 'absolute'};
this.attachViewWithArgs(viewArgs, 'show-popup-button');
}
const topic = this.get('topic');
if (!topic.get('isPrivateMessage')) {
// We hide some controls from private messages
if (this.get('topic.details.can_invite_to')) {
this.attachViewClass('invite-reply-button');
}
this.attachViewClass('bookmark-button');
this.attachViewClass('share-button');
if (this.get('topic.details.can_flag_topic')) {
this.attachViewClass('flag-topic-button');
if (mobileView) {
this.attachViewWithArgs({ topic }, 'topic-footer-mobile-dropdown');
} else {
// We hide some controls from private messages
if (this.get('topic.details.can_invite_to')) {
this.attachViewClass('invite-reply-button');
}
this.attachViewClass('bookmark-button');
this.attachViewClass('share-button');
if (this.get('topic.details.can_flag_topic')) {
this.attachViewClass('flag-topic-button');
}
}
}
if (this.get('topic.details.can_create_post')) {
this.attachViewClass('reply-button');

View File

@ -300,6 +300,13 @@ a.star {
border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -60%);
padding: 20px 0 0 0;
.fa-bookmark.bookmarked { color: $tertiary; }
.combobox {
float: left;
margin-right: 1em;
width: 160px;
margin-bottom: 0.5em;
}
}
/* this is to force the drop-down notification state description para below the button */

View File

@ -1275,6 +1275,8 @@ en:
error: "Sorry, there was an error inviting that user."
group_name: "group name"
controls: "Topic Controls"
invite_reply:
title: 'Invite'
username_placeholder: "username"