DEV: Introduce API for rendering Glimmer inside posts (#20140)
`helper.renderGlimmer` will return an HTML element which can be added to a post's `cooked` Example usage: ``` import { hbs } from "ember-cli-htmlbars"; api.decorateCookedElement((cooked, helper) => { const glimmerElement = helper.renderGlimmer( "div.my-wrapper-class", hbs`<DButton @icon={{@data.param}} @translatedLabel="Hello world from Glimmer Component"/>`, { param: "user-plus" } ); cooked.appendChild(glimmerElement); }, { onlyStream: true, id: "my-id" }); ``` See `widgets/render-glimmer.js` for more detailed usage information.
This commit is contained in:
parent
adbf69c300
commit
ca2b2d034f
|
@ -2,6 +2,7 @@ import Connector from "discourse/widgets/connector";
|
||||||
import PostCooked from "discourse/widgets/post-cooked";
|
import PostCooked from "discourse/widgets/post-cooked";
|
||||||
import RawHtml from "discourse/widgets/raw-html";
|
import RawHtml from "discourse/widgets/raw-html";
|
||||||
import { h } from "virtual-dom";
|
import { h } from "virtual-dom";
|
||||||
|
import RenderGlimmer from "discourse/widgets/render-glimmer";
|
||||||
|
|
||||||
class DecoratorHelper {
|
class DecoratorHelper {
|
||||||
constructor(widget, attrs, state) {
|
constructor(widget, attrs, state) {
|
||||||
|
@ -106,6 +107,44 @@ class DecoratorHelper {
|
||||||
connect(details) {
|
connect(details) {
|
||||||
return new Connector(this.widget, details);
|
return new Connector(this.widget, details);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an element containing a rendered glimmer template. For full usage instructions,
|
||||||
|
* see `widgets/render-glimmer.js`.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* import { hbs } from "ember-cli-htmlbars";
|
||||||
|
*
|
||||||
|
* api.decorateCookedElement((cooked, helper) => {
|
||||||
|
* const glimmerElement = helper.renderGlimmer(
|
||||||
|
* "div.my-wrapper-class",
|
||||||
|
* hbs`<DButton @icon={{@data.param}} @translatedLabel="Hello world from Glimmer Component"/>`,
|
||||||
|
* { param: "user-plus" }
|
||||||
|
* );
|
||||||
|
* cooked.appendChild(glimmerElement);
|
||||||
|
* }, { onlyStream: true, id: "my-id" });
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
renderGlimmer(tagName, template, data) {
|
||||||
|
if (!this.widget.postContentsDestroyCallbacks) {
|
||||||
|
throw "renderGlimmer can only be used in the context of a post";
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderGlimmer = new RenderGlimmer(
|
||||||
|
this.widget,
|
||||||
|
tagName,
|
||||||
|
template,
|
||||||
|
data
|
||||||
|
);
|
||||||
|
renderGlimmer.init();
|
||||||
|
this.widget.postContentsDestroyCallbacks.push(
|
||||||
|
renderGlimmer.destroy.bind(renderGlimmer)
|
||||||
|
);
|
||||||
|
return renderGlimmer.element;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DecoratorHelper.prototype.h = h;
|
DecoratorHelper.prototype.h = h;
|
||||||
|
|
||||||
|
|
|
@ -629,6 +629,14 @@ createWidget("post-contents", {
|
||||||
controller.setProperties({ topic, post });
|
controller.setProperties({ topic, post });
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.postContentsDestroyCallbacks = [];
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.postContentsDestroyCallbacks.forEach((c) => c());
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
createWidget("post-notice", {
|
createWidget("post-notice", {
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { hbs } from "ember-cli-htmlbars";
|
||||||
|
import { setComponentTemplate } from "@ember/component";
|
||||||
|
import { test } from "qunit";
|
||||||
|
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||||
|
import { visit } from "@ember/test-helpers";
|
||||||
|
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||||
|
|
||||||
|
acceptance("Acceptance | decorateCookedElement", function () {
|
||||||
|
test("decorator with renderGlimmer works", async function (assert) {
|
||||||
|
class DemoComponent extends Component {
|
||||||
|
static eventLog = [];
|
||||||
|
constructor() {
|
||||||
|
DemoComponent.eventLog.push("created");
|
||||||
|
return super(...arguments);
|
||||||
|
}
|
||||||
|
willDestroy() {
|
||||||
|
DemoComponent.eventLog.push("willDestroy");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setComponentTemplate(
|
||||||
|
hbs`<span class='glimmer-component-content'>Hello world</span>`,
|
||||||
|
DemoComponent
|
||||||
|
);
|
||||||
|
|
||||||
|
withPluginApi(0, (api) => {
|
||||||
|
api.decorateCookedElement((cooked, helper) => {
|
||||||
|
if (helper.getModel().post_number !== 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cooked.appendChild(
|
||||||
|
helper.renderGlimmer(
|
||||||
|
"div.glimmer-wrapper",
|
||||||
|
hbs`<@data.component />`,
|
||||||
|
{ component: DemoComponent }
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await visit("/t/internationalization-localization/280");
|
||||||
|
|
||||||
|
assert.dom("div.glimmer-wrapper").exists();
|
||||||
|
assert.dom("span.glimmer-component-content").exists();
|
||||||
|
assert.deepEqual(DemoComponent.eventLog, ["created"]);
|
||||||
|
|
||||||
|
await visit("/");
|
||||||
|
|
||||||
|
assert.deepEqual(DemoComponent.eventLog, ["created", "willDestroy"]);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue