DEV: Plugin API for customizing text in the composer conditionally
Co-authored-by: Isaac Janzen <issac.janzen@discourse.org>
This commit is contained in:
parent
3eb737c014
commit
bef5223672
|
@ -24,8 +24,15 @@ export default Component.extend({
|
||||||
options: alias("model.replyOptions"),
|
options: alias("model.replyOptions"),
|
||||||
action: alias("model.action"),
|
action: alias("model.action"),
|
||||||
|
|
||||||
@discourseComputed("options", "action")
|
// Note we update when some other attributes like tag/category change to allow
|
||||||
|
// text customizations to use those.
|
||||||
|
@discourseComputed("options", "action", "model.tags", "model.category")
|
||||||
actionTitle(opts, action) {
|
actionTitle(opts, action) {
|
||||||
|
let result = this.model.customizationFor("actionTitle");
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
if (TITLES[action]) {
|
if (TITLES[action]) {
|
||||||
return I18n.t(TITLES[action]);
|
return I18n.t(TITLES[action]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -240,13 +240,22 @@ export default Controller.extend({
|
||||||
return SAVE_ICONS[modelAction];
|
return SAVE_ICONS[modelAction];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Note we update when some other attributes like tag/category change to allow
|
||||||
|
// text customizations to use those.
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"model.action",
|
"model.action",
|
||||||
"isWhispering",
|
"isWhispering",
|
||||||
"model.editConflict",
|
"model.editConflict",
|
||||||
"model.privateMessage"
|
"model.privateMessage",
|
||||||
|
"model.tags",
|
||||||
|
"model.category"
|
||||||
)
|
)
|
||||||
saveLabel(modelAction, isWhispering, editConflict, privateMessage) {
|
saveLabel(modelAction, isWhispering, editConflict, privateMessage) {
|
||||||
|
let result = this.model.customizationFor("saveLabel");
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
if (editConflict) {
|
if (editConflict) {
|
||||||
return "composer.overwrite_edit";
|
return "composer.overwrite_edit";
|
||||||
} else if (isWhispering) {
|
} else if (isWhispering) {
|
||||||
|
|
|
@ -37,7 +37,9 @@ import {
|
||||||
registerIconRenderer,
|
registerIconRenderer,
|
||||||
replaceIcon,
|
replaceIcon,
|
||||||
} from "discourse-common/lib/icon-library";
|
} from "discourse-common/lib/icon-library";
|
||||||
import Composer from "discourse/models/composer";
|
import Composer, {
|
||||||
|
registerCustomizationCallback,
|
||||||
|
} from "discourse/models/composer";
|
||||||
import DiscourseBanner from "discourse/components/discourse-banner";
|
import DiscourseBanner from "discourse/components/discourse-banner";
|
||||||
import KeyboardShortcuts from "discourse/lib/keyboard-shortcuts";
|
import KeyboardShortcuts from "discourse/lib/keyboard-shortcuts";
|
||||||
import Sharing from "discourse/lib/sharing";
|
import Sharing from "discourse/lib/sharing";
|
||||||
|
@ -87,7 +89,7 @@ import { addSearchSuggestion } from "discourse/widgets/search-menu-results";
|
||||||
import { CUSTOM_USER_SEARCH_OPTIONS } from "select-kit/components/user-chooser";
|
import { CUSTOM_USER_SEARCH_OPTIONS } from "select-kit/components/user-chooser";
|
||||||
|
|
||||||
// If you add any methods to the API ensure you bump up this number
|
// If you add any methods to the API ensure you bump up this number
|
||||||
const PLUGIN_API_VERSION = "0.12.3";
|
const PLUGIN_API_VERSION = "0.12.5";
|
||||||
|
|
||||||
// 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) {
|
||||||
|
@ -1471,6 +1473,28 @@ class PluginApi {
|
||||||
{ ignoreMissing: true }
|
{ ignoreMissing: true }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Support for customizing the composer text. By providing a callback. Callbacks should
|
||||||
|
* return `null` or `undefined` if you don't need a customization based on the current state.
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* api.customizeComposerText({
|
||||||
|
* actionTitle(model) {
|
||||||
|
* if (model.hello) {
|
||||||
|
* return "hello.world";
|
||||||
|
* }
|
||||||
|
* },
|
||||||
|
*
|
||||||
|
* saveLabel(model) {
|
||||||
|
* return "my.custom_save_label_key";
|
||||||
|
* }
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
customizeComposerText(callbacks) {
|
||||||
|
registerCustomizationCallback(callbacks);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// from http://stackoverflow.com/questions/6832596/how-to-compare-software-version-number-using-js-only-number
|
// from http://stackoverflow.com/questions/6832596/how-to-compare-software-version-number-using-js-only-number
|
||||||
|
|
|
@ -24,6 +24,15 @@ import { isEmpty } from "@ember/utils";
|
||||||
import { propertyNotEqual } from "discourse/lib/computed";
|
import { propertyNotEqual } from "discourse/lib/computed";
|
||||||
import { throwAjaxError } from "discourse/lib/ajax-error";
|
import { throwAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
|
||||||
|
let _customizations = [];
|
||||||
|
export function registerCustomizationCallback(cb) {
|
||||||
|
_customizations.push(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resetComposerCustomizations() {
|
||||||
|
_customizations = [];
|
||||||
|
}
|
||||||
|
|
||||||
// The actions the composer can take
|
// The actions the composer can take
|
||||||
export const CREATE_TOPIC = "createTopic",
|
export const CREATE_TOPIC = "createTopic",
|
||||||
CREATE_SHARED_DRAFT = "createSharedDraft",
|
CREATE_SHARED_DRAFT = "createSharedDraft",
|
||||||
|
@ -1305,6 +1314,18 @@ const Composer = RestModel.extend({
|
||||||
this.set("draftSaving", false);
|
this.set("draftSaving", false);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
customizationFor(type) {
|
||||||
|
for (let i = 0; i < _customizations.length; i++) {
|
||||||
|
let cb = _customizations[i][type];
|
||||||
|
if (cb) {
|
||||||
|
let result = cb(this);
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
Composer.reopenClass({
|
Composer.reopenClass({
|
||||||
|
|
|
@ -12,7 +12,8 @@ import { click, currentURL, fillIn, visit } from "@ember/test-helpers";
|
||||||
import { skip, test } from "qunit";
|
import { skip, test } from "qunit";
|
||||||
import Draft from "discourse/models/draft";
|
import Draft from "discourse/models/draft";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import { NEW_TOPIC_KEY } from "discourse/models/composer";
|
import { CREATE_TOPIC, NEW_TOPIC_KEY } from "discourse/models/composer";
|
||||||
|
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||||
import { Promise } from "rsvp";
|
import { Promise } from "rsvp";
|
||||||
import { run } from "@ember/runloop";
|
import { run } from "@ember/runloop";
|
||||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||||
|
@ -1008,3 +1009,51 @@ acceptance("Composer", function (needs) {
|
||||||
assert.notOk(exists(".discard-draft-modal .save-draft"));
|
assert.notOk(exists(".discard-draft-modal .save-draft"));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
acceptance("Composer - Customizations", function (needs) {
|
||||||
|
needs.user();
|
||||||
|
needs.site({ can_tag_topics: true });
|
||||||
|
|
||||||
|
function customComposerAction(composer) {
|
||||||
|
return (
|
||||||
|
(composer.tags || []).indexOf("monkey") !== -1 &&
|
||||||
|
composer.action === CREATE_TOPIC
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
needs.hooks.beforeEach(() => {
|
||||||
|
withPluginApi("0.8.14", (api) => {
|
||||||
|
api.customizeComposerText({
|
||||||
|
actionTitle(model) {
|
||||||
|
if (customComposerAction(model)) {
|
||||||
|
return "custom text";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
saveLabel(model) {
|
||||||
|
if (customComposerAction(model)) {
|
||||||
|
return "composer.emoji";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Supports text customization", async function (assert) {
|
||||||
|
await visit("/");
|
||||||
|
await click("#create-topic");
|
||||||
|
assert.equal(query(".action-title").innerText, I18n.t("topic.create_long"));
|
||||||
|
assert.equal(
|
||||||
|
query(".save-or-cancel button").innerText,
|
||||||
|
I18n.t("composer.create_topic")
|
||||||
|
);
|
||||||
|
const tags = selectKit(".mini-tag-chooser");
|
||||||
|
await tags.expand();
|
||||||
|
await tags.selectRowByValue("monkey");
|
||||||
|
assert.equal(query(".action-title").innerText, "custom text");
|
||||||
|
assert.equal(
|
||||||
|
query(".save-or-cancel button").innerText,
|
||||||
|
I18n.t("composer.emoji")
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -37,6 +37,7 @@ import { resetUsernameDecorators } from "discourse/helpers/decorate-username-sel
|
||||||
import { resetWidgetCleanCallbacks } from "discourse/components/mount-widget";
|
import { resetWidgetCleanCallbacks } from "discourse/components/mount-widget";
|
||||||
import { resetUserSearchCache } from "discourse/lib/user-search";
|
import { resetUserSearchCache } from "discourse/lib/user-search";
|
||||||
import { resetCardClickListenerSelector } from "discourse/mixins/card-contents-base";
|
import { resetCardClickListenerSelector } from "discourse/mixins/card-contents-base";
|
||||||
|
import { resetComposerCustomizations } from "discourse/models/composer";
|
||||||
import sessionFixtures from "discourse/tests/fixtures/session-fixtures";
|
import sessionFixtures from "discourse/tests/fixtures/session-fixtures";
|
||||||
import { setTopicList } from "discourse/lib/topic-list-tracker";
|
import { setTopicList } from "discourse/lib/topic-list-tracker";
|
||||||
import sinon from "sinon";
|
import sinon from "sinon";
|
||||||
|
@ -280,6 +281,7 @@ export function acceptance(name, optionsOrCallback) {
|
||||||
resetCustomPostMessageCallbacks();
|
resetCustomPostMessageCallbacks();
|
||||||
resetUserSearchCache();
|
resetUserSearchCache();
|
||||||
resetCardClickListenerSelector();
|
resetCardClickListenerSelector();
|
||||||
|
resetComposerCustomizations();
|
||||||
resetPostMenuExtraButtons();
|
resetPostMenuExtraButtons();
|
||||||
clearNavItems();
|
clearNavItems();
|
||||||
setTopicList(null);
|
setTopicList(null);
|
||||||
|
|
Loading…
Reference in New Issue