DEV: Plugin API method to replace post-menu buttons (#22995)
This commit is contained in:
parent
5b6493ff4b
commit
1b63e046af
|
@ -8,6 +8,7 @@ import {
|
||||||
addButton,
|
addButton,
|
||||||
apiExtraButtons,
|
apiExtraButtons,
|
||||||
removeButton,
|
removeButton,
|
||||||
|
replaceButton,
|
||||||
} from "discourse/widgets/post-menu";
|
} from "discourse/widgets/post-menu";
|
||||||
import {
|
import {
|
||||||
addExtraIconRenderer,
|
addExtraIconRenderer,
|
||||||
|
@ -129,7 +130,7 @@ import { _addBulkButton } from "discourse/components/modal/topic-bulk-actions";
|
||||||
// based on Semantic Versioning 2.0.0. Please update the changelog at
|
// based on Semantic Versioning 2.0.0. Please update the changelog at
|
||||||
// docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md whenever you change the version
|
// docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md whenever you change the version
|
||||||
// using the format described at https://keepachangelog.com/en/1.0.0/.
|
// using the format described at https://keepachangelog.com/en/1.0.0/.
|
||||||
export const PLUGIN_API_VERSION = "1.8.0";
|
export const PLUGIN_API_VERSION = "1.8.1";
|
||||||
|
|
||||||
// This helper prevents us from applying the same `modifyClass` over and over in test mode.
|
// This helper prevents us from applying the same `modifyClass` over and over in test mode.
|
||||||
function canModify(klass, type, resolverName, changes) {
|
function canModify(klass, type, resolverName, changes) {
|
||||||
|
@ -656,6 +657,26 @@ class PluginApi {
|
||||||
removeButton(name, callback);
|
removeButton(name, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace an existing button with a widget
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* ```
|
||||||
|
* api.replacePostMenuButton("like", {
|
||||||
|
* name: "widget-name",
|
||||||
|
* buildAttrs: (widget) => {
|
||||||
|
* return { post: widget.findAncestorModel() };
|
||||||
|
* },
|
||||||
|
* shouldRender: (widget) => {
|
||||||
|
* const post = widget.findAncestorModel();
|
||||||
|
* return post.id === 1
|
||||||
|
* }
|
||||||
|
* });
|
||||||
|
**/
|
||||||
|
replacePostMenuButton(name, widget) {
|
||||||
|
replaceButton(name, widget);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A hook that is called when the editor toolbar is created. You can
|
* A hook that is called when the editor toolbar is created. You can
|
||||||
* use this to add custom editor buttons.
|
* use this to add custom editor buttons.
|
||||||
|
|
|
@ -20,6 +20,7 @@ const _builders = {};
|
||||||
export let apiExtraButtons = {};
|
export let apiExtraButtons = {};
|
||||||
let _extraButtons = {};
|
let _extraButtons = {};
|
||||||
let _buttonsToRemoveCallbacks = {};
|
let _buttonsToRemoveCallbacks = {};
|
||||||
|
let _buttonsToReplace = {};
|
||||||
|
|
||||||
export function addButton(name, builder) {
|
export function addButton(name, builder) {
|
||||||
_extraButtons[name] = builder;
|
_extraButtons[name] = builder;
|
||||||
|
@ -32,6 +33,7 @@ export function resetPostMenuExtraButtons() {
|
||||||
|
|
||||||
_extraButtons = {};
|
_extraButtons = {};
|
||||||
_buttonsToRemoveCallbacks = {};
|
_buttonsToRemoveCallbacks = {};
|
||||||
|
_buttonsToReplace = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeButton(name, callback) {
|
export function removeButton(name, callback) {
|
||||||
|
@ -40,6 +42,10 @@ export function removeButton(name, callback) {
|
||||||
_buttonsToRemoveCallbacks[name].push(callback || (() => true));
|
_buttonsToRemoveCallbacks[name].push(callback || (() => true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function replaceButton(name, replaceWith) {
|
||||||
|
_buttonsToReplace[name] = replaceWith;
|
||||||
|
}
|
||||||
|
|
||||||
function registerButton(name, builder) {
|
function registerButton(name, builder) {
|
||||||
_builders[name] = builder;
|
_builders[name] = builder;
|
||||||
}
|
}
|
||||||
|
@ -47,17 +53,28 @@ function registerButton(name, builder) {
|
||||||
export function buildButton(name, widget) {
|
export function buildButton(name, widget) {
|
||||||
let { attrs, state, siteSettings, settings, currentUser } = widget;
|
let { attrs, state, siteSettings, settings, currentUser } = widget;
|
||||||
|
|
||||||
let shouldAddButton = true;
|
// Return early if the button is supposed to be removed via the plugin API
|
||||||
|
if (
|
||||||
if (_buttonsToRemoveCallbacks[name]) {
|
_buttonsToRemoveCallbacks[name] &&
|
||||||
shouldAddButton = !_buttonsToRemoveCallbacks[name].some((c) =>
|
_buttonsToRemoveCallbacks[name].some((c) =>
|
||||||
c(attrs, state, siteSettings, settings, currentUser)
|
c(attrs, state, siteSettings, settings, currentUser)
|
||||||
);
|
)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for a button replacement, build and return widget attrs if present
|
||||||
|
let replacement = _buttonsToReplace[name];
|
||||||
|
if (replacement && replacement?.shouldRender(widget)) {
|
||||||
|
return {
|
||||||
|
replaced: true,
|
||||||
|
name: replacement.name,
|
||||||
|
attrs: replacement.buildAttrs(widget),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let builder = _builders[name];
|
let builder = _builders[name];
|
||||||
|
if (builder) {
|
||||||
if (shouldAddButton && builder) {
|
|
||||||
let button = builder(attrs, state, siteSettings, settings, currentUser);
|
let button = builder(attrs, state, siteSettings, settings, currentUser);
|
||||||
if (button && !button.id) {
|
if (button && !button.id) {
|
||||||
button.id = name;
|
button.id = name;
|
||||||
|
@ -438,7 +455,7 @@ registerButton("delete", (attrs) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function replaceButton(buttons, find, replace) {
|
function _replaceButton(buttons, find, replace) {
|
||||||
const idx = buttons.indexOf(find);
|
const idx = buttons.indexOf(find);
|
||||||
if (idx !== -1) {
|
if (idx !== -1) {
|
||||||
buttons[idx] = replace;
|
buttons[idx] = replace;
|
||||||
|
@ -468,6 +485,13 @@ export default createWidget("post-menu", {
|
||||||
|
|
||||||
attachButton(name) {
|
attachButton(name) {
|
||||||
let buttonAtts = buildButton(name, this);
|
let buttonAtts = buildButton(name, this);
|
||||||
|
|
||||||
|
// If the button is replaced via the plugin API, we need to render the
|
||||||
|
// replacement rather than a button
|
||||||
|
if (buttonAtts?.replaced) {
|
||||||
|
return this.attach(buttonAtts.name, buttonAtts.attrs);
|
||||||
|
}
|
||||||
|
|
||||||
if (buttonAtts) {
|
if (buttonAtts) {
|
||||||
let button = this.attach(this.settings.buttonType, buttonAtts);
|
let button = this.attach(this.settings.buttonType, buttonAtts);
|
||||||
if (buttonAtts.before) {
|
if (buttonAtts.before) {
|
||||||
|
@ -509,8 +533,8 @@ export default createWidget("post-menu", {
|
||||||
|
|
||||||
// If the post is a wiki, make Edit more prominent
|
// If the post is a wiki, make Edit more prominent
|
||||||
if (attrs.wiki && attrs.canEdit) {
|
if (attrs.wiki && attrs.canEdit) {
|
||||||
replaceButton(orderedButtons, "edit", "reply-small");
|
_replaceButton(orderedButtons, "edit", "reply-small");
|
||||||
replaceButton(orderedButtons, "reply", "wiki-edit");
|
_replaceButton(orderedButtons, "reply", "wiki-edit");
|
||||||
}
|
}
|
||||||
|
|
||||||
orderedButtons.forEach((i) => {
|
orderedButtons.forEach((i) => {
|
||||||
|
|
|
@ -5,6 +5,8 @@ import { count, exists } from "discourse/tests/helpers/qunit-helpers";
|
||||||
import { hbs } from "ember-cli-htmlbars";
|
import { hbs } from "ember-cli-htmlbars";
|
||||||
import { resetPostMenuExtraButtons } from "discourse/widgets/post-menu";
|
import { resetPostMenuExtraButtons } from "discourse/widgets/post-menu";
|
||||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||||
|
import { createWidget } from "discourse/widgets/widget";
|
||||||
|
import { h } from "virtual-dom";
|
||||||
|
|
||||||
module("Integration | Component | Widget | post-menu", function (hooks) {
|
module("Integration | Component | Widget | post-menu", function (hooks) {
|
||||||
setupRenderingTest(hooks);
|
setupRenderingTest(hooks);
|
||||||
|
@ -88,4 +90,51 @@ module("Integration | Component | Widget | post-menu", function (hooks) {
|
||||||
|
|
||||||
assert.ok(!exists(".actions .reply"), "it removes reply button");
|
assert.ok(!exists(".actions .reply"), "it removes reply button");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
createWidget("post-menu-replacement", {
|
||||||
|
html(attrs) {
|
||||||
|
return h("h1.post-menu-replacement", {}, attrs.id);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
test("buttons are replaced when shouldRender is true", async function (assert) {
|
||||||
|
this.set("args", { id: 1, canCreatePost: true });
|
||||||
|
|
||||||
|
withPluginApi("0.14.0", (api) => {
|
||||||
|
api.replacePostMenuButton("reply", {
|
||||||
|
name: "post-menu-replacement",
|
||||||
|
buildAttrs: (widget) => {
|
||||||
|
return widget.attrs;
|
||||||
|
},
|
||||||
|
shouldRender: (widget) => widget.attrs.id === 1, // true!
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await render(hbs`<MountWidget @widget="post-menu" @args={{this.args}} />`);
|
||||||
|
|
||||||
|
assert.ok(exists("h1.post-menu-replacement"), "replacement is rendered");
|
||||||
|
assert.ok(!exists(".actions .reply"), "reply button is replaced button");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("buttons are not replaced when shouldRender is false", async function (assert) {
|
||||||
|
this.set("args", { id: 1, canCreatePost: true, canRemoveReply: false });
|
||||||
|
|
||||||
|
withPluginApi("0.14.0", (api) => {
|
||||||
|
api.replacePostMenuButton("reply", {
|
||||||
|
name: "post-menu-replacement",
|
||||||
|
buildAttrs: (widget) => {
|
||||||
|
return widget.attrs;
|
||||||
|
},
|
||||||
|
shouldRender: (widget) => widget.attrs.id === 102323948, // false!
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await render(hbs`<MountWidget @widget="post-menu" @args={{this.args}} />`);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
!exists("h1.post-menu-replacement"),
|
||||||
|
"replacement is not rendered"
|
||||||
|
);
|
||||||
|
assert.ok(exists(".actions .reply"), "reply button is present");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,6 +7,20 @@ in this file.
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.8.1] - 2023-08-08
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Adds `replacePostMenuButton` which allows plugins to replace a post menu button with a widget.
|
||||||
|
|
||||||
|
## [1.8.0] - 2023-07-18
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Adds `addSidebarPanel` which is experimental, and adds a Sidebar panel by returning a class which extends from the
|
||||||
|
BaseCustomSidebarPanel class.
|
||||||
|
|
||||||
|
- Adds `setSidebarPanel` which is experimental, and sets the current sidebar panel.
|
||||||
|
|
||||||
## [1.7.1] - 2023-07-18
|
## [1.7.1] - 2023-07-18
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
Loading…
Reference in New Issue