diff --git a/app/assets/javascripts/discourse/app/components/d-editor.js b/app/assets/javascripts/discourse/app/components/d-editor.js index 9a1dd3c1411..193836dccfd 100644 --- a/app/assets/javascripts/discourse/app/components/d-editor.js +++ b/app/assets/javascripts/discourse/app/components/d-editor.js @@ -162,45 +162,55 @@ class Toolbar { this.groups[this.groups.length - 1].lastGroup = true; } - addButton(button) { - const g = this.groups.findBy("group", button.group); + addButton(buttonAttrs) { + const g = this.groups.findBy("group", buttonAttrs.group); if (!g) { - throw new Error(`Couldn't find toolbar group ${button.group}`); + throw new Error(`Couldn't find toolbar group ${buttonAttrs.group}`); } const createdButton = { - id: button.id, - tabindex: button.tabindex || "-1", - className: button.className || button.id, - label: button.label, - icon: button.icon, - action: button.action || ((a) => this.context.send("toolbarButton", a)), - perform: button.perform || function () {}, - trimLeading: button.trimLeading, - popupMenu: button.popupMenu || false, - preventFocus: button.preventFocus || false, - condition: button.condition || (() => true), + id: buttonAttrs.id, + tabindex: buttonAttrs.tabindex || "-1", + className: buttonAttrs.className || buttonAttrs.id, + label: buttonAttrs.label, + icon: buttonAttrs.icon, + action: (button) => { + buttonAttrs.action + ? buttonAttrs.action(button) + : this.context.send("toolbarButton", button); + this.context.appEvents.trigger( + "d-editor:toolbar-button-clicked", + button + ); + }, + perform: buttonAttrs.perform || function () {}, + trimLeading: buttonAttrs.trimLeading, + popupMenu: buttonAttrs.popupMenu || false, + preventFocus: buttonAttrs.preventFocus || false, + condition: buttonAttrs.condition || (() => true), }; - if (button.sendAction) { - createdButton.sendAction = button.sendAction; + if (buttonAttrs.sendAction) { + createdButton.sendAction = buttonAttrs.sendAction; } - const title = I18n.t(button.title || `composer.${button.id}_title`); - if (button.shortcut) { + const title = I18n.t( + buttonAttrs.title || `composer.${buttonAttrs.id}_title` + ); + if (buttonAttrs.shortcut) { const shortcutTitle = `${translateModKey( PLATFORM_KEY_MODIFIER + "+" - )}${translateModKey(button.shortcut)}`; + )}${translateModKey(buttonAttrs.shortcut)}`; createdButton.title = `${title} (${shortcutTitle})`; this.shortcuts[ - `${PLATFORM_KEY_MODIFIER}+${button.shortcut}`.toLowerCase() + `${PLATFORM_KEY_MODIFIER}+${buttonAttrs.shortcut}`.toLowerCase() ] = createdButton; } else { createdButton.title = title; } - if (button.unshift) { + if (buttonAttrs.unshift) { g.buttons.unshift(createdButton); } else { g.buttons.push(createdButton); diff --git a/app/assets/javascripts/discourse/app/services/composer.js b/app/assets/javascripts/discourse/app/services/composer.js index e6949c2f4ae..03fc5da0abb 100644 --- a/app/assets/javascripts/discourse/app/services/composer.js +++ b/app/assets/javascripts/discourse/app/services/composer.js @@ -384,6 +384,7 @@ export default class ComposerService extends Service { options.push( this._setupPopupMenuOption({ + name: "toggle-invisible", action: "toggleInvisible", icon: "far-eye-slash", label: "composer.toggle_unlisted", @@ -394,6 +395,7 @@ export default class ComposerService extends Service { if (this.capabilities.touch) { options.push( this._setupPopupMenuOption({ + name: "format-code", action: "applyFormatCode", icon: "code", label: "composer.code_title", @@ -402,6 +404,7 @@ export default class ComposerService extends Service { options.push( this._setupPopupMenuOption({ + name: "apply-unordered-list", action: "applyUnorderedList", icon: "list-ul", label: "composer.ulist_title", @@ -410,6 +413,7 @@ export default class ComposerService extends Service { options.push( this._setupPopupMenuOption({ + name: "apply-ordered-list", action: "applyOrderedList", icon: "list-ol", label: "composer.olist_title", @@ -419,6 +423,7 @@ export default class ComposerService extends Service { options.push( this._setupPopupMenuOption({ + name: "toggle-whisper", action: "toggleWhisper", icon: "far-eye-slash", label: "composer.toggle_whisper", @@ -428,6 +433,7 @@ export default class ComposerService extends Service { options.push( this._setupPopupMenuOption({ + name: "toggle-spreadsheet", action: "toggleSpreadsheet", icon: "table", label: "composer.insert_table", @@ -653,13 +659,19 @@ export default class ComposerService extends Service { } @action - onPopupMenuAction(menuAction) { - if (typeof menuAction === "function") { - return menuAction(this.toolbarEvent); + onPopupMenuAction(menuItem) { + // menuItem is an object with keys name & action like so: { name: "toggle-invisible, action: "toggleInvisible" } + // `action` value can either be a string (to lookup action by) or a function to call + this.appEvents.trigger( + "composer:toolbar-popup-menu-button-clicked", + menuItem + ); + if (typeof menuItem.action === "function") { + return menuItem.action(this.toolbarEvent); } else { return ( - this.actions?.[menuAction]?.bind(this) || // Legacy-style contributions from themes/plugins - this[menuAction] + this.actions?.[menuItem.action]?.bind(this) || // Legacy-style contributions from themes/plugins + this[menuItem.action] )(); } } @@ -1411,6 +1423,7 @@ export default class ComposerService extends Service { await this._setModel(composerModel, opts); } finally { this.skipAutoSave = false; + this.appEvents.trigger("composer:open", { model: this.model }); } } diff --git a/app/assets/javascripts/discourse/tests/acceptance/composer-test.js b/app/assets/javascripts/discourse/tests/acceptance/composer-test.js index 3f81b4b619c..52e76708580 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/composer-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/composer-test.js @@ -616,7 +616,7 @@ acceptance("Composer", function (needs) { await click(".topic-post:nth-of-type(1) button.reply"); await menu.expand(); - await menu.selectRowByValue("toggleWhisper"); + await menu.selectRowByName(I18n.t("composer.toggle_whisper")); assert.strictEqual( count(".composer-actions svg.d-icon-far-eye-slash"), @@ -625,7 +625,7 @@ acceptance("Composer", function (needs) { ); await menu.expand(); - await menu.selectRowByValue("toggleWhisper"); + await menu.selectRowByName(I18n.t("composer.toggle_whisper")); assert.ok( !exists(".composer-actions svg.d-icon-far-eye-slash"), @@ -633,14 +633,14 @@ acceptance("Composer", function (needs) { ); await menu.expand(); - await menu.selectRowByValue("toggleWhisper"); + await menu.selectRowByName(I18n.t("composer.toggle_whisper")); await click(".toggle-fullscreen"); await menu.expand(); assert.ok( - menu.rowByValue("toggleWhisper").exists(), + menu.rowByName(I18n.t("composer.toggle_whisper")).exists(), "whisper toggling is still present when going fullscreen" ); }); @@ -728,8 +728,9 @@ acceptance("Composer", function (needs) { await click(".topic-post:nth-of-type(1) button.reply"); await selectKit(".toolbar-popup-menu-options").expand(); - await selectKit(".toolbar-popup-menu-options").selectRowByValue( - "toggleWhisper" + + await selectKit(".toolbar-popup-menu-options").selectRowByName( + I18n.t("composer.toggle_whisper") ); assert.strictEqual( @@ -748,8 +749,8 @@ acceptance("Composer", function (needs) { ); await selectKit(".toolbar-popup-menu-options").expand(); - await selectKit(".toolbar-popup-menu-options").selectRowByValue( - "toggleInvisible" + await selectKit(".toolbar-popup-menu-options").selectRowByName( + I18n.t("composer.toggle_unlisted") ); assert.ok( diff --git a/app/assets/javascripts/select-kit/addon/components/toolbar-popup-menu-options.js b/app/assets/javascripts/select-kit/addon/components/toolbar-popup-menu-options.js index 02a074e99b8..e6859a9118e 100644 --- a/app/assets/javascripts/select-kit/addon/components/toolbar-popup-menu-options.js +++ b/app/assets/javascripts/select-kit/addon/components/toolbar-popup-menu-options.js @@ -20,7 +20,7 @@ export default DropdownSelectBoxComponent.extend({ return { icon: content.icon, name: I18n.t(content.label), - id: content.action, + id: { name: content.name, action: content.action }, }; } }) diff --git a/plugins/discourse-presence/test/javascripts/acceptance/discourse-presence-test.js b/plugins/discourse-presence/test/javascripts/acceptance/discourse-presence-test.js index 2a12aa69ef7..a21f6ca1312 100644 --- a/plugins/discourse-presence/test/javascripts/acceptance/discourse-presence-test.js +++ b/plugins/discourse-presence/test/javascripts/acceptance/discourse-presence-test.js @@ -13,6 +13,7 @@ import { query, } from "discourse/tests/helpers/qunit-helpers"; import selectKit from "discourse/tests/helpers/select-kit-helper"; +import I18n from "discourse-i18n"; acceptance("Discourse Presence Plugin", function (needs) { needs.user({ whisperer: true }); @@ -82,7 +83,7 @@ acceptance("Discourse Presence Plugin", function (needs) { const menu = selectKit(".toolbar-popup-menu-options"); await menu.expand(); - await menu.selectRowByValue("toggleWhisper"); + await menu.selectRowByName(I18n.t("composer.toggle_whisper")); assert.strictEqual( count(".composer-actions svg.d-icon-far-eye-slash"),