NAME

App::FuguWeb::Page - the one chrome around one body fragment

SYNOPSIS

use App::FuguWeb::Page;

my $page = App::FuguWeb::Page->new(
    config   => $config,
    language => $config->language('zh-Hans'),
    footer   => $footer);

$page->write($out, 'zh-hans/install.html', 'Install', $fragment);

my $top = App::FuguWeb::Page->new(config => $config);
my $forward = $top->forward;
$top->write($out, '404.html', 'Not found',
    $top->sections([en => $en], ['zh-Hans' => $zh]));

my $link = App::FuguWeb::Page::relative('keys/index.html',
    'en/index.html');    # ../en/index.html
my $tag = App::FuguWeb::Page::body_lang($entry, $language);

DESCRIPTION

Every source format is reduced to one HTML body fragment, and this class wraps it in the chrome of WEB-CHROME: the head, the header, the navigation, the fragment, and the footer. The layout is fixed. What a project decides is the site name, the languages, the navigation, and the footer prose.

A page takes its path below the site root. "relative" makes each link of the chrome from that path, per WEB-LINKS-1. The place of the path decides the rest of the chrome:

the path                  the page
<tree>/<page>             a tree page of the language of the tree
<page>                    a page of the top level, such as 404.html
<dir>/index.html          the human page of a key directory

The forward page of the top level, index.html, takes a shape of its own, and "forward" writes it.

The class builds the document as characters, with string operations, not with a substitution over a template. A title may therefore hold any character, including the slash and the ampersand that a sed template could not take. The write encodes the document to UTF-8, per WEB-SITE-5.

The em dash between the page title and the site name is not ASCII. It is the character constant EM_DASH, and the encode writes its bytes. The chrome holds no other separator, no <hr> and no class, per WEB-CHROME-5 and D-04. The sheet draws each rule and each separator.

The title, the site name, the name of each language and every navigation label go through "escape_html" in App::FuguWeb.

FUNCTIONS

relative

my $link = App::FuguWeb::Page::relative($from, $to);

The link from the page at the path $from to the file at the path $to, per WEB-LINKS-1. Each path names a file below the site root. The link steps up out of each directory of $from that $to does not share, then down into $to. A query or a fragment of $to stays at the end of the link.

A browser reads a link whose first segment holds a colon as a URL scheme. Such a link takes ./ in front of it, so the link to Fugu::Daemon.3p.html from its own tree is ./Fugu::Daemon.3p.html.

body_lang

my $tag = App::FuguWeb::Page::body_lang($entry, $language);

The tag of the language of the <main> element of the page of one entry of "pages" in App::FuguWeb::Config in the tree of the language, per WEB-LANGUAGE-11. It is the language of the value of the entry. The index marks each part of its own, so the <main> of an index page takes the language of the tree. App::FuguWeb::Site and App::FuguWeb::Check read the language here, so the two agree.

METHODS

new

App::FuguWeb::Page->new(config => $config, language => $language,
    footer => $html)

config is an App::FuguWeb::Config and is required.

language is the App::FuguWeb::Language of the tree whose words the chrome takes, and it defaults to the default language of the site. A page of the top level and the key page take the default language.

footer is the footer fragment of that language, as characters. App::FuguWeb::Site reads it, and a tree page carries it. A page without one carries no footer.

write

$page->write($out, $path, $title, $fragment, %page)

Write the whole page to $out/$path with Fugu::File: the chrome around the fragment, encoded to UTF-8. The fragment goes in unchanged: it is already HTML, from a renderer or from the project's own source directory. The method returns true on success, and undef with a message in the log otherwise. The page arguments are those of "document".

document

$page->document($path, $title, $fragment, body_lang => 'en')

The whole page at the path below the site root, as characters. A caller that writes the file itself, or that holds the page beside other generated bytes, reads the document here and never repeats the chrome. The method dies for a path of more than two segments, because no page of the site sits there.

body_lang is the tag of the language of the fragment, and it defaults to the language of the page. A fragment of another language carries the marks of "THE LANGUAGE OF EACH PART" on the <main> element. The parts of an index page come from more than one language, so App::FuguWeb::Site passes the language of the tree for it. "body" in App::FuguWeb::Index marks each part of another language.

forward

my $html = $page->forward;

The forward page of the top level, index.html, as characters, per WEB-TOP-1 and WEB-TOP-2. It is a page of the language of the page object, so the caller makes the object with the default language. A meta refresh forwards to the entry page of the default tree, and the page loads nothing, per D-01:

<head>
<meta charset="utf-8">
<meta http-equiv="refresh" content="0; url=en/index.html">
<title>Example</title>
<link rel="canonical" href="https://example.org/">
<link rel="alternate" hreflang="en" href="https://example.org/en/index.html">
<link rel="alternate" hreflang="de" href="https://example.org/de/index.html">
<link rel="alternate" hreflang="x-default" href="https://example.org/">
</head>
<body>
<ul>
<li><a href="en/index.html" hreflang="en" lang="en">English</a></li>
<li><a href="de/index.html" hreflang="de" lang="de">Deutsch</a></li>
</ul>
</body>

The title is the site name. The canonical link is the bare url, and the link of each language goes to the entry page of that language. On a site of more than one language, the body holds the list of the languages. Each link goes to the entry page of its language, and no link is the current one. On a site of one language, the body holds one link to the entry page, with the site name as its text.

sections

my $main = $page->sections([en => $en], ['zh-Hans' => $zh]);

The <main> part of the top-level 404.html, per WEB-TOP-5. Each body is an array reference of the tag of the language of its text, and the body. Each body sits in its own <section>, in order, with the marks of its language, per WEB-LANGUAGE-11. The body goes in unchanged, so the caller fits it first with "not_found" in App::FuguWeb::Fragment, per WEB-TOP-6.

<section>
<h1>Not found</h1>
</section>
<section lang="zh-Hans">
...
</section>

THE TREE PAGE

A tree page takes the whole chrome, per WEB-CHROME-1 to WEB-CHROME-7:

<head>
<meta charset="utf-8">
<meta name="viewport" ...>
<title>...</title>
<link rel="canonical" href="https://example.org/en/install.html">
<link rel="alternate" hreflang="en" href="https://example.org/en/install.html">
<link rel="alternate" hreflang="de" href="https://example.org/de/install.html">
<link rel="alternate" hreflang="x-default" href="https://example.org/">
<link rel="stylesheet" href="../style.css">
</head>
<body>
<header>
<a href="index.html">Example</a>
<ul>
<li><a href="install.html" hreflang="en" lang="en" aria-current="page">English</a></li>
<li><a href="../de/install.html" hreflang="de" lang="de">Deutsch</a></li>
</ul>
</header>
<nav>
<ul>
<li><a href="index.html">Home</a></li>
<li><a href="install.html" aria-current="page">Install</a></li>
</ul>
</nav>
<main>
...
</main>
<footer>
...
</footer>

The title is the page title, an em dash, and the site name of the language. The head names the page itself, the same page in each language, and the forward page, per WEB-CHROME-6. Each href is the url of the description, then the path of the target page. The forward page is the bare url.

The header links the entry page of the tree, with the site name of the language as its text. On a site of more than one language, the list of the languages follows it, in the order of the declaration. Each link goes to the same page in that language. Its text is the name of the language, and the tag is its lang and its hreflang. A language of another direction than the page also gives its dir. The link of the language of the page carries aria-current="page".

The nav holds one list of the nav entries of the tree, in the order of the description. A relative href names a page of the tree, and the link goes from the page to that page. An absolute URL and a root-absolute path pass unchanged, per WEB-LINKS-2. The entry whose href names the page carries aria-current="page", with or without the ./ in front of it. A description with no nav entry gives no nav.

THE KEY PAGE

The human page of a key directory, <dir>/index.html, is a page of en, because its own words are English, per WEB-CHROME-8. Its head holds the charset, the viewport, the title and the stylesheet link. The title is the English page title alone, so it holds the words of one language. The head names no page of WEB-CHROME-6.

The header holds the site link alone, to the entry page of the default tree. The nav holds the entries of the default tree, and no entry is the current one. Each link of the chrome steps out of the key directory, as in ../en/index.html. The page carries no footer.

THE PAGE OF THE TOP LEVEL

A page of the top level is a page of the default language, and its chrome links the default tree, as in en/index.html. Its head holds a <base> before the title, and its href is "url_path" in App::FuguWeb::Config. A host serves the top-level 404.html at each path that no file answers, and the base makes each relative link of the page resolve from the site root. The head names no page of WEB-CHROME-6, and the page carries no footer.

On a site of more than one language, the list of the languages follows the site link, per WEB-TOP-4. The page belongs to no tree, so each link goes to the entry page of its language, and no link is the current one.

THE LANGUAGE OF EACH PART

The <html> element of a page carries the tag of its language as lang, and dir="rtl" when that language is right to left, per WEB-LANGUAGE-10.

A part of the chrome whose text comes from another language than the page carries the marks of that language, per WEB-LANGUAGE-11: the tag as lang, and its direction as dir when the two directions differ. The part is the site link of the header, the link of a navigation label, the <main> of a body, the <footer>, or a <section> of the top-level 404.html.

<a href="manuals.html" lang="en" dir="ltr">Manuals</a>

THE OPTIONAL FOOTER

The footer setting of the description names the footer fragment, and a language block can name the fragment of its language. A project without one gets no <footer> element: an empty footer is a gap, not chrome.

A tree page carries the footer, and no other page does, per WEB-CHROME-7 and WEB-KEYS-32. The prose is the project's own, and this class copies it in unchanged. A relative link inside it resolves against the directory of the page. Inside a tree it names a page of that tree. On the key page it would name a file of the key directory, and on a page of the top level a file of the root. The writer of the fragment named neither.

SEE ALSO

App::FuguWeb, App::FuguWeb::Config, App::FuguWeb::Language, App::FuguWeb::Site, Fugu::File

AUTHOR

Dick Olsson <hi@senzilla.io>