Compare commits
2 commits
0d9cf1ed26
...
2ea4f461d3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ea4f461d3 | ||
|
|
5e2e709496 |
5 changed files with 84 additions and 24 deletions
|
|
@ -41,13 +41,16 @@ DEFAULT_LANG = "en"
|
|||
THEME = "theme"
|
||||
|
||||
# The plugin reads the allowed elements and attributes from the Mews DTD and
|
||||
# brings every page inside that subset. It only touches files ending .xhtml,
|
||||
# so everything has to be written out under that suffix.
|
||||
# brings every page inside that subset.
|
||||
PLUGINS = ["pelican.plugins.mews"]
|
||||
|
||||
ARTICLE_URL = ARTICLE_SAVE_AS = "{{slug}}.xhtml"
|
||||
PAGE_URL = PAGE_SAVE_AS = "{{slug}}.xhtml"
|
||||
INDEX_SAVE_AS = "index.xhtml"
|
||||
# This whole site is Mews, so its pages are plain .html: a server sends those
|
||||
# as text/html, which section 7.1 asks for so a small markup error still shows
|
||||
# as a page, and index.html is the directory index everywhere. The plugin
|
||||
# defaults to .xhtml instead, for sites that are only partly Mews.
|
||||
MEWS_SUFFIX = ".html"
|
||||
ARTICLE_URL = ARTICLE_SAVE_AS = "{{slug}}.html"
|
||||
PAGE_URL = PAGE_SAVE_AS = "{{slug}}.html"
|
||||
|
||||
# Markdown has to produce XML for the plugin to parse. Tables and definition
|
||||
# lists are both in the Mews subset but need their extensions turned on.
|
||||
|
|
@ -59,7 +62,11 @@ MARKDOWN = {{
|
|||
}},
|
||||
}}
|
||||
|
||||
# Mews pages carry no author styling, so there is nothing for these to show.
|
||||
# Every page written under MEWS_SUFFIX goes through the plugin, and Pelican
|
||||
# falls back to its own HTML templates for these when the theme has none. They
|
||||
# have nothing to show on a site like this, so they stay off; give them
|
||||
# templates in theme/templates/ if you want them.
|
||||
DIRECT_TEMPLATES = ["index"]
|
||||
AUTHOR_SAVE_AS = CATEGORY_SAVE_AS = TAG_SAVE_AS = ""
|
||||
AUTHORS_SAVE_AS = CATEGORIES_SAVE_AS = TAGS_SAVE_AS = ARCHIVES_SAVE_AS = ""
|
||||
# Pelican writes several feeds by default and they are all broken until
|
||||
|
|
@ -115,7 +122,7 @@ ARTICLE = """\
|
|||
{% block content %}
|
||||
<h1>{{ article.title }}</h1>
|
||||
{{ article.content }}
|
||||
<p><a href="index.xhtml">All posts</a></p>
|
||||
<p><a href="index.html">All posts</a></p>
|
||||
{% endblock %}
|
||||
"""
|
||||
|
||||
|
|
@ -125,7 +132,7 @@ PAGE = """\
|
|||
{% block content %}
|
||||
<h1>{{ page.title }}</h1>
|
||||
{{ page.content }}
|
||||
<p><a href="index.xhtml">All posts</a></p>
|
||||
<p><a href="index.html">All posts</a></p>
|
||||
{% endblock %}
|
||||
"""
|
||||
|
||||
|
|
@ -157,7 +164,8 @@ A Mews site. The pages follow [Mews Profile 0.1](https://mews.page/spec/0.1).
|
|||
uv run pelican content
|
||||
```
|
||||
|
||||
The finished pages land in `output/`. To work on it with a reload on save:
|
||||
The finished pages land in `output/`, as plain `.html` that any web server
|
||||
serves correctly with no configuration. To work on it with a reload on save:
|
||||
|
||||
```shell
|
||||
uv run pelican --autoreload --listen content
|
||||
|
|
@ -165,12 +173,7 @@ uv run pelican --autoreload --listen content
|
|||
|
||||
## Publish it
|
||||
|
||||
Copy `output/` to any web server. Two things are worth setting:
|
||||
|
||||
- Serve `.xhtml` files as `text/html`. Section 7.1 of the spec asks for that,
|
||||
so a browser still shows a page carrying a small markup error.
|
||||
- Make `index.xhtml` the directory index, since the plugin only processes
|
||||
files under that suffix. In Caddy: `file_server {{ index index.xhtml }}`.
|
||||
Copy `output/` to any web server. Nothing to configure.
|
||||
|
||||
## Subscribe to it
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ Three optional settings:
|
|||
| `MEWS_STRICT` | `False` | Fail the build on content outside the subset instead of stripping it. Removals are always logged either way. |
|
||||
| `MEWS_CSS_DIR` | `"css"` | Directory below the output root where `mews-0.1.css` is copied. Themes see the resulting path as the `MEWS_CSS` global. |
|
||||
| `MEWS_OUTPUT_PATH` | unset | Put the finished pages in this folder instead of `OUTPUT_PATH`. |
|
||||
| `MEWS_SUFFIX` | `".xhtml"` | Which written files are Mews pages. Set it to `".html"` on a site that is Mews throughout, and save your pages under that suffix too: servers send `.xhtml` as `application/xhtml+xml`, which makes a browser parse the page as XML and fail outright on a small markup error, while section 7.1 asks for `text/html` so the page still shows. `index.html` is also the directory index everywhere, which `index.xhtml` is not. Note that `.html` puts every page Pelican writes through the plugin, including the index, tag and archive pages it falls back to when the theme has no template for them, so give those a Mews template or switch them off with `DIRECT_TEMPLATES` and the matching `*_SAVE_AS` settings. |
|
||||
|
||||
### Rendering beside an existing blog
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,13 @@ LOGGER = logging.getLogger(__name__)
|
|||
|
||||
CSS_NAME = "mews-0.1.css"
|
||||
DEFAULT_CSS_DIR = "css"
|
||||
XHTML_SUFFIX = ".xhtml"
|
||||
# Which files Pelican writes are Mews pages. The default keeps the plugin off
|
||||
# everything else, so it can run on a site that also produces ordinary HTML.
|
||||
# A site that is Mews throughout wants ".html" instead: servers send .xhtml as
|
||||
# application/xhtml+xml, which makes a browser parse as XML and fail hard on a
|
||||
# small markup error, and section 7.1 asks for text/html precisely to avoid
|
||||
# that. Set MEWS_SUFFIX to choose.
|
||||
DEFAULT_SUFFIX = ".xhtml"
|
||||
|
||||
ALLOWLIST = parse_allowlist(
|
||||
files(__package__).joinpath("dtd", "mews.dtd").read_text(encoding="utf-8")
|
||||
|
|
@ -67,6 +73,12 @@ def _on_initialized(pelican) -> None:
|
|||
overrides.append(templates)
|
||||
|
||||
|
||||
def _suffix() -> str:
|
||||
"""Return the file extension a Mews page is written under, with its dot."""
|
||||
suffix = str(_settings.get("MEWS_SUFFIX", DEFAULT_SUFFIX)).strip()
|
||||
return suffix if suffix.startswith(".") else f".{suffix}"
|
||||
|
||||
|
||||
def _on_generator_init(generator) -> None:
|
||||
css_dir = generator.settings.get("MEWS_CSS_DIR", DEFAULT_CSS_DIR)
|
||||
generator.env.globals["MEWS_CSS"] = f"{css_dir}/{CSS_NAME}"
|
||||
|
|
@ -74,7 +86,7 @@ def _on_generator_init(generator) -> None:
|
|||
|
||||
def _on_content_written(path, **_) -> None:
|
||||
file = Path(path)
|
||||
if file.suffix != XHTML_SUFFIX:
|
||||
if file.suffix != _suffix():
|
||||
return
|
||||
try:
|
||||
tree, doctype = parse_page(file.read_bytes())
|
||||
|
|
|
|||
|
|
@ -28,6 +28,44 @@ def test_written_page_matches_expected(tmp_path, case):
|
|||
assert normalize(page) == normalize(expected)
|
||||
|
||||
|
||||
def test_a_site_can_choose_its_own_suffix(tmp_path):
|
||||
"""A site that is Mews throughout writes .html, so servers send text/html."""
|
||||
output = build_case(
|
||||
"basic",
|
||||
tmp_path,
|
||||
MEWS_SUFFIX=".html",
|
||||
PAGE_SAVE_AS="{slug}.html",
|
||||
PAGE_URL="{slug}.html",
|
||||
# With .html the plugin sees every page Pelican writes, including the
|
||||
# index, tags and archives it falls back to when the theme has no
|
||||
# template for them. Those fallbacks are HTML, not XML, so a site
|
||||
# using .html has to give every direct template a Mews template or
|
||||
# switch the lot off, as here.
|
||||
DIRECT_TEMPLATES=[],
|
||||
)
|
||||
page = (output / "page.html").read_bytes()
|
||||
assert normalize(page) == normalize(
|
||||
(FIXTURES / "basic" / "expected.xhtml").read_bytes()
|
||||
)
|
||||
|
||||
|
||||
def test_the_default_suffix_leaves_other_html_alone(tmp_path):
|
||||
"""Left at its default the plugin must not touch a plain HTML page."""
|
||||
output = build_case(
|
||||
"strip",
|
||||
tmp_path,
|
||||
PAGE_SAVE_AS="{slug}.html",
|
||||
PAGE_URL="{slug}.html",
|
||||
INDEX_SAVE_AS="",
|
||||
)
|
||||
# The strip fixture carries a <span>, a class and a comment, all three of
|
||||
# which the plugin removes. Untouched, every one of them survives.
|
||||
written = (output / "page.html").read_bytes()
|
||||
assert b"<span" in written
|
||||
assert b'class="big"' in written
|
||||
assert b"stray comment" in written
|
||||
|
||||
|
||||
@pytest.mark.parametrize("case", ["basic", "strip", "cssdir", "structure"])
|
||||
def test_css_is_copied(tmp_path, case):
|
||||
"""The bundled stylesheet lands under the configured directory."""
|
||||
|
|
|
|||
|
|
@ -35,9 +35,15 @@ def test_the_settings_are_valid_python(tmp_path):
|
|||
)
|
||||
assert settings["SITENAME"] == "Signal Bars"
|
||||
assert settings["PLUGINS"] == ["pelican.plugins.mews"]
|
||||
# The plugin only touches this suffix, so everything has to be saved under it.
|
||||
assert settings["ARTICLE_SAVE_AS"].endswith(".xhtml")
|
||||
assert settings["INDEX_SAVE_AS"].endswith(".xhtml")
|
||||
# A site that is Mews throughout writes plain .html: servers send that as
|
||||
# text/html (section 7.1) and index.html is the directory index everywhere.
|
||||
# The suffix the plugin acts on has to agree with where pages are saved.
|
||||
assert settings["MEWS_SUFFIX"] == ".html"
|
||||
assert settings["ARTICLE_SAVE_AS"].endswith(".html")
|
||||
assert settings["PAGE_SAVE_AS"].endswith(".html")
|
||||
# Pelican falls back to its own HTML for any direct template the theme
|
||||
# lacks, and with .html the plugin would choke on it.
|
||||
assert settings["DIRECT_TEMPLATES"] == ["index"]
|
||||
assert settings["MARKDOWN"]["output_format"] == "xhtml"
|
||||
|
||||
|
||||
|
|
@ -62,11 +68,11 @@ def test_the_scaffolded_site_builds_conforming_pages(tmp_path):
|
|||
check=False,
|
||||
)
|
||||
assert built.returncode == 0, built.stderr
|
||||
pages = sorted((site / "output").glob("*.xhtml"))
|
||||
assert [p.name for p in pages] == ["first-post.xhtml", "index.xhtml"]
|
||||
pages = sorted((site / "output").glob("*.html"))
|
||||
assert [p.name for p in pages] == ["first-post.html", "index.html"]
|
||||
for page in pages:
|
||||
report = validate_file(str(page))
|
||||
assert report.conforms, "\n".join(str(f) for f in report.failures)
|
||||
# Section 6.1: the index has to be subscribable.
|
||||
index = (site / "output" / "index.xhtml").read_text()
|
||||
assert '<li><a href="first-post.xhtml">' in index
|
||||
index = (site / "output" / "index.html").read_text()
|
||||
assert '<li><a href="first-post.html">' in index
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue