Skip to content

Commit

Permalink
fix dynamic html bug
Browse files Browse the repository at this point in the history
  • Loading branch information
trueadm committed Apr 17, 2024
1 parent f3510c8 commit c2dfda1
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 4 deletions.
33 changes: 29 additions & 4 deletions packages/svelte/src/internal/client/dom/blocks/html.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,51 @@
import { derived } from '../../reactivity/deriveds.js';
import { render_effect } from '../../reactivity/effects.js';
import { current_effect, get } from '../../runtime.js';
import { is_array } from '../../utils.js';
import { hydrate_nodes, hydrating } from '../hydration.js';
import { create_fragment_from_html, remove } from '../reconciler.js';
import { push_template_node } from '../template.js';

/**
* @param {import('#client').Effect} effect
* @param {(Element | Comment | Text)[]} to_remove
* @returns {void}
*/
function remove_from_parent_effect(effect, to_remove) {
const dom = effect.dom;

if (is_array(dom)) {
for (let i = dom.length - 1; i >= 0; i--) {
if (to_remove.includes(dom[i])) {
dom.splice(i, 1);
break;
}
}
} else if (dom !== null && to_remove.includes(dom)) {
effect.dom = null;
}
}

/**
* @param {Element | Text | Comment} anchor
* @param {() => string} get_value
* @param {boolean} svg
* @returns {void}
*/
export function html(anchor, get_value, svg) {
var effect = anchor.parentNode !== current_effect?.dom ? current_effect : null;
const parent_effect = anchor.parentNode !== current_effect?.dom ? current_effect : null;
let value = derived(get_value);

render_effect(() => {
var dom = html_to_dom(anchor, effect, get(value), svg);
effect = null;
var dom = html_to_dom(anchor, parent_effect, get(value), svg);

if (dom) {
return () => remove(dom);
return () => {
if (parent_effect !== null) {
remove_from_parent_effect(parent_effect, is_array(dom) ? dom : [dom]);
}
remove(dom);
};
}
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { flushSync } from '../../../../src/index-client';
import { test } from '../../test';

export default test({
html: `<button>add item</button><button>make span</button><button>reverse</button>`,

async test({ assert, target }) {
const [btn1, btn2, btn3] = target.querySelectorAll('button');

flushSync(() => {
btn1?.click();
btn1?.click();
btn1?.click();
});

assert.htmlEqual(
target.innerHTML,
`<button>add item</button><button>make span</button><button>reverse</button><div>Item 1</div><div>Item 2</div><div>Item 3</div>`
);

flushSync(() => {
btn2?.click();
});

assert.htmlEqual(
target.innerHTML,
`<button>add item</button><button>make span</button><button>reverse</button><span>Item 1</span><span>Item 2</span><span>Item 3</span>`
);

flushSync(() => {
btn3?.click();
});

assert.htmlEqual(
target.innerHTML,
`<button>add item</button><button>make span</button><button>reverse</button><span>Item 3</span><span>Item 2</span><span>Item 1</span>`
);
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<script>
let items = $state([]);
function add_item() {
items.push({
id: items.length,
text: 'Item ' + (items.length + 1),
html: '<div>Item ' + (items.length + 1) + '</div>',
dom: null,
})
}
function make_span() {
items.forEach(item => {
item.html = item.html.replace(/div/g, 'span')
})
}
function reverse() {
items.reverse();
}
</script>

<button on:click={add_item}>add item</button>
<button on:click={make_span}>make span</button>
<button on:click={reverse}>reverse</button>

{#each items as item (item.id)}
{@html item.html}
{/each}

0 comments on commit c2dfda1

Please sign in to comment.