diff --git a/app/assets/javascripts/admin/controllers/admin-reports.js.es6 b/app/assets/javascripts/admin/controllers/admin-reports.js.es6 index e964d17a257..d83a031c6bc 100644 --- a/app/assets/javascripts/admin/controllers/admin-reports.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-reports.js.es6 @@ -1,3 +1,6 @@ +import { exportEntity } from 'discourse/lib/export-csv'; +import { outputExportResult } from 'discourse/lib/export-result'; + export default Ember.Controller.extend({ viewMode: 'table', viewingTable: Em.computed.equal('viewMode', 'table'), @@ -30,6 +33,15 @@ export default Ember.Controller.extend({ viewAsBarChart() { 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); } } }); diff --git a/app/assets/javascripts/admin/templates/reports.hbs b/app/assets/javascripts/admin/templates/reports.hbs index c7383ef2c8a..5e1b406ea6a 100644 --- a/app/assets/javascripts/admin/templates/reports.hbs +++ b/app/assets/javascripts/admin/templates/reports.hbs @@ -5,6 +5,7 @@ {{i18n 'admin.dashboard.reports.end_date'}} {{input type="date" value=endDate}} {{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="exportCsv" label="admin.export_csv.button_text"}}
diff --git a/app/assets/javascripts/discourse/components/popup-menu.js.es6 b/app/assets/javascripts/discourse/components/popup-menu.js.es6 new file mode 100644 index 00000000000..1f5de232ae6 --- /dev/null +++ b/app/assets/javascripts/discourse/components/popup-menu.js.es6 @@ -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; + } + } + } +}); diff --git a/app/assets/javascripts/discourse/components/post-menu.js.es6 b/app/assets/javascripts/discourse/components/post-menu.js.es6 index 33800387f2c..9981c5330bc 100644 --- a/app/assets/javascripts/discourse/components/post-menu.js.es6 +++ b/app/assets/javascripts/discourse/components/post-menu.js.es6 @@ -369,13 +369,13 @@ const PostMenuComponent = Ember.Component.extend(StringBuffer, { unhidePostIcon = iconHTML('eye'), unhidePostText = I18n.t('post.controls.unhide'); - const html = '
' + + const html = '
' + '

' + I18n.t('admin_title') + '

' + '
    ' + - '
  • ' + wikiIcon + wikiText + '
  • ' + - (Discourse.User.currentProp('staff') ? '
  • ' + postTypeIcon + postTypeText + '
  • ' : '') + - '
  • ' + rebakePostIcon + rebakePostText + '
  • ' + - (post.hidden ? '
  • ' + unhidePostIcon + unhidePostText + '
  • ' : '') + + '
  • ' + wikiIcon + wikiText + '
  • ' + + (Discourse.User.currentProp('staff') ? '
  • ' + postTypeIcon + postTypeText + '
  • ' : '') + + '
  • ' + rebakePostIcon + rebakePostText + '
  • ' + + (post.hidden ? '
  • ' + unhidePostIcon + unhidePostText + '
  • ' : '') + '
' + '
'; diff --git a/app/assets/javascripts/discourse/components/show-popup-button.js.es6 b/app/assets/javascripts/discourse/components/show-popup-button.js.es6 new file mode 100644 index 00000000000..0f1a40734fd --- /dev/null +++ b/app/assets/javascripts/discourse/components/show-popup-button.js.es6 @@ -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"); + } +}); diff --git a/app/assets/javascripts/discourse/components/show-topic-admin.js.es6 b/app/assets/javascripts/discourse/components/show-topic-admin.js.es6 deleted file mode 100644 index 1faf600056a..00000000000 --- a/app/assets/javascripts/discourse/components/show-topic-admin.js.es6 +++ /dev/null @@ -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(""); - }, - - 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; - } -}); diff --git a/app/assets/javascripts/discourse/controllers/composer.js.es6 b/app/assets/javascripts/discourse/controllers/composer.js.es6 index 9e5b2206d0a..8ded3a2e858 100644 --- a/app/assets/javascripts/discourse/controllers/composer.js.es6 +++ b/app/assets/javascripts/discourse/controllers/composer.js.es6 @@ -55,6 +55,7 @@ export default Ember.Controller.extend({ similarTopics: null, similarTopicsMessage: null, lastSimilaritySearch: null, + optionsVisible: false, topic: null, @@ -84,6 +85,20 @@ export default Ember.Controller.extend({ }.property('model.creatingPrivateMessage', 'model.targetUsernames'), 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() { this.toggle(); diff --git a/app/assets/javascripts/discourse/controllers/topic-admin-menu.js.es6 b/app/assets/javascripts/discourse/controllers/topic-admin-menu.js.es6 deleted file mode 100644 index 4e454b85230..00000000000 --- a/app/assets/javascripts/discourse/controllers/topic-admin-menu.js.es6 +++ /dev/null @@ -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); } - } - -}); diff --git a/app/assets/javascripts/discourse/controllers/topic.js.es6 b/app/assets/javascripts/discourse/controllers/topic.js.es6 index 80ac937398b..4d8b126d026 100644 --- a/app/assets/javascripts/discourse/controllers/topic.js.es6 +++ b/app/assets/javascripts/discourse/controllers/topic.js.es6 @@ -19,6 +19,10 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, { enteredAt: null, firstPostExpanded: 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'), @@ -93,6 +97,14 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, { }.on('init'), actions: { + showTopicAdminMenu() { + this.set('adminMenuVisible', true); + }, + + hideTopicAdminMenu() { + this.set('adminMenuVisible', false); + }, + deleteTopic() { this.deleteTopic(); }, diff --git a/app/assets/javascripts/discourse/lib/Markdown.Editor.js b/app/assets/javascripts/discourse/lib/Markdown.Editor.js index 97a58375c9b..13ca4b52a4d 100644 --- a/app/assets/javascripts/discourse/lib/Markdown.Editor.js +++ b/app/assets/javascripts/discourse/lib/Markdown.Editor.js @@ -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(); var forceRefresh = that.refreshPreview = function () { previewManager.refresh(true); }; @@ -1219,12 +1219,12 @@ }, 0); }; - function UIManager(postfix, panels, undoManager, previewManager, commandManager, helpOptions, getString) { + function UIManager(postfix, panels, undoManager, previewManager, commandManager, helpOptions, getString, options) { var inputBox = panels.input, buttons = {}; // buttons.undo, buttons.link, etc. The actual DOM elements. - makeSpritedButtonRow(); + makeSpritedButtonRow(options); var keyEvent = "keydown"; @@ -1396,7 +1396,8 @@ return function () { method.apply(commandManager, arguments); } } - function makeSpritedButtonRow() { + function makeSpritedButtonRow(options) { + options = options || {}; var buttonBar = panels.buttonBar; var buttonRow = document.createElement("div"); @@ -1459,17 +1460,21 @@ buttons.heading = makeButton("wmd-heading-button", getString("heading"), bindCommand("doHeading")); buttons.hr = makeButton("wmd-hr-button", getString("hr"), bindCommand("doHorizontalRule")); - // If we have any buttons to append, do it! - if (typeof PagedownCustom != "undefined") { - var appendButtons = PagedownCustom.appendButtons - if (appendButtons && (appendButtons.length > 0)) { - for (var i=0; i< appendButtons.length; i++) { - var b = appendButtons[i]; + function createExtraButtons(buttons) { + if (buttons && (buttons.length > 0)) { + for (var i=0; i< buttons.length; i++) { + var b = buttons[i]; 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); //buttons.undo = makeButton("wmd-undo-button", getString("undo"), null); diff --git a/app/assets/javascripts/discourse/lib/export-csv.js.es6 b/app/assets/javascripts/discourse/lib/export-csv.js.es6 index 9681c9fc5a9..c4b74a08fb0 100644 --- a/app/assets/javascripts/discourse/lib/export-csv.js.es6 +++ b/app/assets/javascripts/discourse/lib/export-csv.js.es6 @@ -1,7 +1,7 @@ -function exportEntityByType(type, entity) { +function exportEntityByType(type, entity, args) { return Discourse.ajax("/export_csv/export_entity.json", { method: 'POST', - data: {entity_type: type, entity} + data: {entity_type: type, entity, args} }); } @@ -14,6 +14,6 @@ export function exportUserArchive() { } -export function exportEntity(entity) { - return exportEntityByType('admin', entity); +export function exportEntity(entity, args) { + return exportEntityByType('admin', entity, args); } diff --git a/app/assets/javascripts/discourse/lib/markdown.js b/app/assets/javascripts/discourse/lib/markdown.js index 9e59a38a387..888f282d182 100644 --- a/app/assets/javascripts/discourse/lib/markdown.js +++ b/app/assets/javascripts/discourse/lib/markdown.js @@ -152,16 +152,16 @@ Discourse.Markdown = { return this.markdownConverter(opts).makeHtml(raw); }, - createEditor: function(converterOptions) { - if (!converterOptions) converterOptions = {}; + createEditor: function(options) { + options = options || {}; // 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 = { - containerElement: converterOptions.containerElement, + containerElement: options.containerElement, strings: { bold: I18n.t("composer.bold_title") + " Ctrl+B", boldexample: I18n.t("composer.bold_text"), @@ -197,7 +197,8 @@ Discourse.Markdown = { redomac: I18n.t("composer.redo_title") + " - Ctrl+Shift+Z", help: I18n.t("composer.help") - } + }, + appendButtons: options.appendButtons }; return new Markdown.Editor(markdownConverter, undefined, editorOptions); diff --git a/app/assets/javascripts/discourse/routes/topic.js.es6 b/app/assets/javascripts/discourse/routes/topic.js.es6 index 759ec4bbb7b..8bfdf13d5b5 100644 --- a/app/assets/javascripts/discourse/routes/topic.js.es6 +++ b/app/assets/javascripts/discourse/routes/topic.js.es6 @@ -41,10 +41,6 @@ const TopicRoute = Discourse.Route.extend({ actions: { - showTopicAdminMenu() { - this.controllerFor("topic-admin-menu").send("show"); - }, - showFlags(model) { showModal('flag', { model }); this.controllerFor('flag').setProperties({ selected: null }); @@ -213,7 +209,6 @@ const TopicRoute = Discourse.Route.extend({ this.controllerFor('header').setProperties({ topic: model, showExtraInfo: false }); this.searchService.set('searchContext', model.get('searchContext')); - this.controllerFor('topic-admin-menu').set('model', model); this.controllerFor('composer').set('topic', model); this.topicTrackingState.trackIncoming('all'); diff --git a/app/assets/javascripts/discourse/templates/components/popup-menu.hbs b/app/assets/javascripts/discourse/templates/components/popup-menu.hbs new file mode 100644 index 00000000000..5c5c8a9ed2e --- /dev/null +++ b/app/assets/javascripts/discourse/templates/components/popup-menu.hbs @@ -0,0 +1,4 @@ +

{{i18n title}}

+
    + {{yield}} +
diff --git a/app/assets/javascripts/discourse/templates/composer.hbs b/app/assets/javascripts/discourse/templates/composer.hbs index 01234ff0e9b..4e75418d926 100644 --- a/app/assets/javascripts/discourse/templates/composer.hbs +++ b/app/assets/javascripts/discourse/templates/composer.hbs @@ -1,8 +1,17 @@ {{#if visible}}
+ + {{#if currentUser.staff}} + {{#popup-menu visible=optionsVisible hide="hideOptions" title="composer.options"}} +
  • + {{d-button action="toggleWhisper" icon="eye-slash" label="composer.toggle_whisper"}} +
  • + {{/popup-menu}} + {{/if}} + {{render "composer-messages"}}
    - + {{#if model.viewOpen}}
    @@ -11,6 +20,10 @@
    {{{model.actionTitle}}} + {{#if model.whisper}} + ({{i18n "composer.whisper"}}) + {{/if}} + {{#if canEdit}} {{#if showEditReason}}
    @@ -61,15 +74,6 @@
    {{/if}} - {{#if canWhisper}} -
    - -
    - {{/if}} - {{plugin-outlet "composer-fields"}}
    diff --git a/app/assets/javascripts/discourse/templates/topic-admin-menu.hbs b/app/assets/javascripts/discourse/templates/topic-admin-menu.hbs deleted file mode 100644 index 2f190df2140..00000000000 --- a/app/assets/javascripts/discourse/templates/topic-admin-menu.hbs +++ /dev/null @@ -1,62 +0,0 @@ -

    {{i18n 'admin_title'}}

    - -
      -
    • - {{d-button action="toggleMultiSelect" icon="tasks" label="topic.actions.multi_select" class="btn-admin"}} -
    • - - {{#if model.details.can_delete}} -
    • - {{d-button action="deleteTopic" icon="trash-o" label="topic.actions.delete" class="btn-admin btn-danger"}} -
    • - {{/if}} - - {{#if showRecover}} -
    • - {{d-button action="recoverTopic" icon="undo" label="topic.actions.recover" class="btn-admin"}} -
    • - {{/if}} - -
    • - {{#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}} -
    • - - {{#unless model.isPrivateMessage}} - {{#if model.visible}} -
    • - {{#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}} -
    • - {{/if}} - {{/unless}} - -
    • - {{d-button action="showChangeTimestamp" icon="calendar" label="topic.change_timestamp.title" class="btn-admin"}} -
    • - -
    • - {{#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}} -
    • - -
    • - {{#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}} -
    • - - {{plugin-outlet "topic-admin-menu-buttons"}} -
    diff --git a/app/assets/javascripts/discourse/templates/topic.hbs b/app/assets/javascripts/discourse/templates/topic.hbs index 986b8321ad5..bb521636501 100644 --- a/app/assets/javascripts/discourse/templates/topic.hbs +++ b/app/assets/javascripts/discourse/templates/topic.hbs @@ -55,7 +55,6 @@ {{/if}}
    - {{view "selected-posts"}}
    @@ -87,6 +86,7 @@ {{#if loadedAllPosts}} {{view "topic-closing" topic=model}} + {{show-popup-button action="showTopicAdminMenu" title="topic_admin_menu" icon="wrench" position="absolute"}} {{#if session.showSignupCta}} {{! replace "Log In to Reply" with the infobox }} {{signup-cta}} @@ -155,6 +155,65 @@ {{/if}} {{#if currentUser.canManageTopic}} - {{show-topic-admin show="showTopicAdminMenu"}} - {{render "topic-admin-menu"}} + {{show-popup-button action="showTopicAdminMenu" class="show-topic-admin" title="topic_admin_menu" icon="wrench"}} + {{#popup-menu visible=adminMenuVisible hide="hideTopicAdminMenu" title="admin_title"}} +
  • + {{d-button action="toggleMultiSelect" icon="tasks" label="topic.actions.multi_select"}} +
  • + + {{#if model.details.can_delete}} +
  • + {{d-button action="deleteTopic" icon="trash-o" label="topic.actions.delete" class="btn-danger"}} +
  • + {{/if}} + + {{#if showRecover}} +
  • + {{d-button action="recoverTopic" icon="undo" label="topic.actions.recover"}} +
  • + {{/if}} + +
  • + {{#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}} +
  • + + {{#unless model.isPrivateMessage}} + {{#if model.visible}} +
  • + {{#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}} +
  • + {{/if}} + {{/unless}} + +
  • + {{d-button action="showChangeTimestamp" icon="calendar" label="topic.change_timestamp.title"}} +
  • + +
  • + {{#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}} +
  • + +
  • + {{#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}} +
  • + + {{plugin-outlet "topic-admin-menu-buttons"}} + {{/popup-menu}} {{/if}} diff --git a/app/assets/javascripts/discourse/views/composer.js.es6 b/app/assets/javascripts/discourse/views/composer.js.es6 index 5d62db4161b..076c02ab983 100644 --- a/app/assets/javascripts/discourse/views/composer.js.es6 +++ b/app/assets/javascripts/discourse/views/composer.js.es6 @@ -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 let $wmdInput; const self = this; + const controller = this.get('controller'); + this.wmdInput = $wmdInput = this.$('.wmd-input'); if ($wmdInput.length === 0 || $wmdInput.data('init') === true) return; @@ -233,7 +235,7 @@ const ComposerView = Ember.View.extend(Ember.Evented, { dataSource(term) { return userSearch({ term: term, - topicId: self.get('controller.controllers.topic.model.id'), + topicId: controller.get('controllers.topic.model.id'), includeGroups: true }); }, @@ -243,18 +245,40 @@ const ComposerView = Ember.View.extend(Ember.Evented, { } }); - this.editor = Discourse.Markdown.createEditor({ + + const options ={ containerElement: this.element, lookupAvatarByPostNumber(postNumber, topicId) { - const posts = self.get('controller.controllers.topic.model.postStream.posts'); - if (posts && topicId === self.get('controller.controllers.topic.model.id')) { + const posts = controller.get('controllers.topic.model.postStream.posts'); + if (posts && topicId === controller.get('controllers.topic.model.id')) { const quotedPost = posts.findProperty("post_number", postNumber); if (quotedPost) { 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 if (!Discourse.Utilities.allowsAttachments()) { @@ -265,7 +289,7 @@ const ComposerView = Ember.View.extend(Ember.Evented, { this.editor.hooks.insertImageDialog = function(callback) { callback(null); - self.get('controller').send('showUploadSelector', self); + controller.send('showUploadSelector', self); return true; }; @@ -278,7 +302,7 @@ const ComposerView = Ember.View.extend(Ember.Evented, { this.loadingChanged(); const saveDraft = debounce((function() { - return self.get('controller').saveDraft(); + return controller.saveDraft(); }), 2000); $wmdInput.keyup(function() { @@ -344,7 +368,7 @@ const ComposerView = Ember.View.extend(Ember.Evented, { $uploadTarget.on("fileuploadsend", (e, data) => { // hide the "file selector" modal - this.get("controller").send("closeModal"); + controller.send("closeModal"); // deal with cancellation cancelledByTheUser = false; // add upload placeholder diff --git a/app/assets/javascripts/discourse/views/topic-admin-menu-button.js.es6 b/app/assets/javascripts/discourse/views/topic-admin-menu-button.js.es6 deleted file mode 100644 index cdd00b78dce..00000000000 --- a/app/assets/javascripts/discourse/views/topic-admin-menu-button.js.es6 +++ /dev/null @@ -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(""); - }, - - 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"); - } -}); diff --git a/app/assets/javascripts/discourse/views/topic-admin-menu.js.es6 b/app/assets/javascripts/discourse/views/topic-admin-menu.js.es6 deleted file mode 100644 index 05321a45474..00000000000 --- a/app/assets/javascripts/discourse/views/topic-admin-menu.js.es6 +++ /dev/null @@ -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"), - -}); diff --git a/app/assets/javascripts/discourse/views/topic-footer-buttons.js.es6 b/app/assets/javascripts/discourse/views/topic-footer-buttons.js.es6 index 3b70d394db6..25c9974f79f 100644 --- a/app/assets/javascripts/discourse/views/topic-footer-buttons.js.es6 +++ b/app/assets/javascripts/discourse/views/topic-footer-buttons.js.es6 @@ -1,4 +1,3 @@ -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 BookmarkButton from 'discourse/views/bookmark-button'; @@ -47,14 +46,11 @@ export default DiscourseContainerView.extend({ // Add the buttons below a topic createButtons() { const topic = this.get('topic'); - if (Discourse.User.current()) { + const currentUser = this.get('controller.currentUser'); + + if (currentUser) { const viewArgs = {topic}; - if (Discourse.User.currentProp("staff")) { - this.attachViewClass(TopicAdminMenuButton); - } - this.attachViewWithArgs(viewArgs, MainPanel); - this.attachViewWithArgs(viewArgs, PinnedButton); this.attachViewWithArgs(viewArgs, TopicNotificationsButton); diff --git a/app/assets/stylesheets/common/base/compose.scss b/app/assets/stylesheets/common/base/compose.scss index 844a9e32d37..c128d32ccec 100644 --- a/app/assets/stylesheets/common/base/compose.scss +++ b/app/assets/stylesheets/common/base/compose.scss @@ -142,8 +142,13 @@ div.ac-wrap { left: 48%; top: 20%; } + .whisper { + margin-left: 1em; + font-style: italic; + } } + // 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 .wmd-preview > *:first-child { diff --git a/app/assets/stylesheets/common/base/pagedown.scss b/app/assets/stylesheets/common/base/pagedown.scss index d7d411f6311..1ee211aa503 100644 --- a/app/assets/stylesheets/common/base/pagedown.scss +++ b/app/assets/stylesheets/common/base/pagedown.scss @@ -111,6 +111,10 @@ content: "\f0e5"; } +.wmd-composer-options:before { + content: "\f013"; +} + .wmd-prompt-background { background-color: #111; box-shadow: 0 3px 7px rgba(0,0,0, .8); diff --git a/app/assets/stylesheets/common/base/rtl.scss b/app/assets/stylesheets/common/base/rtl.scss index 1be9d21a485..bae997b4699 100644 --- a/app/assets/stylesheets/common/base/rtl.scss +++ b/app/assets/stylesheets/common/base/rtl.scss @@ -3,7 +3,7 @@ // Adding the !important declaration to a rule prevents it from being flipped. // Keep the topic admin menu on the page -.rtl .topic-admin-menu { +.rtl .popup-menu { right: 0 !important; } diff --git a/app/assets/stylesheets/common/base/topic-admin-menu.scss b/app/assets/stylesheets/common/base/topic-admin-menu.scss index a0db149139c..73e6a896e23 100644 --- a/app/assets/stylesheets/common/base/topic-admin-menu.scss +++ b/app/assets/stylesheets/common/base/topic-admin-menu.scss @@ -8,7 +8,7 @@ outline: 0; } -.topic-admin-menu { +.popup-menu { background-color: $secondary; width: 205px; padding: 10px; @@ -20,10 +20,13 @@ margin: 10px 0 0 0; } + .btn { + text-align: left; + } + button { width: 200px; margin-bottom: 5px; - i { width: 14px; } diff --git a/app/assets/stylesheets/common/components/buttons.css.scss b/app/assets/stylesheets/common/components/buttons.css.scss index e195a034f4b..bf42ff0f088 100644 --- a/app/assets/stylesheets/common/components/buttons.css.scss +++ b/app/assets/stylesheets/common/components/buttons.css.scss @@ -62,12 +62,6 @@ } } -// Buttons used in admin panel -// -------------------------------------------------- -.btn-admin { - text-align:left; -} - // Primary button // -------------------------------------------------- diff --git a/app/assets/stylesheets/desktop/topic-post.scss b/app/assets/stylesheets/desktop/topic-post.scss index df6a7d34503..41e29a5fa6d 100644 --- a/app/assets/stylesheets/desktop/topic-post.scss +++ b/app/assets/stylesheets/desktop/topic-post.scss @@ -593,14 +593,7 @@ a.mention { margin-top: -20px; } -#show-topic-admin { - right: 20px; - padding: 5px 8px; - margin-top: 5px; - -} - -.topic-admin-menu { +.popup-menu { h3 {margin-top: 0;} } diff --git a/app/assets/stylesheets/mobile/topic-post.scss b/app/assets/stylesheets/mobile/topic-post.scss index 842d13e506f..6e868fbd462 100644 --- a/app/assets/stylesheets/mobile/topic-post.scss +++ b/app/assets/stylesheets/mobile/topic-post.scss @@ -437,14 +437,6 @@ button.select-post { 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 { font-size: 2.571em; } diff --git a/app/controllers/export_csv_controller.rb b/app/controllers/export_csv_controller.rb index 74e341168cd..f632b93bee6 100644 --- a/app/controllers/export_csv_controller.rb +++ b/app/controllers/export_csv_controller.rb @@ -3,11 +3,8 @@ class ExportCsvController < ApplicationController skip_before_filter :preload_json, :check_xhr, only: [:show] def export_entity - params.require(:entity) - params.require(:entity_type) - guardian.ensure_can_export_entity!(params[:entity_type]) - - Jobs.enqueue(:export_csv_file, entity: params[:entity], user_id: current_user.id) + guardian.ensure_can_export_entity!(export_params[:entity_type]) + Jobs.enqueue(:export_csv_file, entity: export_params[:entity], user_id: current_user.id, args: export_params[:args]) render json: success_json end @@ -27,4 +24,13 @@ class ExportCsvController < ApplicationController 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 diff --git a/app/jobs/regular/export_csv_file.rb b/app/jobs/regular/export_csv_file.rb index 8e4201453d8..d3d2d3da891 100644 --- a/app/jobs/regular/export_csv_file.rb +++ b/app/jobs/regular/export_csv_file.rb @@ -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_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['report'] = ['date', 'value'] sidekiq_options retry: false attr_accessor :current_user def execute(args) @entity = args[:entity] + @extra = HashWithIndifferentAccess.new(args[:args]) if args[:args] @file_name = @entity @current_user = User.find_by(id: args[:user_id]) @@ -93,6 +95,16 @@ module Jobs 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 case @entity diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index d9ed6cf1d64..65082425730 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -827,9 +827,11 @@ en: composer: emoji: "Emoji :smile:" + options: "Composer Options" + whisper: "whisper" 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?" saving_draft_tip: "saving..." saved_draft_tip: "saved"