|
|
@ -4,13 +4,19 @@ import { get_slot_scope } from './shared/get_slot_scope';
|
|
|
|
import { boolean_attributes } from './shared/boolean_attributes';
|
|
|
|
import { boolean_attributes } from './shared/boolean_attributes';
|
|
|
|
import Renderer, { RenderOptions } from '../Renderer';
|
|
|
|
import Renderer, { RenderOptions } from '../Renderer';
|
|
|
|
import Element from '../../nodes/Element';
|
|
|
|
import Element from '../../nodes/Element';
|
|
|
|
|
|
|
|
import { INode } from '../../nodes/interfaces';
|
|
|
|
import { x } from 'code-red';
|
|
|
|
import { x } from 'code-red';
|
|
|
|
import Expression from '../../nodes/shared/Expression';
|
|
|
|
import Expression from '../../nodes/shared/Expression';
|
|
|
|
import fix_attribute_casing from '../../render_dom/wrappers/Element/fix_attribute_casing';
|
|
|
|
import fix_attribute_casing from '../../render_dom/wrappers/Element/fix_attribute_casing';
|
|
|
|
|
|
|
|
import { trim_end, trim_start } from '../../../utils/trim';
|
|
|
|
|
|
|
|
import { link } from '../../../utils/link';
|
|
|
|
|
|
|
|
|
|
|
|
export default function(node: Element, renderer: Renderer, options: RenderOptions & {
|
|
|
|
export default function(node: Element, renderer: Renderer, options: RenderOptions & {
|
|
|
|
slot_scopes: Map<any, any>;
|
|
|
|
slot_scopes: Map<any, any>;
|
|
|
|
}) {
|
|
|
|
}) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const children = remove_whitespace_children(node.children, node.next);
|
|
|
|
|
|
|
|
|
|
|
|
// awkward special case
|
|
|
|
// awkward special case
|
|
|
|
let node_contents;
|
|
|
|
let node_contents;
|
|
|
|
|
|
|
|
|
|
|
@ -134,7 +140,7 @@ export default function(node: Element, renderer: Renderer, options: RenderOption
|
|
|
|
if (node_contents !== undefined) {
|
|
|
|
if (node_contents !== undefined) {
|
|
|
|
if (contenteditable) {
|
|
|
|
if (contenteditable) {
|
|
|
|
renderer.push();
|
|
|
|
renderer.push();
|
|
|
|
renderer.render(node.children, options);
|
|
|
|
renderer.render(children, options);
|
|
|
|
const result = renderer.pop();
|
|
|
|
const result = renderer.pop();
|
|
|
|
|
|
|
|
|
|
|
|
renderer.add_expression(x`($$value => $$value === void 0 ? ${result} : $$value)(${node_contents})`);
|
|
|
|
renderer.add_expression(x`($$value => $$value === void 0 ? ${result} : $$value)(${node_contents})`);
|
|
|
@ -146,7 +152,7 @@ export default function(node: Element, renderer: Renderer, options: RenderOption
|
|
|
|
renderer.add_string(`</${node.name}>`);
|
|
|
|
renderer.add_string(`</${node.name}>`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (slot && nearest_inline_component) {
|
|
|
|
} else if (slot && nearest_inline_component) {
|
|
|
|
renderer.render(node.children, options);
|
|
|
|
renderer.render(children, options);
|
|
|
|
|
|
|
|
|
|
|
|
if (!is_void(node.name)) {
|
|
|
|
if (!is_void(node.name)) {
|
|
|
|
renderer.add_string(`</${node.name}>`);
|
|
|
|
renderer.add_string(`</${node.name}>`);
|
|
|
@ -164,10 +170,80 @@ export default function(node: Element, renderer: Renderer, options: RenderOption
|
|
|
|
output: renderer.pop()
|
|
|
|
output: renderer.pop()
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
renderer.render(node.children, options);
|
|
|
|
renderer.render(children, options);
|
|
|
|
|
|
|
|
|
|
|
|
if (!is_void(node.name)) {
|
|
|
|
if (!is_void(node.name)) {
|
|
|
|
renderer.add_string(`</${node.name}>`);
|
|
|
|
renderer.add_string(`</${node.name}>`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// similar logic from `compile/render_dom/wrappers/Fragment`
|
|
|
|
|
|
|
|
// We want to remove trailing whitespace inside an element/component/block,
|
|
|
|
|
|
|
|
// *unless* there is no whitespace between this node and its next sibling
|
|
|
|
|
|
|
|
function remove_whitespace_children(children: INode[], next?: INode): INode[] {
|
|
|
|
|
|
|
|
const nodes: INode[] = [];
|
|
|
|
|
|
|
|
let last_child: INode;
|
|
|
|
|
|
|
|
let i = children.length;
|
|
|
|
|
|
|
|
while (i--) {
|
|
|
|
|
|
|
|
const child = children[i];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (child.type === 'Text') {
|
|
|
|
|
|
|
|
if (child.should_skip()) {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let { data } = child;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (nodes.length === 0) {
|
|
|
|
|
|
|
|
const should_trim = next
|
|
|
|
|
|
|
|
? next.type === 'Text' &&
|
|
|
|
|
|
|
|
/^\s/.test(next.data) &&
|
|
|
|
|
|
|
|
trimmable_at(child, next)
|
|
|
|
|
|
|
|
: !child.has_ancestor('EachBlock');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (should_trim) {
|
|
|
|
|
|
|
|
data = trim_end(data);
|
|
|
|
|
|
|
|
if (!data) continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// glue text nodes (which could e.g. be separated by comments) together
|
|
|
|
|
|
|
|
if (last_child && last_child.type === 'Text') {
|
|
|
|
|
|
|
|
last_child.data = data + last_child.data;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nodes.unshift(child);
|
|
|
|
|
|
|
|
link(last_child, last_child = child);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
nodes.unshift(child);
|
|
|
|
|
|
|
|
link(last_child, last_child = child);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const first = nodes[0];
|
|
|
|
|
|
|
|
if (first && first.type === 'Text') {
|
|
|
|
|
|
|
|
first.data = trim_start(first.data);
|
|
|
|
|
|
|
|
if (!first.data) {
|
|
|
|
|
|
|
|
first.var = null;
|
|
|
|
|
|
|
|
nodes.shift();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (nodes[0]) {
|
|
|
|
|
|
|
|
nodes[0].prev = null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return nodes;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function trimmable_at(child: INode, next_sibling: INode): boolean {
|
|
|
|
|
|
|
|
// Whitespace is trimmable if one of the following is true:
|
|
|
|
|
|
|
|
// The child and its sibling share a common nearest each block (not at an each block boundary)
|
|
|
|
|
|
|
|
// The next sibling's previous node is an each block
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
|
|
next_sibling.find_nearest(/EachBlock/) ===
|
|
|
|
|
|
|
|
child.find_nearest(/EachBlock/) || next_sibling.prev.type === 'EachBlock'
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|