UX: add topic admin button to the bottom of the topic

This commit is contained in:
Régis Hanol 2014-10-06 20:19:07 +02:00
parent b1271ed44b
commit 67c10a7eab
12 changed files with 167 additions and 98 deletions

View File

@ -0,0 +1,24 @@
export default Em.Component.extend({
tagName: "button",
classNames: ["btn", "no-text", "show-topic-admin"],
attributeBindings: ["title"],
title: I18n.t("topic_admin_menu"),
render: function(buffer) {
buffer.push("<i class='fa fa-wrench'></i>");
},
click: function() {
var $target = this.$(),
position = $target.position(),
width = $target.innerWidth();
var location = {
position: "fixed",
left: position.left + width,
top: position.top,
};
this.appEvents.trigger("topic-admin-menu:open", location);
this.sendAction("show");
return false;
}
});

View File

@ -10,17 +10,11 @@ import ObjectController from 'discourse/controllers/object';
**/
export default ObjectController.extend({
menuVisible: false,
needs: ['modal'],
showRecover: Em.computed.and('deleted', 'details.can_recover'),
actions: {
show: function() {
this.set('menuVisible', true);
},
show: function() { this.set('menuVisible', true); },
hide: function() { this.set('menuVisible', false); }
}
hide: function() {
this.set('menuVisible', false);
}
},
showRecover: Em.computed.and('deleted', 'details.can_recover')
});

View File

@ -13,6 +13,10 @@ Discourse.TopicRoute = Discourse.Route.extend({
},
actions: {
showTopicAdminMenu: function() {
this.controllerFor("topic-admin-menu").send("show");
},
// Modals that can pop up within a topic
expandPostUser: function(post) {
this.controllerFor('user-expansion').show(post.get('username'), post.get('uploaded_avatar_id'));

View File

@ -1,74 +1,68 @@
{{#if menuVisible}}
<div class="topic-admin-menu">
<h3>{{i18n admin_title}}</h3>
<h3>{{i18n admin_title}}</h3>
<ul>
<li>
<button {{action "toggleMultiSelect"}} class='btn btn-admin'><i class='fa fa-tasks'></i> {{i18n topic.actions.multi_select}}</button>
</li>
<ul>
<li>
<button {{action "toggleMultiSelect"}} class='btn btn-admin'>{{fa-icon tasks}} {{i18n topic.actions.multi_select}}</button>
</li>
{{#if details.can_delete}}
<li>
<button {{action "deleteTopic"}} class='btn btn-admin btn-danger'><i class='fa fa-trash-o'></i> {{i18n topic.actions.delete}}</button>
</li>
{{/if}}
{{#if details.can_delete}}
<li>
<button {{action "deleteTopic"}} class='btn btn-admin btn-danger'>{{fa-icon trash-o}} {{i18n topic.actions.delete}}</button>
</li>
{{/if}}
{{#if showRecover}}
<li>
<button {{action "recoverTopic"}} class='btn btn-admin'><i class='fa fa-undo'></i> {{i18n topic.actions.recover}}</button>
</li>
{{/if}}
{{#if showRecover}}
<li>
<button {{action "recoverTopic"}} class='btn btn-admin'>{{fa-icon undo}} {{i18n topic.actions.recover}}</button>
</li>
{{/if}}
<li>
{{#if closed}}
<button {{action "toggleClosed"}} class='btn btn-admin'><i class='fa fa-unlock'></i> {{i18n topic.actions.open}}</button>
{{else}}
<button {{action "toggleClosed"}} class='btn btn-admin'><i class='fa fa-lock'></i> {{i18n topic.actions.close}}</button>
<button {{action "showAutoClose"}} class='btn btn-admin'><i class='fa fa-clock-o'></i> {{i18n topic.actions.auto_close}}</button>
{{/if}}
</li>
<li>
{{#if closed}}
<button {{action "toggleClosed"}} class='btn btn-admin'>{{fa-icon unlock}} {{i18n topic.actions.open}}</button>
{{else}}
<button {{action "toggleClosed"}} class='btn btn-admin'>{{fa-icon lock}} {{i18n topic.actions.close}}</button>
<button {{action "showAutoClose"}} class='btn btn-admin'>{{fa-icon clock-o}} {{i18n topic.actions.auto_close}}</button>
{{/if}}
</li>
{{#unless isPrivateMessage}}
<li>
{{#if isBanner}}
<button {{action "removeBanner"}} class='btn btn-admin'><i class='fa fa-bullhorn'></i> {{i18n topic.actions.remove_banner}}</button>
{{else}}
{{#if visible}}
<button {{action "makeBanner"}} class='btn btn-admin'><i class='fa fa-bullhorn'></i> {{i18n topic.actions.make_banner}}</button>
{{/if}}
{{/if}}
</li>
<li>
{{#if pinned_at}}
<button {{action "togglePinned"}} class='btn btn-admin'><i class='fa fa-thumb-tack'></i> {{i18n topic.actions.unpin}}</button>
{{else}}
{{#if visible}}
<button {{action "togglePinned"}} class='btn btn-admin'><i class='fa fa-thumb-tack'></i> {{i18n topic.actions.pin}}</button>
<button {{action "togglePinnedGlobally"}} class='btn btn-admin'><i class='fa fa-thumb-tack'></i> {{i18n topic.actions.pin_globally}}</button>
{{/if}}
{{/if}}
</li>
{{/unless}}
<li>
{{#if archived}}
<button {{action "toggleArchived"}} class='btn btn-admin'><i class='fa fa-folder'></i> {{i18n topic.actions.unarchive}}</button>
{{else}}
<button {{action "toggleArchived"}} class='btn btn-admin'><i class='fa fa-folder'></i> {{i18n topic.actions.archive}}</button>
{{/if}}
</li>
<li>
{{#unless isPrivateMessage}}
<li>
{{#if isBanner}}
<button {{action "removeBanner"}} class='btn btn-admin'>{{fa-icon bullhorn}} {{i18n topic.actions.remove_banner}}</button>
{{else}}
{{#if visible}}
<button {{action "toggleVisibility"}} class='btn btn-admin'><i class='fa fa-eye-slash'></i> {{i18n topic.actions.invisible}}</button>
{{else}}
<button {{action "toggleVisibility"}} class='btn btn-admin'><i class='fa fa-eye'></i> {{i18n topic.actions.visible}}</button>
<button {{action "makeBanner"}} class='btn btn-admin'>{{fa-icon bullhorn}} {{i18n topic.actions.make_banner}}</button>
{{/if}}
</li>
{{/if}}
</li>
</ul>
</div>
{{else}}
<button class='btn no-text' id='show-topic-admin' {{action "show"}}><i class='fa fa-wrench'></i></button>
{{/if}}
<li>
{{#if pinned_at}}
<button {{action "togglePinned"}} class='btn btn-admin'>{{fa-icon thumb-tack}} {{i18n topic.actions.unpin}}</button>
{{else}}
{{#if visible}}
<button {{action "togglePinned"}} class='btn btn-admin'>{{fa-icon thumb-tack}} {{i18n topic.actions.pin}}</button>
<button {{action "togglePinnedGlobally"}} class='btn btn-admin'>{{fa-icon thumb-tack}} {{i18n topic.actions.pin_globally}}</button>
{{/if}}
{{/if}}
</li>
{{/unless}}
<li>
{{#if archived}}
<button {{action "toggleArchived"}} class='btn btn-admin'>{{fa-icon folder}} {{i18n topic.actions.unarchive}}</button>
{{else}}
<button {{action "toggleArchived"}} class='btn btn-admin'>{{fa-icon folder}} {{i18n topic.actions.archive}}</button>
{{/if}}
</li>
<li>
{{#if visible}}
<button {{action "toggleVisibility"}} class='btn btn-admin'>{{fa-icon eye-slash}} {{i18n topic.actions.invisible}}</button>
{{else}}
<button {{action "toggleVisibility"}} class='btn btn-admin'>{{fa-icon eye}} {{i18n topic.actions.visible}}</button>
{{/if}}
</li>
</ul>

View File

@ -25,12 +25,12 @@
{{/if}}
{{text-field id='edit-title' value=newTitle maxLength=maxTitleLength}}
<button class='btn btn-primary btn-small no-text' {{action "finishedEditingTopic"}}><i class='fa fa-check'></i></button>
<button class='btn btn-small no-text' {{action "cancelEditingTopic"}}><i class='fa fa-times'></i></button>
<button class='btn btn-primary btn-small no-text' {{action "finishedEditingTopic"}}>{{fa-icon check}}</button>
<button class='btn btn-small no-text' {{action "cancelEditingTopic"}}>{{fa-icon times}}</button>
{{else}}
<h1>
{{#unless is_warning}}
<span class="private-message-glyph"><i class='fa fa-envelope'></i></span>
<span class="private-message-glyph">{{fa-icon envelope}}</span>
{{/unless}}
{{#if details.loaded}}
@ -46,7 +46,7 @@
{{#if details.can_edit}}
<a href='#' {{action "editTopic"}} class='edit-topic' title='{{i18n edit}}'><i class="fa fa-pencil"></i></a>
<a href='#' {{action "editTopic"}} class='edit-topic' title='{{i18n edit}}'>{{fa-icon pencil}}</a>
{{/if}}
</h1>
@ -118,7 +118,6 @@
{{/if}}
{{/if}}
</section>
</div>
@ -134,7 +133,7 @@
{{message}}
{{#if noRetry}}
{{#unless currentUser}}
<button {{action "showLogin"}} class='btn btn-primary topic-retry'><i class="fa fa-user"></i>{{i18n log_in}}</button>
<button {{action "showLogin"}} class='btn btn-primary topic-retry'>{{fa-icon user}} {{i18n log_in}}</button>
{{/unless}}
{{else}}
<button class="btn btn-primary topic-retry" {{action "retryLoading"}}>{{i18n errors.buttons.again}}</button>
@ -159,5 +158,6 @@
{{/if}}
{{#if currentUser.canManageTopic}}
{{show-topic-admin show="showTopicAdminMenu"}}
{{render "topic-admin-menu"}}
{{/if}}

View File

@ -5,9 +5,10 @@ export default Discourse.View.extend({
title: function() {
return I18n.t(this.get('helpKey') || this.get('textKey'));
}.property('helpKey'),
}.property('helpKey', 'textKey'),
text: function() {
if (Em.empty(this.get('textKey'))) { return ""; }
return I18n.t(this.get('textKey'));
}.property('textKey'),

View File

@ -0,0 +1,21 @@
import ButtonView from "discourse/views/button";
export default ButtonView.extend({
classNameBindings: [":no-text"],
helpKey: "topic_admin_menu",
renderIcon: function(buffer) {
buffer.push("<i class='fa fa-wrench'></i>");
},
click: function() {
var offset = this.$().offset();
var location = {
position: "absolute",
left: offset.left,
top: offset.top,
};
this.get("controller").appEvents.trigger("topic-admin-menu:open", location);
return this.get("controller").send("showTopicAdminMenu");
}
});

View File

@ -7,21 +7,47 @@
@module Discourse
**/
export default Discourse.View.extend({
classNameBindings: ["controller.menuVisible::hidden", ":topic-admin-menu"],
willDestroyElement: function() {
$('html').off('mouseup.discourse-topic-admin-menu');
},
didInsertElement: function() {
_setup: function() {
var self = this;
$('html').on('mouseup.discourse-topic-admin-menu', function(e) {
this.appEvents.on("topic-admin-menu:open", this, "_changeLocation");
$("html").on("mouseup.discourse-topic-admin-menu", function(e) {
var $target = $(e.target);
if ($target.is('button') || self.$().has($target).length === 0) {
self.get('controller').send('hide');
if ($target.is("button") || self.$().has($target).length === 0) {
self.get("controller").send("hide");
}
});
}
}.on("didInsertElement"),
_changeLocation: function(location) {
console.log("_changeLocation", location);
var $this = this.$();
switch (location.position) {
case "absolute": {
$this.css({
position: "absolute",
top: location.top - $this.innerHeight() + 5,
left: location.left,
})
break;
}
case "fixed": {
$this.css({
position: "fixed",
top: location.top,
left: location.left - $this.innerWidth(),
})
break;
}
}
},
_cleanup: function() {
$("html").off("mouseup.discourse-topic-admin-menu");
this.appEvents.off("topic-admin-menu:open");
}.on("willDestroyElement"),
});

View File

@ -1,3 +1,4 @@
import TopicAdminMenuButton from 'discourse/views/topic-admin-menu-button';
import LoginReplyButton from 'discourse/views/login-reply-button';
import FlagTopicButton from 'discourse/views/flag-topic-button';
import StarButton from 'discourse/views/star-button';
@ -21,6 +22,9 @@ export default DiscourseContainerView.extend({
createButtons: function() {
var topic = this.get('topic');
if (Discourse.User.current()) {
if (Discourse.User.currentProp("staff")) {
this.attachViewClass(TopicAdminMenuButton);
}
if (!topic.get('isPrivateMessage')) {
// We hide some controls from private messages
if (this.get('topic.details.can_invite_to')) {

View File

@ -1,10 +1,11 @@
// Styles for the topic admin menu
#show-topic-admin {
.show-topic-admin {
position: fixed;
top: 70px;
right: 10px;
z-index: 1000;
outline: 0;
}
.topic-admin-menu {
@ -12,9 +13,6 @@
width: 205px;
padding: 10px;
border: 1px solid scale-color-diff();
position: fixed;
top: 70px;
right: 10px;
z-index: 1001;
ul {

View File

@ -473,6 +473,7 @@ a.star {
color: $primary;
}
.btn {
outline: 0;
margin-bottom: 5px;
margin-right: 10px;
.fa-star {margin-right: 5px;}

View File

@ -101,6 +101,8 @@ en:
google+: 'share this link on Google+'
email: 'send this link in an email'
topic_admin_menu: "topic admin actions"
edit: 'edit the title and category of this topic'
not_implemented: "That feature hasn't been implemented yet, sorry!"
no_value: "No"