// SYNTHETIC XenForo 2 thread pages for the forum-thread tests. The forum, the // thread, the members and every word are invented; the markup follows the // shape XenForo 2 serves (article.message, .bbWrapper, the attribution header, // the page nav), and one variant is shaped the way a browser's "Save page as" // rewrites a page. export const ORIGIN = "https://forum.example"; export const THREAD_PATH = "/threads/the-teapot-collectors-thread.4242/"; export const THREAD_URL = `${ORIGIN}${THREAD_PATH}`; export type FakePost = { id: number; author: string; userId: number; // Epoch seconds. ts: number; position: number; body: string; editedTs?: number; attachments?: { href: string; name: string }[]; }; export function message(p: FakePost, opts: { savedAssets?: boolean; article?: boolean } = {}): string { const iso = new Date(p.ts * 1000).toISOString().replace(".000Z", "+0000"); const avatar = opts.savedAssets ? `./The Teapot Collectors Thread_files/${p.userId}.jpg` : `/data/avatars/m/0/${p.userId}.jpg?1700000000`; const attachments = p.attachments?.length ? `

Attachments

` : ""; const edited = p.editedTs ? `
Last edited:
` : ""; return `
${p.body}
 
${attachments}
${edited}
`; } export function pageNav(page: number, last: number): string { if (last <= 1) return ""; const items: string[] = []; for (const n of [1, page - 1, page, page + 1, last]) { if (n < 1 || n > last || items.some((i) => i.includes(`>${n}<`))) continue; items.push( ``, ); } return ``; } export function threadPage(opts: { page: number; last: number; posts: FakePost[]; saved?: boolean; title?: string; // An article thread: this post (its first) shown atop the page. article?: FakePost; }): string { const canonical = `${ORIGIN}${THREAD_PATH}${opts.page > 1 ? `page-${opts.page}` : ""}`; const savedComment = opts.saved ? `\n` : ""; // A browser's save keeps the canonical link; the variant drops it so the // saved-from comment is what names the page. const canonicalLink = opts.saved ? "" : ``; return ` ${savedComment} ${opts.title ?? "The Teapot Collectors Thread"}${opts.page > 1 ? ` | Page ${opts.page}` : ""} | Example Forum ${canonicalLink}

Hobby ${opts.title ?? "The Teapot Collectors Thread"}

${pageNav(opts.page, opts.last)}
${opts.article ? message(opts.article, { savedAssets: opts.saved, article: true }) : ""} ${opts.posts.map((p) => message(p, { savedAssets: opts.saved })).join("\n")}
${pageNav(opts.page, opts.last)} `; } // A browser check page of the KiwiFlare kind: no posts, a proof-of-work script // and its marker. export const CHALLENGE_PAGE = ` Checking your browser
Please wait while your browser solves a proof-of-work challenge.
`; export const CAPTCHA_PAGE = ` One more step
`; export const LOGIN_PAGE = ` Log in | Example Forum
You must be logged-in to do that.
`; export const NOT_FOUND_PAGE = ` Oops! We ran into some problems. | Example Forum
The requested thread could not be found.
`; // A body exercising everything the body reader handles. export const RICH_BODY = `
Marigold said:
The blue one is a reproduction.
Look at the glaze.
I disagree, @Marigold.

Here is the catalogue: https://archive.example/AbCd1
And the museum page :)
teapot.jpg
The lid was glued on.
receipt.png `;