diff --git a/app/assets/javascripts/discourse/components/combo-box.js.es6 b/app/assets/javascripts/discourse/components/combo-box.js.es6
index ab43f7462d0..c314db566a4 100644
--- a/app/assets/javascripts/discourse/components/combo-box.js.es6
+++ b/app/assets/javascripts/discourse/components/combo-box.js.es6
@@ -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'),
diff --git a/app/assets/javascripts/discourse/components/topic-footer-mobile-dropdown.js.es6 b/app/assets/javascripts/discourse/components/topic-footer-mobile-dropdown.js.es6
new file mode 100644
index 00000000000..a975ade19d5
--- /dev/null
+++ b/app/assets/javascripts/discourse/components/topic-footer-mobile-dropdown.js.es6
@@ -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;
+ }
+ }
+});
diff --git a/app/assets/javascripts/discourse/lib/mobile.js b/app/assets/javascripts/discourse/lib/mobile.js
index 688482fa447..552e3f68733 100644
--- a/app/assets/javascripts/discourse/lib/mobile.js
+++ b/app/assets/javascripts/discourse/lib/mobile.js
@@ -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,
diff --git a/app/assets/javascripts/discourse/views/bookmark-button.js.es6 b/app/assets/javascripts/discourse/views/bookmark-button.js.es6
index 4fc63222c03..6135feae891 100644
--- a/app/assets/javascripts/discourse/views/bookmark-button.js.es6
+++ b/app/assets/javascripts/discourse/views/bookmark-button.js.es6
@@ -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("");
+ renderIcon(buffer) {
+ const className = this.get("bookmarked") ? "bookmarked" : "";
+ buffer.push(iconHTML('bookmark', { class: className }));
}
});
diff --git a/app/assets/javascripts/discourse/views/flag-topic-button.js.es6 b/app/assets/javascripts/discourse/views/flag-topic-button.js.es6
index f6ac7241fc3..ec3296ac091 100644
--- a/app/assets/javascripts/discourse/views/flag-topic-button.js.es6
+++ b/app/assets/javascripts/discourse/views/flag-topic-button.js.es6
@@ -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("");
+ renderIcon(buffer) {
+ buffer.push(iconHTML('flag'));
}
});
diff --git a/app/assets/javascripts/discourse/views/invite-reply-button.js.es6 b/app/assets/javascripts/discourse/views/invite-reply-button.js.es6
index 5e3279d5d00..2c856376f02 100644
--- a/app/assets/javascripts/discourse/views/invite-reply-button.js.es6
+++ b/app/assets/javascripts/discourse/views/invite-reply-button.js.es6
@@ -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("");
+ buffer.push(iconHTML('users'));
},
click() {
diff --git a/app/assets/javascripts/discourse/views/share-button.js.es6 b/app/assets/javascripts/discourse/views/share-button.js.es6
index 93ccdea03af..a7920b4afdc 100644
--- a/app/assets/javascripts/discourse/views/share-button.js.es6
+++ b/app/assets/javascripts/discourse/views/share-button.js.es6
@@ -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("");
+ renderIcon(buffer) {
+ buffer.push(iconHTML("link"));
}
});
-
diff --git a/app/assets/javascripts/discourse/views/share.js.es6 b/app/assets/javascripts/discourse/views/share.js.es6
index dc0925d7aed..6c1d0f18481 100644
--- a/app/assets/javascripts/discourse/views/share.js.es6
+++ b/app/assets/javascripts/discourse/views/share.js.es6
@@ -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;
});
diff --git a/app/assets/javascripts/discourse/views/topic-footer-main-buttons.js.es6 b/app/assets/javascripts/discourse/views/topic-footer-main-buttons.js.es6
index 8ba52885538..b35cfc9ddb9 100644
--- a/app/assets/javascripts/discourse/views/topic-footer-main-buttons.js.es6
+++ b/app/assets/javascripts/discourse/views/topic-footer-main-buttons.js.es6
@@ -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');
diff --git a/app/assets/stylesheets/mobile/topic-post.scss b/app/assets/stylesheets/mobile/topic-post.scss
index c58ab353a75..c0ffdc23506 100644
--- a/app/assets/stylesheets/mobile/topic-post.scss
+++ b/app/assets/stylesheets/mobile/topic-post.scss
@@ -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 */
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index eb01802f6a1..1b37af813fb 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -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"