|
|
|
@ -2,7 +2,6 @@ import Renderer from '../Renderer';
|
|
|
|
|
import Block from '../Block';
|
|
|
|
|
import Tag from './shared/Tag';
|
|
|
|
|
import Wrapper from './shared/Wrapper';
|
|
|
|
|
import deindent from '../../utils/deindent';
|
|
|
|
|
import MustacheTag from '../../nodes/MustacheTag';
|
|
|
|
|
import RawMustacheTag from '../../nodes/RawMustacheTag';
|
|
|
|
|
|
|
|
|
@ -19,95 +18,47 @@ export default class RawMustacheTagWrapper extends Tag {
|
|
|
|
|
this.cannot_use_innerhtml();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render(block: Block, parent_node: string, parent_nodes: string) {
|
|
|
|
|
const name = this.var;
|
|
|
|
|
|
|
|
|
|
render(block: Block, parent_node: string, _parent_nodes: string) {
|
|
|
|
|
const in_head = parent_node === '@_document.head';
|
|
|
|
|
const needs_anchors = !parent_node || in_head;
|
|
|
|
|
|
|
|
|
|
// if in head always needs anchors
|
|
|
|
|
if (in_head) {
|
|
|
|
|
this.prev = null;
|
|
|
|
|
this.next = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO use is_dom_node instead of type === 'Element'?
|
|
|
|
|
const needs_anchor_before = this.prev ? this.prev.node.type !== 'Element' : needs_anchors;
|
|
|
|
|
const needs_anchor_after = this.next ? this.next.node.type !== 'Element' : needs_anchors;
|
|
|
|
|
const can_use_innerhtml = !in_head && parent_node && !this.prev && !this.next;
|
|
|
|
|
|
|
|
|
|
const anchor_before = needs_anchor_before
|
|
|
|
|
? block.get_unique_name(`${name}_before`)
|
|
|
|
|
: (this.prev && this.prev.var) || 'null';
|
|
|
|
|
if (can_use_innerhtml) {
|
|
|
|
|
const insert = content => `${parent_node}.innerHTML = ${content};`;
|
|
|
|
|
|
|
|
|
|
const anchor_after = needs_anchor_after
|
|
|
|
|
? block.get_unique_name(`${name}_after`)
|
|
|
|
|
: (this.next && this.next.var) || 'null';
|
|
|
|
|
|
|
|
|
|
let detach: string;
|
|
|
|
|
let insert: (content: string) => string;
|
|
|
|
|
let use_innerhtml = false;
|
|
|
|
|
const { init } = this.rename_this_method(
|
|
|
|
|
block,
|
|
|
|
|
content => insert(content)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (anchor_before === 'null' && anchor_after === 'null') {
|
|
|
|
|
use_innerhtml = true;
|
|
|
|
|
detach = `${parent_node}.innerHTML = '';`;
|
|
|
|
|
insert = content => `${parent_node}.innerHTML = ${content};`;
|
|
|
|
|
} else if (anchor_before === 'null') {
|
|
|
|
|
detach = `@detach_before(${anchor_after});`;
|
|
|
|
|
insert = content => `${anchor_after}.insertAdjacentHTML("beforebegin", ${content});`;
|
|
|
|
|
} else if (anchor_after === 'null') {
|
|
|
|
|
detach = `@detach_after(${anchor_before});`;
|
|
|
|
|
insert = content => `${anchor_before}.insertAdjacentHTML("afterend", ${content});`;
|
|
|
|
|
} else {
|
|
|
|
|
detach = `@detach_between(${anchor_before}, ${anchor_after});`;
|
|
|
|
|
insert = content => `${anchor_before}.insertAdjacentHTML("afterend", ${content});`;
|
|
|
|
|
block.builders.mount.add_line(insert(init));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { init } = this.rename_this_method(
|
|
|
|
|
block,
|
|
|
|
|
content => deindent`
|
|
|
|
|
${!use_innerhtml && detach}
|
|
|
|
|
${insert(content)}
|
|
|
|
|
`
|
|
|
|
|
);
|
|
|
|
|
else {
|
|
|
|
|
const needs_anchor = in_head || (this.next && !this.next.is_dom_node());
|
|
|
|
|
|
|
|
|
|
// we would have used comments here, but the `insertAdjacentHTML` api only
|
|
|
|
|
// exists for `Element`s.
|
|
|
|
|
if (needs_anchor_before) {
|
|
|
|
|
block.add_element(
|
|
|
|
|
anchor_before,
|
|
|
|
|
`@element('noscript')`,
|
|
|
|
|
parent_nodes && `@element('noscript')`,
|
|
|
|
|
parent_node,
|
|
|
|
|
true
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
const html_tag = block.get_unique_name('html_tag');
|
|
|
|
|
const html_anchor = needs_anchor && block.get_unique_name('html_anchor');
|
|
|
|
|
|
|
|
|
|
block.add_variable(html_tag);
|
|
|
|
|
|
|
|
|
|
function add_anchor_after() {
|
|
|
|
|
block.add_element(
|
|
|
|
|
anchor_after,
|
|
|
|
|
`@element('noscript')`,
|
|
|
|
|
parent_nodes && `@element('noscript')`,
|
|
|
|
|
parent_node
|
|
|
|
|
const { init } = this.rename_this_method(
|
|
|
|
|
block,
|
|
|
|
|
content => `${html_tag}.p(${content});`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (needs_anchor_after && anchor_before === 'null') {
|
|
|
|
|
// anchor_after needs to be in the DOM before we
|
|
|
|
|
// insert the HTML...
|
|
|
|
|
add_anchor_after();
|
|
|
|
|
}
|
|
|
|
|
const anchor = in_head ? 'null' : needs_anchor ? html_anchor : this.next ? this.next.var : 'null';
|
|
|
|
|
|
|
|
|
|
block.builders.mount.add_line(insert(init));
|
|
|
|
|
block.builders.hydrate.add_line(`${html_tag} = new @HtmlTag(${init}, ${anchor});`);
|
|
|
|
|
block.builders.mount.add_line(`${html_tag}.m(${parent_node || '#target'}, anchor);`);
|
|
|
|
|
|
|
|
|
|
if (needs_anchors) {
|
|
|
|
|
block.builders.destroy.add_conditional('detaching', needs_anchor_before
|
|
|
|
|
? `${detach}\n@detach(${anchor_before});`
|
|
|
|
|
: detach);
|
|
|
|
|
}
|
|
|
|
|
if (needs_anchor) {
|
|
|
|
|
block.add_element(html_anchor, '@empty()', '@empty()', parent_node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (needs_anchor_after && anchor_before !== 'null') {
|
|
|
|
|
// ...otherwise it should go afterwards
|
|
|
|
|
add_anchor_after();
|
|
|
|
|
if (!parent_node || in_head) {
|
|
|
|
|
block.builders.destroy.add_conditional('detaching', `${html_tag}.d();`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|