renderer.title

pull/16797/head
Rich Harris 6 days ago
parent 31d326451e
commit b0900ee435

@ -14,6 +14,8 @@ export function TitleElement(node, context) {
template.push(b.literal('</title>'));
context.state.init.push(
b.stmt(b.call('$.build_title', b.id('$$renderer'), b.thunk(b.block(build_template(template)))))
b.stmt(
b.call('$$renderer.title', b.arrow([b.id('$$renderer')], b.block(build_template(template))))
)
);
}

@ -493,32 +493,3 @@ export function derived(fn) {
return updated_value;
};
}
/**
* Since your document can only have one `title`, we have to have some sort of algorithm for determining
* which one "wins". To do this, we perform a depth-first comparison of where the title was encountered --
* later ones "win" over earlier ones, regardless of what order the promises resolve in. To accomodate this, we:
* - Figure out where we are in the content tree (`get_path`)
* - Render the title in its own child so that it has a defined "slot" in the renderer
* - Compact that spot so that we get the entire rendered contents of the title
* - Attempt to set the global title (this is where the "wins" logic based on the path happens)
*
* TODO we could optimize this by not even rendering the title if the path wouldn't be accepted
*
* @param {Renderer} renderer
* @param {((renderer: Renderer) => void | Promise<void>)} children
*/
export function build_title(renderer, children) {
const path = renderer.get_path();
const i = renderer.length;
renderer.child(children);
renderer.compact({
start: i,
fn: ({ head }) => {
renderer.global.set_title(head, path);
// since we can only ever render the title in this chunk, and title rendering is handled specially,
// we can just ditch the results after we've saved them globally
return { head: '', body: '' };
}
});
}

@ -222,6 +222,34 @@ export class Renderer {
}
}
/**
* @param {(renderer: Renderer) => void} fn
*/
title(fn) {
const path = this.get_path();
/** @param {string} head */
const close = (head) => {
this.global.set_title(head, path);
};
this.child((renderer) => {
const r = new Renderer(renderer.global, renderer);
fn(r);
const content = { head: '', body: '' };
if (renderer.global.mode === 'async') {
return Renderer.#collect_content_async([r], 'body', content).then(() => {
close(content.head);
});
} else {
Renderer.#collect_content([r], 'body', content);
close(content.head);
}
});
}
/**
* @param {string | (() => Promise<string>)} content
*/

Loading…
Cancel
Save