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"