Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: set innerHTML #258

Merged
merged 2 commits into from
Mar 11, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@builder.io/qwik",
"version": "0.0.18-0",
"version": "0.0.18-1",
"description": "An Open-Source sub-framework designed with a focus on server-side-rendering, lazy-loading, and styling/animation.",
"scripts": {
"build": "node scripts --tsc --build --api --platform-binding --wasm",
2 changes: 1 addition & 1 deletion src/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "create-qwik",
"version": "0.0.18-0",
"version": "0.0.18-1",
"description": "Interactive CLI and API for generating Qwik projects.",
"bin": {
"create-qwik": "create-qwik"
45 changes: 30 additions & 15 deletions src/core/render/cursor.ts
Original file line number Diff line number Diff line change
@@ -11,7 +11,8 @@ import { NodeType } from '../util/types';
import { intToStr } from '../object/store';
import { EMPTY_ARRAY } from '../util/flyweight';
import { SkipRerender } from './jsx/host.public';
import { logDebug, logError } from '../util/log';
import { logDebug, logError, logWarn } from '../util/log';
import { qDev } from '../util/qdev';

type KeyToIndexMap = { [key: string]: number };

@@ -248,7 +249,8 @@ export function patchVnode(
}

let promise: ValueOrPromise<void>;
const dirty = updateProperties(ctx, elm as Element, vnode.props, isSvg);
const props = vnode.props;
const dirty = updateProperties(ctx, elm as Element, props, isSvg);
const isSlot = tag === 'q:slot';
if (isSvg && vnode.type === 'foreignObject') {
isSvg = false;
@@ -289,6 +291,13 @@ export function patchVnode(
});
});
}
const setsInnerHTML = props && 'innerHTML' in props;
if (setsInnerHTML) {
if (qDev && ch.length > 0) {
logWarn('Node can not have children when innerHTML is set');
}
return;
}
return then(promise, () => {
const mode = isSlot ? 'fallback' : 'default';
return smartUpdateChildren(ctx, elm, ch, mode, isSvg);
@@ -327,7 +336,7 @@ function removeVnodes(
for (; startIdx <= endIdx; ++startIdx) {
const ch = nodes[startIdx];
assertDefined(ch);
removeNode(ctx, parentElm, ch);
removeNode(ctx, ch);
}
}

@@ -374,7 +383,7 @@ function removeTemplates(ctx: RenderContext, slotMaps: SlotMaps) {
Object.keys(slotMaps.templates).forEach((key) => {
const template = slotMaps.templates[key]!;
if (template && slotMaps.slots[key] !== undefined) {
removeNode(ctx, template.parentNode!, template);
removeNode(ctx, template);
slotMaps.templates[key] = undefined;
}
});
@@ -437,11 +446,11 @@ function createElm(ctx: RenderContext, vnode: JSXNode, isSvg: boolean): ValueOrP
isSvg = tag === 'svg';
}

const data = vnode.props;
const props = vnode.props;
const elm = (vnode.elm = createElement(ctx, tag, isSvg));
const isComponent = isComponentNode(vnode);
setKey(elm, vnode.key);
updateProperties(ctx, elm, data, isSvg);
updateProperties(ctx, elm, props, isSvg);

if (isSvg && tag === 'foreignObject') {
isSvg = false;
@@ -468,6 +477,14 @@ function createElm(ctx: RenderContext, vnode: JSXNode, isSvg: boolean): ValueOrP
classlistAdd(ctx, elm, hostStyleTag);
}
wait = componentCtx.render(ctx);
} else {
const setsInnerHTML = props && 'innerHTML' in props;
if (setsInnerHTML) {
if (qDev && vnode.children.length > 0) {
logWarn('Node can not have children when innerHTML is set');
}
return elm;
}
}
return then(wait, () => {
let children = vnode.children;
@@ -560,17 +577,10 @@ const checkBeforeAssign: PropHandler = (ctx, elm, prop, newValue) => {
return true;
};

const setInnerHTML: PropHandler = (ctx, elm, prop, newValue) => {
setProperty(ctx, elm, prop, newValue);
setAttribute(ctx, elm, 'q:static', '');
return true;
};

const PROP_HANDLER_MAP: Record<string, PropHandler> = {
style: handleStyle,
value: checkBeforeAssign,
checked: checkBeforeAssign,
innerHTML: setInnerHTML,
};

const ALLOWS_PROPS = ['className', 'style', 'id', 'q:slot'];
@@ -773,9 +783,14 @@ function prepend(ctx: RenderContext, parent: Element, newChild: Node) {
});
}

function removeNode(ctx: RenderContext, parent: Node, el: Node) {
function removeNode(ctx: RenderContext, el: Node) {
const fn = () => {
parent.removeChild(el);
const parent = el.parentNode;
if (parent) {
parent.removeChild(el);
} else if (qDev) {
logWarn('Trying to remove component already removed', el);
}
};
ctx.operations.push({
el: el,
17 changes: 14 additions & 3 deletions src/core/render/render.unit.tsx
Original file line number Diff line number Diff line change
@@ -136,11 +136,18 @@ describe('render', () => {
await render(fixture.host, <InnerHTMLComponent />);
expectRendered(
<div>
{/<node:.*>/}
<div>
<span>WORKS</span>
</div>
{/<\/node:.*>/}
</div>
);
notifyRender(fixture.host.firstElementChild!);
await getTestPlatform(fixture.document).flush();
expectRendered(
<div>
<div>
<span>WORKS</span>
</div>
</div>
);
});
@@ -691,6 +698,10 @@ function delay(time: number) {
export const InnerHTMLComponent = component$(async () => {
return $(() => {
const html = '<span>WORKS</span>';
return <div innerHTML={html}></div>;
return (
<div innerHTML={html}>
<div>not rendered</div>
</div>
);
});
});