Skip to content

Commit

Permalink
FIX: In test mode, initializers were modifying classes over and over
Browse files Browse the repository at this point in the history
This adds a new property, `pluginId` which you can pass to `modifyClass`
which prevent the class from being modified over and over again.

This also includes a fix for polls which was leaking state between tests
which this new functionality exposed.
  • Loading branch information
eviltrout committed Sep 2, 2021
1 parent fa66d1f commit 0976429
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 19 deletions.
39 changes: 37 additions & 2 deletions app/assets/javascripts/discourse/app/lib/plugin-api.js
Expand Up @@ -86,6 +86,25 @@ import { addSearchSuggestion } from "discourse/widgets/search-menu-results";
// If you add any methods to the API ensure you bump up this number
const PLUGIN_API_VERSION = "0.12.2";

// This helper prevents us from applying the same `modifyClass` over and over in test mode.
function canModify(klass, type, resolverName, changes) {
if (!changes.pluginId) {
// eslint-disable-next-line no-console
console.warn(
"To prevent errors, add a `pluginId` key to your changes when calling `modifyClass`"
);
return true;
}

let key = "_" + type + "/" + changes.pluginId + "/" + resolverName;
if (klass.class[key]) {
return false;
} else {
klass.class[key] = 1;
return true;
}
}

class PluginApi {
constructor(version, container) {
this.version = version;
Expand Down Expand Up @@ -138,10 +157,14 @@ class PluginApi {
/**
* Allows you to overwrite or extend methods in a class.
*
* You should add a `pluginId` property to identify your plugin
* to help Discourse reload classes properly.
*
* For example:
*
* ```
* api.modifyClass('controller:composer', {
* pluginId: 'my-plugin',
* actions: {
* newActionHere() { }
* }
Expand All @@ -150,9 +173,15 @@ class PluginApi {
**/
modifyClass(resolverName, changes, opts) {
const klass = this._resolveClass(resolverName, opts);
if (klass) {
if (!klass) {
return;
}

if (canModify(klass, "member", resolverName, changes)) {
delete changes.pluginId;
klass.class.reopen(changes);
}

return klass;
}

Expand All @@ -169,9 +198,15 @@ class PluginApi {
**/
modifyClassStatic(resolverName, changes, opts) {
const klass = this._resolveClass(resolverName, opts);
if (klass) {
if (!klass) {
return;
}

if (canModify(klass, "static", resolverName, changes)) {
delete changes.pluginId;
klass.class.reopenClass(changes);
}

return klass;
}

Expand Down
Expand Up @@ -15,6 +15,7 @@ function initializeDetails(api) {
});

api.modifyClass("controller:composer", {
pluginId: "discourse-details",
actions: {
insertDetails() {
this.toolbarEvent.applySurround(
Expand Down
Expand Up @@ -82,6 +82,7 @@ function initializeDiscourseLocalDates(api) {
});

api.modifyClass("component:d-editor", {
pluginId: "discourse-local-dates",
actions: {
insertDiscourseLocalDate(toolbarEvent) {
showModal("discourse-local-dates-create-modal").setProperties({
Expand Down
@@ -1,19 +1,24 @@
import { ajax } from "discourse/lib/ajax";
import { withPluginApi } from "discourse/lib/plugin-api";

const PLUGIN_ID = "new-user-narrative";

function initialize(api) {
const messageBus = api.container.lookup("message-bus:main");
const currentUser = api.getCurrentUser();
const appEvents = api.container.lookup("service:app-events");

api.modifyClass("component:site-header", {
pluginId: PLUGIN_ID,
didInsertElement() {
this._super(...arguments);
this.dispatch("header:search-context-trigger", "header");
},
});

api.modifyClass("controller:topic", {
pluginId: PLUGIN_ID,

_togglePostBookmark(post) {
// if we are talking to discobot then any bookmarks should just
// be created without reminder options, to streamline the new user
Expand Down
Expand Up @@ -4,6 +4,7 @@ import { withPluginApi } from "discourse/lib/plugin-api";

function initializePollUIBuilder(api) {
api.modifyClass("controller:composer", {
pluginId: "discourse-poll-ui-builder",
@discourseComputed(
"siteSettings.poll_enabled",
"siteSettings.poll_minimum_trust_level_to_create",
Expand Down
38 changes: 21 additions & 17 deletions plugins/poll/assets/javascripts/initializers/extend-for-poll.js.es6
Expand Up @@ -4,10 +4,30 @@ import { getRegister } from "discourse-common/lib/get-owner";
import { observes } from "discourse-common/utils/decorators";
import { withPluginApi } from "discourse/lib/plugin-api";

const PLUGIN_ID = "discourse-poll";
let _glued = [];
let _interval = null;

function rerender() {
_glued.forEach((g) => g.queueRerender());
}

function cleanUpPolls() {
if (_interval) {
clearInterval(_interval);
_interval = null;
}

_glued.forEach((g) => g.cleanUp());
_glued = [];
}

function initializePolls(api) {
const register = getRegister(api);
cleanUpPolls();

api.modifyClass("controller:topic", {
pluginId: PLUGIN_ID,
subscribe() {
this._super(...arguments);
this.messageBus.subscribe("/polls/" + this.get("model.id"), (msg) => {
Expand All @@ -23,14 +43,8 @@ function initializePolls(api) {
},
});

let _glued = [];
let _interval = null;

function rerender() {
_glued.forEach((g) => g.queueRerender());
}

api.modifyClass("model:post", {
pluginId: PLUGIN_ID,
_polls: null,
pollsObject: null,

Expand Down Expand Up @@ -110,16 +124,6 @@ function initializePolls(api) {
});
}

function cleanUpPolls() {
if (_interval) {
clearInterval(_interval);
_interval = null;
}

_glued.forEach((g) => g.cleanUp());
_glued = [];
}

api.includePostAttributes("polls", "polls_votes");
api.decorateCooked(attachPolls, { onlyStream: true, id: "discourse-poll" });
api.cleanupStream(cleanUpPolls);
Expand Down

0 comments on commit 0976429

Please sign in to comment.