Merge branch 'master' into signup-cta

Conflicts:
	app/assets/javascripts/discourse/templates/topic.hbs
This commit is contained in:
Kane York 2015-09-15 13:52:12 -07:00
commit d47f1db2be
31 changed files with 290 additions and 260 deletions

View File

@ -1,3 +1,6 @@
import { exportEntity } from 'discourse/lib/export-csv';
import { outputExportResult } from 'discourse/lib/export-result';
export default Ember.Controller.extend({ export default Ember.Controller.extend({
viewMode: 'table', viewMode: 'table',
viewingTable: Em.computed.equal('viewMode', 'table'), viewingTable: Em.computed.equal('viewMode', 'table'),
@ -30,6 +33,15 @@ export default Ember.Controller.extend({
viewAsBarChart() { viewAsBarChart() {
this.set('viewMode', 'barChart'); this.set('viewMode', 'barChart');
},
exportCsv() {
exportEntity('report', {
name: this.get("model.type"),
start_date: this.get('startDate'),
end_date: this.get('endDate'),
category_id: this.get('categoryId') == 'all' ? undefined : this.get('categoryId')
}).then(outputExportResult);
} }
} }
}); });

View File

@ -5,6 +5,7 @@
{{i18n 'admin.dashboard.reports.end_date'}} {{input type="date" value=endDate}} {{i18n 'admin.dashboard.reports.end_date'}} {{input type="date" value=endDate}}
{{combo-box valueAttribute="value" content=categoryOptions value=categoryId}} {{combo-box valueAttribute="value" content=categoryOptions value=categoryId}}
{{d-button action="refreshReport" class="btn-primary" label="admin.dashboard.reports.refresh_report" icon="refresh"}} {{d-button action="refreshReport" class="btn-primary" label="admin.dashboard.reports.refresh_report" icon="refresh"}}
{{d-button action="exportCsv" label="admin.export_csv.button_text"}}
</div> </div>
<div class='view-options'> <div class='view-options'>

View File

@ -0,0 +1,45 @@
import { on } from 'ember-addons/ember-computed-decorators';
export default Ember.Component.extend({
classNameBindings: ["visible::hidden", ":popup-menu"],
@on('didInsertElement')
_setup() {
this.appEvents.on("popup-menu:open", this, "_changeLocation");
$('html').on(`mouseup.popup-menu-${this.get('elementId')}`, (e) => {
const $target = $(e.target);
if ($target.is("button") || this.$().has($target).length === 0) {
this.sendAction('hide');
}
});
},
@on('willDestroyElement')
_cleanup() {
$('html').off(`mouseup.popup-menu-${this.get('elementId')}`);
this.appEvents.off("popup-menu:open");
},
_changeLocation(location) {
const $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;
}
}
}
});

View File

@ -369,13 +369,13 @@ const PostMenuComponent = Ember.Component.extend(StringBuffer, {
unhidePostIcon = iconHTML('eye'), unhidePostIcon = iconHTML('eye'),
unhidePostText = I18n.t('post.controls.unhide'); unhidePostText = I18n.t('post.controls.unhide');
const html = '<div class="post-admin-menu">' + const html = '<div class="post-admin-menu popup-menu">' +
'<h3>' + I18n.t('admin_title') + '</h3>' + '<h3>' + I18n.t('admin_title') + '</h3>' +
'<ul>' + '<ul>' +
'<li class="btn btn-admin" data-action="toggleWiki">' + wikiIcon + wikiText + '</li>' + '<li class="btn" data-action="toggleWiki">' + wikiIcon + wikiText + '</li>' +
(Discourse.User.currentProp('staff') ? '<li class="btn btn-admin" data-action="togglePostType">' + postTypeIcon + postTypeText + '</li>' : '') + (Discourse.User.currentProp('staff') ? '<li class="btn" data-action="togglePostType">' + postTypeIcon + postTypeText + '</li>' : '') +
'<li class="btn btn-admin" data-action="rebakePost">' + rebakePostIcon + rebakePostText + '</li>' + '<li class="btn" data-action="rebakePost">' + rebakePostIcon + rebakePostText + '</li>' +
(post.hidden ? '<li class="btn btn-admin" data-action="unhidePost">' + unhidePostIcon + unhidePostText + '</li>' : '') + (post.hidden ? '<li class="btn" data-action="unhidePost">' + unhidePostIcon + unhidePostText + '</li>' : '') +
'</ul>' + '</ul>' +
'</div>'; '</div>';

View File

@ -0,0 +1,17 @@
import DButton from 'discourse/components/d-button';
export default DButton.extend({
click() {
const $target = this.$(),
position = $target.position(),
width = $target.innerWidth(),
loc = {
position: this.get('position') || "fixed",
left: position.left + width,
top: position.top
};
this.appEvents.trigger("popup-menu:open", loc);
this.sendAction("action");
}
});

View File

@ -1,24 +0,0 @@
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

@ -55,6 +55,7 @@ export default Ember.Controller.extend({
similarTopics: null, similarTopics: null,
similarTopicsMessage: null, similarTopicsMessage: null,
lastSimilaritySearch: null, lastSimilaritySearch: null,
optionsVisible: false,
topic: null, topic: null,
@ -84,6 +85,20 @@ export default Ember.Controller.extend({
}.property('model.creatingPrivateMessage', 'model.targetUsernames'), }.property('model.creatingPrivateMessage', 'model.targetUsernames'),
actions: { actions: {
toggleWhisper() {
this.toggleProperty('model.whisper');
},
showOptions(loc) {
this.appEvents.trigger('popup-menu:open', loc);
this.set('optionsVisible', true);
},
hideOptions() {
this.set('optionsVisible', false);
},
// Toggle the reply view // Toggle the reply view
toggle() { toggle() {
this.toggle(); this.toggle();

View File

@ -1,12 +0,0 @@
// This controller supports the admin menu on topics
export default Ember.Controller.extend({
menuVisible: false,
showRecover: Em.computed.and('model.deleted', 'model.details.can_recover'),
isFeatured: Em.computed.or("model.pinned_at", "model.isBanner"),
actions: {
show: function() { this.set('menuVisible', true); },
hide: function() { this.set('menuVisible', false); }
}
});

View File

@ -19,6 +19,10 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
enteredAt: null, enteredAt: null,
firstPostExpanded: false, firstPostExpanded: false,
retrying: false, retrying: false,
adminMenuVisible: false,
showRecover: Em.computed.and('model.deleted', 'model.details.can_recover'),
isFeatured: Em.computed.or("model.pinned_at", "model.isBanner"),
maxTitleLength: setting('max_topic_title_length'), maxTitleLength: setting('max_topic_title_length'),
@ -93,6 +97,14 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
}.on('init'), }.on('init'),
actions: { actions: {
showTopicAdminMenu() {
this.set('adminMenuVisible', true);
},
hideTopicAdminMenu() {
this.set('adminMenuVisible', false);
},
deleteTopic() { deleteTopic() {
this.deleteTopic(); this.deleteTopic();
}, },

View File

@ -163,7 +163,7 @@
} }
} }
uiManager = new UIManager(idPostfix, panels, undoManager, previewManager, commandManager, options.helpButton, getString); uiManager = new UIManager(idPostfix, panels, undoManager, previewManager, commandManager, options.helpButton, getString, options);
uiManager.setUndoRedoButtonStates(); uiManager.setUndoRedoButtonStates();
var forceRefresh = that.refreshPreview = function () { previewManager.refresh(true); }; var forceRefresh = that.refreshPreview = function () { previewManager.refresh(true); };
@ -1219,12 +1219,12 @@
}, 0); }, 0);
}; };
function UIManager(postfix, panels, undoManager, previewManager, commandManager, helpOptions, getString) { function UIManager(postfix, panels, undoManager, previewManager, commandManager, helpOptions, getString, options) {
var inputBox = panels.input, var inputBox = panels.input,
buttons = {}; // buttons.undo, buttons.link, etc. The actual DOM elements. buttons = {}; // buttons.undo, buttons.link, etc. The actual DOM elements.
makeSpritedButtonRow(); makeSpritedButtonRow(options);
var keyEvent = "keydown"; var keyEvent = "keydown";
@ -1396,7 +1396,8 @@
return function () { method.apply(commandManager, arguments); } return function () { method.apply(commandManager, arguments); }
} }
function makeSpritedButtonRow() { function makeSpritedButtonRow(options) {
options = options || {};
var buttonBar = panels.buttonBar; var buttonBar = panels.buttonBar;
var buttonRow = document.createElement("div"); var buttonRow = document.createElement("div");
@ -1459,17 +1460,21 @@
buttons.heading = makeButton("wmd-heading-button", getString("heading"), bindCommand("doHeading")); buttons.heading = makeButton("wmd-heading-button", getString("heading"), bindCommand("doHeading"));
buttons.hr = makeButton("wmd-hr-button", getString("hr"), bindCommand("doHorizontalRule")); buttons.hr = makeButton("wmd-hr-button", getString("hr"), bindCommand("doHorizontalRule"));
// If we have any buttons to append, do it! function createExtraButtons(buttons) {
if (typeof PagedownCustom != "undefined") { if (buttons && (buttons.length > 0)) {
var appendButtons = PagedownCustom.appendButtons for (var i=0; i< buttons.length; i++) {
if (appendButtons && (appendButtons.length > 0)) { var b = buttons[i];
for (var i=0; i< appendButtons.length; i++) {
var b = appendButtons[i];
makeButton(b.id, b.description, b.execute) makeButton(b.id, b.description, b.execute)
} }
} }
} }
// If we have any buttons to append, do it!
if (typeof PagedownCustom != "undefined") {
createExtraButtons(PagedownCustom.appendButtons);
}
createExtraButtons(options.appendButtons);
//makeSpacer(3); //makeSpacer(3);
//buttons.undo = makeButton("wmd-undo-button", getString("undo"), null); //buttons.undo = makeButton("wmd-undo-button", getString("undo"), null);

View File

@ -1,7 +1,7 @@
function exportEntityByType(type, entity) { function exportEntityByType(type, entity, args) {
return Discourse.ajax("/export_csv/export_entity.json", { return Discourse.ajax("/export_csv/export_entity.json", {
method: 'POST', method: 'POST',
data: {entity_type: type, entity} data: {entity_type: type, entity, args}
}); });
} }
@ -14,6 +14,6 @@ export function exportUserArchive() {
} }
export function exportEntity(entity) { export function exportEntity(entity, args) {
return exportEntityByType('admin', entity); return exportEntityByType('admin', entity, args);
} }

View File

@ -152,16 +152,16 @@ Discourse.Markdown = {
return this.markdownConverter(opts).makeHtml(raw); return this.markdownConverter(opts).makeHtml(raw);
}, },
createEditor: function(converterOptions) { createEditor: function(options) {
if (!converterOptions) converterOptions = {}; options = options || {};
// By default we always sanitize content in the editor // By default we always sanitize content in the editor
converterOptions.sanitize = true; options.sanitize = true;
var markdownConverter = Discourse.Markdown.markdownConverter(converterOptions); var markdownConverter = Discourse.Markdown.markdownConverter(options);
var editorOptions = { var editorOptions = {
containerElement: converterOptions.containerElement, containerElement: options.containerElement,
strings: { strings: {
bold: I18n.t("composer.bold_title") + " <strong> Ctrl+B", bold: I18n.t("composer.bold_title") + " <strong> Ctrl+B",
boldexample: I18n.t("composer.bold_text"), boldexample: I18n.t("composer.bold_text"),
@ -197,7 +197,8 @@ Discourse.Markdown = {
redomac: I18n.t("composer.redo_title") + " - Ctrl+Shift+Z", redomac: I18n.t("composer.redo_title") + " - Ctrl+Shift+Z",
help: I18n.t("composer.help") help: I18n.t("composer.help")
} },
appendButtons: options.appendButtons
}; };
return new Markdown.Editor(markdownConverter, undefined, editorOptions); return new Markdown.Editor(markdownConverter, undefined, editorOptions);

View File

@ -41,10 +41,6 @@ const TopicRoute = Discourse.Route.extend({
actions: { actions: {
showTopicAdminMenu() {
this.controllerFor("topic-admin-menu").send("show");
},
showFlags(model) { showFlags(model) {
showModal('flag', { model }); showModal('flag', { model });
this.controllerFor('flag').setProperties({ selected: null }); this.controllerFor('flag').setProperties({ selected: null });
@ -213,7 +209,6 @@ const TopicRoute = Discourse.Route.extend({
this.controllerFor('header').setProperties({ topic: model, showExtraInfo: false }); this.controllerFor('header').setProperties({ topic: model, showExtraInfo: false });
this.searchService.set('searchContext', model.get('searchContext')); this.searchService.set('searchContext', model.get('searchContext'));
this.controllerFor('topic-admin-menu').set('model', model);
this.controllerFor('composer').set('topic', model); this.controllerFor('composer').set('topic', model);
this.topicTrackingState.trackIncoming('all'); this.topicTrackingState.trackIncoming('all');

View File

@ -0,0 +1,4 @@
<h3>{{i18n title}}</h3>
<ul>
{{yield}}
</ul>

View File

@ -1,8 +1,17 @@
{{#if visible}} {{#if visible}}
<div class='contents'> <div class='contents'>
{{#if currentUser.staff}}
{{#popup-menu visible=optionsVisible hide="hideOptions" title="composer.options"}}
<li>
{{d-button action="toggleWhisper" icon="eye-slash" label="composer.toggle_whisper"}}
</li>
{{/popup-menu}}
{{/if}}
{{render "composer-messages"}} {{render "composer-messages"}}
<div class='control'> <div class='control'>
<a href class='toggler' {{action "toggle" bubbles=false}} title='{{i18n 'composer.toggler'}}'></a> <a href class='toggler' {{action "toggle" bubbles=false}} title={{i18n 'composer.toggler'}}></a>
{{#if model.viewOpen}} {{#if model.viewOpen}}
<div class='control-row reply-area'> <div class='control-row reply-area'>
@ -11,6 +20,10 @@
<div class='reply-to'> <div class='reply-to'>
{{{model.actionTitle}}} {{{model.actionTitle}}}
{{#if model.whisper}}
<span class='whisper'>({{i18n "composer.whisper"}})</span>
{{/if}}
{{#if canEdit}} {{#if canEdit}}
{{#if showEditReason}} {{#if showEditReason}}
<div class="edit-reason-input"> <div class="edit-reason-input">
@ -61,15 +74,6 @@
</div> </div>
{{/if}} {{/if}}
{{#if canWhisper}}
<div class='form-element clearfix'>
<label>
{{input type="checkbox" checked=model.whisper tabindex="3"}}
{{i18n "composer.add_whisper"}}
</label>
</div>
{{/if}}
{{plugin-outlet "composer-fields"}} {{plugin-outlet "composer-fields"}}
</div> </div>

View File

@ -1,62 +0,0 @@
<h3>{{i18n 'admin_title'}}</h3>
<ul>
<li>
{{d-button action="toggleMultiSelect" icon="tasks" label="topic.actions.multi_select" class="btn-admin"}}
</li>
{{#if model.details.can_delete}}
<li>
{{d-button action="deleteTopic" icon="trash-o" label="topic.actions.delete" class="btn-admin btn-danger"}}
</li>
{{/if}}
{{#if showRecover}}
<li>
{{d-button action="recoverTopic" icon="undo" label="topic.actions.recover" class="btn-admin"}}
</li>
{{/if}}
<li>
{{#if model.closed}}
{{d-button action="toggleClosed" icon="unlock" label="topic.actions.open" class="btn-admin"}}
{{else}}
{{d-button action="toggleClosed" icon="lock" label="topic.actions.close" class="btn-admin"}}
{{d-button action="showAutoClose" icon="clock-o" label="topic.actions.auto_close" class="btn-admin"}}
{{/if}}
</li>
{{#unless model.isPrivateMessage}}
{{#if model.visible}}
<li>
{{#if isFeatured}}
{{d-button action="showFeatureTopic" icon="thumb-tack" label="topic.actions.unpin" class="btn-admin"}}
{{else}}
{{d-button action="showFeatureTopic" icon="thumb-tack" label="topic.actions.pin" class="btn-admin"}}
{{/if}}
</li>
{{/if}}
{{/unless}}
<li>
{{d-button action="showChangeTimestamp" icon="calendar" label="topic.change_timestamp.title" class="btn-admin"}}
</li>
<li>
{{#if model.archived}}
{{d-button action="toggleArchived" icon="folder" label="topic.actions.unarchive" class="btn-admin"}}
{{else}}
{{d-button action="toggleArchived" icon="folder" label="topic.actions.archive" class="btn-admin"}}
{{/if}}
</li>
<li>
{{#if model.visible}}
{{d-button action="toggleVisibility" icon="eye-slash" label="topic.actions.invisible" class="btn-admin"}}
{{else}}
{{d-button action="toggleVisibility" icon="eye" label="topic.actions.visible" class="btn-admin"}}
{{/if}}
</li>
{{plugin-outlet "topic-admin-menu-buttons"}}
</ul>

View File

@ -55,7 +55,6 @@
{{/if}} {{/if}}
<div class="container posts"> <div class="container posts">
{{view "selected-posts"}} {{view "selected-posts"}}
<div class="row"> <div class="row">
@ -87,6 +86,7 @@
{{#if loadedAllPosts}} {{#if loadedAllPosts}}
{{view "topic-closing" topic=model}} {{view "topic-closing" topic=model}}
{{show-popup-button action="showTopicAdminMenu" title="topic_admin_menu" icon="wrench" position="absolute"}}
{{#if session.showSignupCta}} {{#if session.showSignupCta}}
{{! replace "Log In to Reply" with the infobox }} {{! replace "Log In to Reply" with the infobox }}
{{signup-cta}} {{signup-cta}}
@ -155,6 +155,65 @@
{{/if}} {{/if}}
{{#if currentUser.canManageTopic}} {{#if currentUser.canManageTopic}}
{{show-topic-admin show="showTopicAdminMenu"}} {{show-popup-button action="showTopicAdminMenu" class="show-topic-admin" title="topic_admin_menu" icon="wrench"}}
{{render "topic-admin-menu"}} {{#popup-menu visible=adminMenuVisible hide="hideTopicAdminMenu" title="admin_title"}}
<li>
{{d-button action="toggleMultiSelect" icon="tasks" label="topic.actions.multi_select"}}
</li>
{{#if model.details.can_delete}}
<li>
{{d-button action="deleteTopic" icon="trash-o" label="topic.actions.delete" class="btn-danger"}}
</li>
{{/if}}
{{#if showRecover}}
<li>
{{d-button action="recoverTopic" icon="undo" label="topic.actions.recover"}}
</li>
{{/if}}
<li>
{{#if model.closed}}
{{d-button action="toggleClosed" icon="unlock" label="topic.actions.open"}}
{{else}}
{{d-button action="toggleClosed" icon="lock" label="topic.actions.close"}}
{{d-button action="showAutoClose" icon="clock-o" label="topic.actions.auto_close"}}
{{/if}}
</li>
{{#unless model.isPrivateMessage}}
{{#if model.visible}}
<li>
{{#if isFeatured}}
{{d-button action="showFeatureTopic" icon="thumb-tack" label="topic.actions.unpin"}}
{{else}}
{{d-button action="showFeatureTopic" icon="thumb-tack" label="topic.actions.pin"}}
{{/if}}
</li>
{{/if}}
{{/unless}}
<li>
{{d-button action="showChangeTimestamp" icon="calendar" label="topic.change_timestamp.title"}}
</li>
<li>
{{#if model.archived}}
{{d-button action="toggleArchived" icon="folder" label="topic.actions.unarchive"}}
{{else}}
{{d-button action="toggleArchived" icon="folder" label="topic.actions.archive"}}
{{/if}}
</li>
<li>
{{#if model.visible}}
{{d-button action="toggleVisibility" icon="eye-slash" label="topic.actions.invisible"}}
{{else}}
{{d-button action="toggleVisibility" icon="eye" label="topic.actions.visible"}}
{{/if}}
</li>
{{plugin-outlet "topic-admin-menu-buttons"}}
{{/popup-menu}}
{{/if}} {{/if}}

View File

@ -219,6 +219,8 @@ const ComposerView = Ember.View.extend(Ember.Evented, {
// but if you start replying to another topic it will get the avatars wrong // but if you start replying to another topic it will get the avatars wrong
let $wmdInput; let $wmdInput;
const self = this; const self = this;
const controller = this.get('controller');
this.wmdInput = $wmdInput = this.$('.wmd-input'); this.wmdInput = $wmdInput = this.$('.wmd-input');
if ($wmdInput.length === 0 || $wmdInput.data('init') === true) return; if ($wmdInput.length === 0 || $wmdInput.data('init') === true) return;
@ -233,7 +235,7 @@ const ComposerView = Ember.View.extend(Ember.Evented, {
dataSource(term) { dataSource(term) {
return userSearch({ return userSearch({
term: term, term: term,
topicId: self.get('controller.controllers.topic.model.id'), topicId: controller.get('controllers.topic.model.id'),
includeGroups: true includeGroups: true
}); });
}, },
@ -243,18 +245,40 @@ const ComposerView = Ember.View.extend(Ember.Evented, {
} }
}); });
this.editor = Discourse.Markdown.createEditor({
const options ={
containerElement: this.element, containerElement: this.element,
lookupAvatarByPostNumber(postNumber, topicId) { lookupAvatarByPostNumber(postNumber, topicId) {
const posts = self.get('controller.controllers.topic.model.postStream.posts'); const posts = controller.get('controllers.topic.model.postStream.posts');
if (posts && topicId === self.get('controller.controllers.topic.model.id')) { if (posts && topicId === controller.get('controllers.topic.model.id')) {
const quotedPost = posts.findProperty("post_number", postNumber); const quotedPost = posts.findProperty("post_number", postNumber);
if (quotedPost) { if (quotedPost) {
return Discourse.Utilities.tinyAvatar(quotedPost.get('avatar_template')); return Discourse.Utilities.tinyAvatar(quotedPost.get('avatar_template'));
} }
} }
} }
}); };
const showOptions = controller.get('canWhisper');
if (showOptions) {
options.appendButtons = [{
id: 'wmd-composer-options',
description: I18n.t("composer.options"),
execute() {
const toolbarPos = self.$('.wmd-controls').position();
const pos = self.$('.wmd-composer-options').position();
const location = {
position: "absolute",
left: toolbarPos.left + pos.left,
top: toolbarPos.top + pos.top,
}
controller.send('showOptions', location);
}
}];
}
this.editor = Discourse.Markdown.createEditor(options);
// HACK to change the upload icon of the composer's toolbar // HACK to change the upload icon of the composer's toolbar
if (!Discourse.Utilities.allowsAttachments()) { if (!Discourse.Utilities.allowsAttachments()) {
@ -265,7 +289,7 @@ const ComposerView = Ember.View.extend(Ember.Evented, {
this.editor.hooks.insertImageDialog = function(callback) { this.editor.hooks.insertImageDialog = function(callback) {
callback(null); callback(null);
self.get('controller').send('showUploadSelector', self); controller.send('showUploadSelector', self);
return true; return true;
}; };
@ -278,7 +302,7 @@ const ComposerView = Ember.View.extend(Ember.Evented, {
this.loadingChanged(); this.loadingChanged();
const saveDraft = debounce((function() { const saveDraft = debounce((function() {
return self.get('controller').saveDraft(); return controller.saveDraft();
}), 2000); }), 2000);
$wmdInput.keyup(function() { $wmdInput.keyup(function() {
@ -344,7 +368,7 @@ const ComposerView = Ember.View.extend(Ember.Evented, {
$uploadTarget.on("fileuploadsend", (e, data) => { $uploadTarget.on("fileuploadsend", (e, data) => {
// hide the "file selector" modal // hide the "file selector" modal
this.get("controller").send("closeModal"); controller.send("closeModal");
// deal with cancellation // deal with cancellation
cancelledByTheUser = false; cancelledByTheUser = false;
// add upload placeholder // add upload placeholder

View File

@ -1,21 +0,0 @@
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

@ -1,52 +0,0 @@
/**
This view is used for rendering the topic admin menu
@class TopicAdminMenuView
@extends Ember.View
@namespace Discourse
@module Discourse
**/
export default Ember.View.extend({
classNameBindings: ["controller.menuVisible::hidden", ":topic-admin-menu"],
_setup: function() {
var self = this;
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");
}
});
}.on("didInsertElement"),
_changeLocation: function(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,4 +1,3 @@
import TopicAdminMenuButton from 'discourse/views/topic-admin-menu-button';
import LoginReplyButton from 'discourse/views/login-reply-button'; import LoginReplyButton from 'discourse/views/login-reply-button';
import FlagTopicButton from 'discourse/views/flag-topic-button'; import FlagTopicButton from 'discourse/views/flag-topic-button';
import BookmarkButton from 'discourse/views/bookmark-button'; import BookmarkButton from 'discourse/views/bookmark-button';
@ -47,14 +46,11 @@ export default DiscourseContainerView.extend({
// Add the buttons below a topic // Add the buttons below a topic
createButtons() { createButtons() {
const topic = this.get('topic'); const topic = this.get('topic');
if (Discourse.User.current()) { const currentUser = this.get('controller.currentUser');
if (currentUser) {
const viewArgs = {topic}; const viewArgs = {topic};
if (Discourse.User.currentProp("staff")) {
this.attachViewClass(TopicAdminMenuButton);
}
this.attachViewWithArgs(viewArgs, MainPanel); this.attachViewWithArgs(viewArgs, MainPanel);
this.attachViewWithArgs(viewArgs, PinnedButton); this.attachViewWithArgs(viewArgs, PinnedButton);
this.attachViewWithArgs(viewArgs, TopicNotificationsButton); this.attachViewWithArgs(viewArgs, TopicNotificationsButton);

View File

@ -142,7 +142,12 @@ div.ac-wrap {
left: 48%; left: 48%;
top: 20%; top: 20%;
} }
.whisper {
margin-left: 1em;
font-style: italic;
} }
}
// this removes the topmost margin from the first element in the topic post // this removes the topmost margin from the first element in the topic post
// if we don't do this, all posts would have extra space at the top // if we don't do this, all posts would have extra space at the top

View File

@ -111,6 +111,10 @@
content: "\f0e5"; content: "\f0e5";
} }
.wmd-composer-options:before {
content: "\f013";
}
.wmd-prompt-background { .wmd-prompt-background {
background-color: #111; background-color: #111;
box-shadow: 0 3px 7px rgba(0,0,0, .8); box-shadow: 0 3px 7px rgba(0,0,0, .8);

View File

@ -3,7 +3,7 @@
// Adding the !important declaration to a rule prevents it from being flipped. // Adding the !important declaration to a rule prevents it from being flipped.
// Keep the topic admin menu on the page // Keep the topic admin menu on the page
.rtl .topic-admin-menu { .rtl .popup-menu {
right: 0 !important; right: 0 !important;
} }

View File

@ -8,7 +8,7 @@
outline: 0; outline: 0;
} }
.topic-admin-menu { .popup-menu {
background-color: $secondary; background-color: $secondary;
width: 205px; width: 205px;
padding: 10px; padding: 10px;
@ -20,10 +20,13 @@
margin: 10px 0 0 0; margin: 10px 0 0 0;
} }
.btn {
text-align: left;
}
button { button {
width: 200px; width: 200px;
margin-bottom: 5px; margin-bottom: 5px;
i { i {
width: 14px; width: 14px;
} }

View File

@ -62,12 +62,6 @@
} }
} }
// Buttons used in admin panel
// --------------------------------------------------
.btn-admin {
text-align:left;
}
// Primary button // Primary button
// -------------------------------------------------- // --------------------------------------------------

View File

@ -593,14 +593,7 @@ a.mention {
margin-top: -20px; margin-top: -20px;
} }
#show-topic-admin { .popup-menu {
right: 20px;
padding: 5px 8px;
margin-top: 5px;
}
.topic-admin-menu {
h3 {margin-top: 0;} h3 {margin-top: 0;}
} }

View File

@ -437,14 +437,6 @@ button.select-post {
background-color: dark-light-diff(rgba($danger,.7), $secondary, 50%, -60%); background-color: dark-light-diff(rgba($danger,.7), $secondary, 50%, -60%);
} }
#show-topic-admin {
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
right: 0;
border-right: 0;
padding-right: 4px;
padding-left: 5px;
}
.deleted-user-avatar { .deleted-user-avatar {
font-size: 2.571em; font-size: 2.571em;
} }

View File

@ -3,11 +3,8 @@ class ExportCsvController < ApplicationController
skip_before_filter :preload_json, :check_xhr, only: [:show] skip_before_filter :preload_json, :check_xhr, only: [:show]
def export_entity def export_entity
params.require(:entity) guardian.ensure_can_export_entity!(export_params[:entity_type])
params.require(:entity_type) Jobs.enqueue(:export_csv_file, entity: export_params[:entity], user_id: current_user.id, args: export_params[:args])
guardian.ensure_can_export_entity!(params[:entity_type])
Jobs.enqueue(:export_csv_file, entity: params[:entity], user_id: current_user.id)
render json: success_json render json: success_json
end end
@ -27,4 +24,13 @@ class ExportCsvController < ApplicationController
end end
end end
private
def export_params
@_export_params ||= begin
params.require(:entity)
params.require(:entity_type)
params.permit(:entity, :entity_type, args: [:name, :start_date, :end_date, :category_id])
end
end
end end

View File

@ -15,12 +15,14 @@ module Jobs
HEADER_ATTRS_FOR['screened_email'] = ['email','action','match_count','last_match_at','created_at','ip_address'] HEADER_ATTRS_FOR['screened_email'] = ['email','action','match_count','last_match_at','created_at','ip_address']
HEADER_ATTRS_FOR['screened_ip'] = ['ip_address','action','match_count','last_match_at','created_at'] HEADER_ATTRS_FOR['screened_ip'] = ['ip_address','action','match_count','last_match_at','created_at']
HEADER_ATTRS_FOR['screened_url'] = ['domain','action','match_count','last_match_at','created_at'] HEADER_ATTRS_FOR['screened_url'] = ['domain','action','match_count','last_match_at','created_at']
HEADER_ATTRS_FOR['report'] = ['date', 'value']
sidekiq_options retry: false sidekiq_options retry: false
attr_accessor :current_user attr_accessor :current_user
def execute(args) def execute(args)
@entity = args[:entity] @entity = args[:entity]
@extra = HashWithIndifferentAccess.new(args[:args]) if args[:args]
@file_name = @entity @file_name = @entity
@current_user = User.find_by(id: args[:user_id]) @current_user = User.find_by(id: args[:user_id])
@ -93,6 +95,16 @@ module Jobs
end end
end end
def report_export
@extra[:start_date] = @extra[:start_date].to_date if @extra[:start_date].is_a?(String)
@extra[:end_date] = @extra[:end_date].to_date if @extra[:end_date].is_a?(String)
@extra[:category_id] = @extra[:category_id].to_i if @extra[:category_id]
r = Report.find(@extra[:name], @extra)
r.data.map do |row|
[row[:x].to_s(:db), row[:y].to_s(:db)]
end
end
def get_header def get_header
case @entity case @entity

View File

@ -827,9 +827,11 @@ en:
composer: composer:
emoji: "Emoji :smile:" emoji: "Emoji :smile:"
options: "Composer Options"
whisper: "whisper"
add_warning: "This is an official warning." add_warning: "This is an official warning."
add_whisper: "This is a whisper only visible to moderators" toggle_whisper: "Toggle Whisper"
posting_not_on_topic: "Which topic do you want to reply to?" posting_not_on_topic: "Which topic do you want to reply to?"
saving_draft_tip: "saving..." saving_draft_tip: "saving..."
saved_draft_tip: "saved" saved_draft_tip: "saved"