mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
DEV: Support appending glimmer into existing post elements (#20164)
Previously `helper.renderGlimmer()` would always create a new wrapper element. This is required when using `RenderGlimmer` within widgets, where there is no direct access to DOM elements. However, when using within `decorateCooked`, we have the ability to pass an existing element to `{{#in-element}}` and have the glimmer content appended with no additional wrappers.
This commit makes the `renderInto` accept an existing DOM node for this 'append' behavior. The previous 'new wrapper element' behaviour is still used when a string is passed.
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
{{#each this._childComponents as |info|}}
|
{{#each this._childComponents as |info|}}
|
||||||
{{#in-element info.element}}
|
{{#in-element info.element insertBefore=null}}
|
||||||
<info.component @data={{info.data}} />
|
<info.component @data={{info.data}} />
|
||||||
{{/in-element}}
|
{{/in-element}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
@@ -118,24 +118,31 @@ class DecoratorHelper {
|
|||||||
* import { hbs } from "ember-cli-htmlbars";
|
* import { hbs } from "ember-cli-htmlbars";
|
||||||
*
|
*
|
||||||
* api.decorateCookedElement((cooked, helper) => {
|
* api.decorateCookedElement((cooked, helper) => {
|
||||||
|
* // Generate a new element with glimmer rendered inside
|
||||||
* const glimmerElement = helper.renderGlimmer(
|
* const glimmerElement = helper.renderGlimmer(
|
||||||
* "div.my-wrapper-class",
|
* "div.my-wrapper-class",
|
||||||
* hbs`<DButton @icon={{@data.param}} @translatedLabel="Hello world from Glimmer Component"/>`,
|
* hbs`<DButton @icon={{@data.param}} @translatedLabel="Hello world from Glimmer Component"/>`,
|
||||||
* { param: "user-plus" }
|
* { param: "user-plus" }
|
||||||
* );
|
* );
|
||||||
* cooked.appendChild(glimmerElement);
|
* cooked.appendChild(glimmerElement);
|
||||||
|
*
|
||||||
|
* // Or append to an existing element
|
||||||
|
* helper.renderGlimmer(
|
||||||
|
* cooked.querySelector(".some-container"),
|
||||||
|
* hbs`I will be appended to some-container`
|
||||||
|
* );
|
||||||
* }, { onlyStream: true, id: "my-id" });
|
* }, { onlyStream: true, id: "my-id" });
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
renderGlimmer(tagName, template, data) {
|
renderGlimmer(renderInto, template, data) {
|
||||||
if (!this.widget.postContentsDestroyCallbacks) {
|
if (!this.widget.postContentsDestroyCallbacks) {
|
||||||
throw "renderGlimmer can only be used in the context of a post";
|
throw "renderGlimmer can only be used in the context of a post";
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderGlimmer = new RenderGlimmer(
|
const renderGlimmer = new RenderGlimmer(
|
||||||
this.widget,
|
this.widget,
|
||||||
tagName,
|
renderInto,
|
||||||
template,
|
template,
|
||||||
data
|
data
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -78,25 +78,30 @@ export default class RenderGlimmer {
|
|||||||
/**
|
/**
|
||||||
* Create a RenderGlimmer instance
|
* Create a RenderGlimmer instance
|
||||||
* @param widget - the widget instance which is rendering this content
|
* @param widget - the widget instance which is rendering this content
|
||||||
* @param tagName - tagName for the wrapper element (e.g. `div.my-class`)
|
* @param renderInto - a string describing a new wrapper element (e.g. `div.my-class`),
|
||||||
|
* or an existing HTML element to append content into.
|
||||||
* @param template - a glimmer template compiled via ember-cli-htmlbars
|
* @param template - a glimmer template compiled via ember-cli-htmlbars
|
||||||
* @param data - will be made available at `@data` in your template
|
* @param data - will be made available at `@data` in your template
|
||||||
*/
|
*/
|
||||||
constructor(widget, tagName, template, data) {
|
constructor(widget, renderInto, template, data) {
|
||||||
assert(
|
assert(
|
||||||
"`template` should be a template compiled via `ember-cli-htmlbars`",
|
"`template` should be a template compiled via `ember-cli-htmlbars`",
|
||||||
template.name === "factory"
|
template.name === "factory"
|
||||||
);
|
);
|
||||||
this.tagName = tagName;
|
this.renderInto = renderInto;
|
||||||
this.widget = widget;
|
this.widget = widget;
|
||||||
this.template = template;
|
this.template = template;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
const [type, ...classNames] = this.tagName.split(".");
|
if (this.renderInto instanceof Element) {
|
||||||
this.element = document.createElement(type);
|
this.element = this.renderInto;
|
||||||
this.element.classList.add(...classNames);
|
} else {
|
||||||
|
const [type, ...classNames] = this.renderInto.split(".");
|
||||||
|
this.element = document.createElement(type);
|
||||||
|
this.element.classList.add(...classNames);
|
||||||
|
}
|
||||||
this.connectComponent();
|
this.connectComponent();
|
||||||
return this.element;
|
return this.element;
|
||||||
}
|
}
|
||||||
@@ -110,7 +115,7 @@ export default class RenderGlimmer {
|
|||||||
update(prev) {
|
update(prev) {
|
||||||
if (
|
if (
|
||||||
prev.template.__id !== this.template.__id ||
|
prev.template.__id !== this.template.__id ||
|
||||||
prev.tagName !== this.tagName
|
prev.renderInto !== this.renderInto
|
||||||
) {
|
) {
|
||||||
// Totally different component, but the widget framework guessed it was the
|
// Totally different component, but the widget framework guessed it was the
|
||||||
// same widget. Destroy old component and re-init the new one.
|
// same widget. Destroy old component and re-init the new one.
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ acceptance("Acceptance | decorateCookedElement", function () {
|
|||||||
if (helper.getModel().post_number !== 1) {
|
if (helper.getModel().post_number !== 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
cooked.innerHTML =
|
||||||
|
"<div class='existing-wrapper'>Some existing content</div>";
|
||||||
|
|
||||||
|
// Create new wrapper element and append
|
||||||
cooked.appendChild(
|
cooked.appendChild(
|
||||||
helper.renderGlimmer(
|
helper.renderGlimmer(
|
||||||
"div.glimmer-wrapper",
|
"div.glimmer-wrapper",
|
||||||
@@ -35,6 +39,12 @@ acceptance("Acceptance | decorateCookedElement", function () {
|
|||||||
{ component: DemoComponent }
|
{ component: DemoComponent }
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Append to existing element
|
||||||
|
helper.renderGlimmer(
|
||||||
|
cooked.querySelector(".existing-wrapper"),
|
||||||
|
hbs` with more content from glimmer`
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -42,6 +52,12 @@ acceptance("Acceptance | decorateCookedElement", function () {
|
|||||||
|
|
||||||
assert.dom("div.glimmer-wrapper").exists();
|
assert.dom("div.glimmer-wrapper").exists();
|
||||||
assert.dom("span.glimmer-component-content").exists();
|
assert.dom("span.glimmer-component-content").exists();
|
||||||
|
|
||||||
|
assert.dom("div.existing-wrapper").exists();
|
||||||
|
assert
|
||||||
|
.dom("div.existing-wrapper")
|
||||||
|
.hasText("Some existing content with more content from glimmer");
|
||||||
|
|
||||||
assert.deepEqual(DemoComponent.eventLog, ["created"]);
|
assert.deepEqual(DemoComponent.eventLog, ["created"]);
|
||||||
|
|
||||||
await visit("/");
|
await visit("/");
|
||||||
|
|||||||
Reference in New Issue
Block a user