fix: ship the real DTD in the Pelican plugin
This commit is contained in:
parent
f54d350216
commit
884300f3cf
8 changed files with 483 additions and 74 deletions
|
|
@ -10,9 +10,10 @@ well-formed UTF-8 XML with the XHTML namespace on `<html>`. The plugin also
|
|||
copies the Mews stylesheet into the output tree and gives themes a
|
||||
`MEWS_CSS` global plus the `mews/head.html` partial.
|
||||
|
||||
The bundled `pelican/plugins/mews/dtd/mews.dtd` is a minimal placeholder.
|
||||
Replace it with the real Mews Profile DTD when it is available; the plugin
|
||||
picks up the change without any code edit.
|
||||
The subset comes from `pelican/plugins/mews/dtd/mews.dtd`, which is a copy of
|
||||
the Mews Profile 0.1 DTD. Only element and attribute names are read from it, so
|
||||
the plugin lists none of them in code: change the DTD and the allowlist changes
|
||||
with it.
|
||||
|
||||
## Install
|
||||
|
||||
|
|
|
|||
|
|
@ -1,87 +1,396 @@
|
|||
<!-- Placeholder for the Mews subset definition. The real allowlist comes
|
||||
from the Mews Profile DTD; replace this file when it is available.
|
||||
Only element and attribute names are read; content models are
|
||||
illustrative. -->
|
||||
<!-- Mews Profile 0.1 DTD
|
||||
Published at mews.page/dtd/mews-0.1.dtd. Browsers and clients must not
|
||||
fetch this file.
|
||||
|
||||
<!ENTITY % common
|
||||
"id ID #IMPLIED
|
||||
title CDATA #IMPLIED
|
||||
xml:lang NMTOKEN #IMPLIED">
|
||||
XHTML Mobile Profile 1.2 restricted as in the Mews Profile
|
||||
Specification 0.1 section 4, extended with lang and dir (section 3).
|
||||
Maintained by hand and checked against the XHTML Mobile 1.2 driver,
|
||||
xhtml-mobile12.dtd (OMA-SUP-DTD_xhtml_mobile12-V1_2-20080331-A), by
|
||||
check_dtd.py. It cannot be generated by stripping the driver: the
|
||||
driver declares no elements itself, attribute lists only ever add,
|
||||
and the rules below do not exist in XHTML-MP to be kept.
|
||||
|
||||
<!ELEMENT html (head, body) >
|
||||
<!ATTLIST html
|
||||
xmlns CDATA #FIXED "http://www.w3.org/1999/xhtml"
|
||||
lang NMTOKEN #IMPLIED
|
||||
dir (ltr | rtl) #IMPLIED
|
||||
%common;
|
||||
This file is standalone: it declares every element and attribute
|
||||
itself, so validation never depends on the Open Mobile Alliance's or
|
||||
W3C's servers. Pages keep the XHTML-MP doctype (section 3.1); only
|
||||
validators use this file (section 9.1).
|
||||
|
||||
Encoded here: the permitted elements and attributes (4.1), the head
|
||||
rules (3.3), the body variant classes (5.3) and the ban on nested
|
||||
tables (4.2). 51 elements are kept from XHTML Mobile 1.2. Dropped:
|
||||
acronym, base, big, button, div, legend, noscript, object, param,
|
||||
script, small, span, style, sub, sup, tt. Event attributes and the
|
||||
style attribute are omitted entirely.
|
||||
-->
|
||||
|
||||
<!-- Datatypes (as in XHTML Modularization) -->
|
||||
<!ENTITY % Text.datatype "CDATA" >
|
||||
<!ENTITY % URI.datatype "CDATA" >
|
||||
<!ENTITY % Number.datatype "CDATA" >
|
||||
<!ENTITY % LanguageCode.datatype "NMTOKEN" >
|
||||
<!ENTITY % Character.datatype "CDATA" >
|
||||
|
||||
<!-- Common attributes. id, title, xml:lang, lang and dir are permitted
|
||||
on every element in the body (SPEC.md 4.1); lang and dir are the Mews
|
||||
extensions over XHTML-MP (SPEC.md 3). -->
|
||||
<!ENTITY % id.attrib "id ID #IMPLIED" >
|
||||
<!ENTITY % title.attrib "title CDATA #IMPLIED" >
|
||||
<!ENTITY % i18n.attrib
|
||||
"xml:lang %LanguageCode.datatype; #IMPLIED
|
||||
lang %LanguageCode.datatype; #IMPLIED
|
||||
dir (ltr | rtl) #IMPLIED" >
|
||||
<!ENTITY % Common.attrib "%id.attrib; %title.attrib; %i18n.attrib;" >
|
||||
|
||||
<!-- Inline classes -->
|
||||
<!ENTITY % InlStruct.class "br" >
|
||||
<!ENTITY % InlPhras.class "| em | strong | code | kbd | samp | var | q | cite | abbr | dfn" >
|
||||
<!ENTITY % InlPres.class "| b | i" >
|
||||
<!ENTITY % Anchor.class "| a" >
|
||||
<!ENTITY % InlSpecial.class "| img" >
|
||||
<!ENTITY % InlFormNoLabel.class "| input | select | textarea" >
|
||||
<!ENTITY % InlForm.class "%InlFormNoLabel.class; | label" >
|
||||
<!ENTITY % Inline.extra "" >
|
||||
<!ENTITY % Inline.class "%InlStruct.class;
|
||||
%InlPhras.class;
|
||||
%InlPres.class;
|
||||
%Anchor.class;
|
||||
%InlSpecial.class;
|
||||
%InlForm.class;
|
||||
%Inline.extra;" >
|
||||
<!ENTITY % InlNoAnchor.class "%InlStruct.class;
|
||||
%InlPhras.class;
|
||||
%InlPres.class;
|
||||
%InlSpecial.class;
|
||||
%InlForm.class;
|
||||
%Inline.extra;" >
|
||||
<!ENTITY % InlNoLabel.class "%InlStruct.class;
|
||||
%InlPhras.class;
|
||||
%InlPres.class;
|
||||
%Anchor.class;
|
||||
%InlSpecial.class;
|
||||
%InlFormNoLabel.class;
|
||||
%Inline.extra;" >
|
||||
|
||||
<!-- Block classes -->
|
||||
<!ENTITY % Heading.class "h1 | h2 | h3 | h4 | h5 | h6" >
|
||||
<!ENTITY % List.class "ul | ol | dl" >
|
||||
<!ENTITY % BlkStruct.class "p" >
|
||||
<!ENTITY % BlkPhras.class "| pre | blockquote | address" >
|
||||
<!ENTITY % BlkPres.class "| hr" >
|
||||
<!ENTITY % Table.class "| table" >
|
||||
<!ENTITY % Form.class "| form" >
|
||||
<!ENTITY % Fieldset.class "| fieldset" >
|
||||
<!ENTITY % Block.extra "" >
|
||||
<!ENTITY % BlkNoForm.class "%Heading.class;
|
||||
| %List.class;
|
||||
| %BlkStruct.class;
|
||||
%BlkPhras.class;
|
||||
%BlkPres.class;
|
||||
%Fieldset.class;
|
||||
%Block.extra;" >
|
||||
<!ENTITY % BlkNoTable.class "%BlkNoForm.class;
|
||||
%Form.class;
|
||||
%Block.extra;" >
|
||||
<!ENTITY % Blk.class "%BlkNoTable.class;
|
||||
%Table.class;
|
||||
%Block.extra;" >
|
||||
<!ENTITY % FlowNoTable.class "%Inline.class;
|
||||
| %BlkNoTable.class;" >
|
||||
|
||||
<!-- pre content model, taken verbatim from the driver. It excludes
|
||||
%InlPres.class; and %InlSpecial.class;, so b, i and img are not
|
||||
permitted in pre, as in XHTML Mobile 1.2. -->
|
||||
<!ENTITY % pre.content
|
||||
"( #PCDATA
|
||||
| %InlStruct.class;
|
||||
%InlPhras.class;
|
||||
%Anchor.class;
|
||||
%Inline.extra; )*"
|
||||
>
|
||||
|
||||
<!ELEMENT head (title, meta, link)* >
|
||||
<!ELEMENT title (#PCDATA) >
|
||||
<!ATTLIST title %common; >
|
||||
<!-- Document structure (SPEC.md 4.1) -->
|
||||
<!--
|
||||
Only body uses %Blk.class;, so a table can appear directly in the
|
||||
body and nowhere else, and tables cannot nest (SPEC.md 4.2). body may
|
||||
carry one class from the variant list (SPEC.md 5.3).
|
||||
-->
|
||||
<!ELEMENT html ( head, body ) >
|
||||
<!ATTLIST html
|
||||
xmlns CDATA #FIXED "http://www.w3.org/1999/xhtml"
|
||||
xml:lang %LanguageCode.datatype; #IMPLIED
|
||||
lang %LanguageCode.datatype; #IMPLIED
|
||||
dir (ltr | rtl) #IMPLIED
|
||||
>
|
||||
<!ELEMENT head ( title, meta, ( meta | link )* ) >
|
||||
<!ELEMENT title ( #PCDATA )* >
|
||||
<!ELEMENT body ( %Blk.class; )+ >
|
||||
<!ATTLIST body
|
||||
%Common.attrib;
|
||||
class (mews-warm | mews-cool | mews-green | mews-mono) #IMPLIED
|
||||
>
|
||||
|
||||
<!-- Head elements (SPEC.md 3.3) -->
|
||||
<!--
|
||||
The head may contain only title, meta and link. The title comes
|
||||
first and at least one meta is required; the conformance marker is a
|
||||
meta (SPEC.md 3.2), but a DTD cannot check its name and content
|
||||
together, so validators confirm the marker as a rule check (SPEC.md
|
||||
9.1). link rel is limited to the uses SPEC.md 3.3 names: the
|
||||
stylesheet, the icon and feed links.
|
||||
-->
|
||||
<!ELEMENT meta EMPTY >
|
||||
<!ATTLIST meta
|
||||
name NMTOKEN #IMPLIED
|
||||
content CDATA #REQUIRED
|
||||
name NMTOKEN #IMPLIED
|
||||
content CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT link EMPTY >
|
||||
<!ATTLIST link
|
||||
rel CDATA #IMPLIED
|
||||
href CDATA #IMPLIED
|
||||
type CDATA #IMPLIED
|
||||
title CDATA #IMPLIED
|
||||
%common;
|
||||
rel (alternate | icon | stylesheet) #IMPLIED
|
||||
href %URI.datatype; #IMPLIED
|
||||
type CDATA #IMPLIED
|
||||
title CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT body (#PCDATA | h1 | h2 | h3 | h4 | h5 | h6 | p | ul | blockquote | pre | hr | a | img)* >
|
||||
<!ATTLIST body %common; >
|
||||
<!-- Headings (SPEC.md 4.1) -->
|
||||
<!ELEMENT h1 ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST h1
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT h2 ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST h2
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT h3 ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST h3
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT h4 ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST h4
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT h5 ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST h5
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT h6 ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST h6
|
||||
%Common.attrib;
|
||||
>
|
||||
|
||||
<!ELEMENT h1 (#PCDATA) >
|
||||
<!ATTLIST h1 %common; >
|
||||
<!ELEMENT h2 (#PCDATA) >
|
||||
<!ATTLIST h2 %common; >
|
||||
<!ELEMENT h3 (#PCDATA) >
|
||||
<!ATTLIST h3 %common; >
|
||||
<!ELEMENT h4 (#PCDATA) >
|
||||
<!ATTLIST h4 %common; >
|
||||
<!ELEMENT h5 (#PCDATA) >
|
||||
<!ATTLIST h5 %common; >
|
||||
<!ELEMENT h6 (#PCDATA) >
|
||||
<!ATTLIST h6 %common; >
|
||||
<!-- Text blocks (SPEC.md 4.1) -->
|
||||
<!ELEMENT p ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST p
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT blockquote ( %BlkNoTable.class; )* >
|
||||
<!ATTLIST blockquote
|
||||
%Common.attrib;
|
||||
cite %URI.datatype; #IMPLIED
|
||||
>
|
||||
<!ELEMENT pre %pre.content; >
|
||||
<!ATTLIST pre
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT address ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST address
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT hr EMPTY >
|
||||
<!ATTLIST hr
|
||||
%Common.attrib;
|
||||
>
|
||||
|
||||
<!ELEMENT p (#PCDATA | em | strong | code | a | img | br)* >
|
||||
<!ATTLIST p %common; >
|
||||
|
||||
<!ELEMENT em (#PCDATA) >
|
||||
<!ATTLIST em %common; >
|
||||
<!ELEMENT strong (#PCDATA) >
|
||||
<!ATTLIST strong %common; >
|
||||
<!ELEMENT code (#PCDATA) >
|
||||
<!ATTLIST code %common; >
|
||||
<!ELEMENT a (#PCDATA) >
|
||||
<!-- Inline text (SPEC.md 4.1) -->
|
||||
<!ELEMENT em ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST em
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT strong ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST strong
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT code ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST code
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT kbd ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST kbd
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT samp ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST samp
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT var ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST var
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT cite ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST cite
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT abbr ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST abbr
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT dfn ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST dfn
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT b ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST b
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT i ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST i
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT q ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST q
|
||||
%Common.attrib;
|
||||
cite %URI.datatype; #IMPLIED
|
||||
>
|
||||
<!ELEMENT br EMPTY >
|
||||
<!ATTLIST br
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT a ( #PCDATA | %InlNoAnchor.class; )* >
|
||||
<!ATTLIST a
|
||||
href CDATA #IMPLIED
|
||||
title CDATA #IMPLIED
|
||||
rel CDATA #IMPLIED
|
||||
%common;
|
||||
%Common.attrib;
|
||||
href %URI.datatype; #IMPLIED
|
||||
hreflang %LanguageCode.datatype; #IMPLIED
|
||||
rel CDATA #IMPLIED
|
||||
type CDATA #IMPLIED
|
||||
accesskey %Character.datatype; #IMPLIED
|
||||
>
|
||||
<!ELEMENT img EMPTY >
|
||||
<!ATTLIST img
|
||||
src CDATA #IMPLIED
|
||||
alt CDATA #IMPLIED
|
||||
%common;
|
||||
%Common.attrib;
|
||||
src %URI.datatype; #REQUIRED
|
||||
alt %Text.datatype; #REQUIRED
|
||||
>
|
||||
<!ELEMENT br EMPTY >
|
||||
|
||||
<!ELEMENT ul (li)+ >
|
||||
<!ATTLIST ul %common; >
|
||||
<!ELEMENT li (#PCDATA | p | ul)* >
|
||||
<!ATTLIST li %common; >
|
||||
<!-- Lists (SPEC.md 4.1) -->
|
||||
<!ELEMENT ul ( li )+ >
|
||||
<!ATTLIST ul
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT ol ( li )+ >
|
||||
<!ATTLIST ol
|
||||
%Common.attrib;
|
||||
start %Number.datatype; #IMPLIED
|
||||
>
|
||||
<!ELEMENT dl ( dt | dd )+ >
|
||||
<!ATTLIST dl
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT li ( #PCDATA | %FlowNoTable.class; )* >
|
||||
<!ATTLIST li
|
||||
%Common.attrib;
|
||||
value %Number.datatype; #IMPLIED
|
||||
>
|
||||
<!ELEMENT dt ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST dt
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT dd ( #PCDATA | %FlowNoTable.class; )* >
|
||||
<!ATTLIST dd
|
||||
%Common.attrib;
|
||||
>
|
||||
|
||||
<!ELEMENT blockquote (p)* >
|
||||
<!ATTLIST blockquote %common; >
|
||||
<!ELEMENT pre (#PCDATA) >
|
||||
<!ATTLIST pre %common; >
|
||||
<!ELEMENT hr EMPTY >
|
||||
<!-- Tables (SPEC.md 4.2) -->
|
||||
<!--
|
||||
As in the XHTML Mobile basic tables module, cells take
|
||||
%FlowNoTable.class; and never a table, so tables cannot nest
|
||||
(SPEC.md 4.2).
|
||||
-->
|
||||
<!ELEMENT table ( caption?, tr+ ) >
|
||||
<!ATTLIST table
|
||||
%Common.attrib;
|
||||
summary %Text.datatype; #IMPLIED
|
||||
>
|
||||
<!ELEMENT caption ( #PCDATA | %Inline.class; )* >
|
||||
<!ATTLIST caption
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT tr ( th | td )+ >
|
||||
<!ATTLIST tr
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT th ( #PCDATA | %FlowNoTable.class; )* >
|
||||
<!ATTLIST th
|
||||
%Common.attrib;
|
||||
rowspan %Number.datatype; "1"
|
||||
colspan %Number.datatype; "1"
|
||||
scope (row | col) #IMPLIED
|
||||
>
|
||||
<!ELEMENT td ( #PCDATA | %FlowNoTable.class; )* >
|
||||
<!ATTLIST td
|
||||
%Common.attrib;
|
||||
rowspan %Number.datatype; "1"
|
||||
colspan %Number.datatype; "1"
|
||||
scope (row | col) #IMPLIED
|
||||
>
|
||||
|
||||
<!-- Forms (SPEC.md 4.1, 4.2) -->
|
||||
<!--
|
||||
As in the XHTML MP forms module, form takes %BlkNoForm.class;, so
|
||||
forms cannot nest. fieldset also takes %BlkNoForm.class;, so a
|
||||
fieldset cannot reintroduce a form.
|
||||
-->
|
||||
<!ELEMENT form ( %BlkNoForm.class; )+ >
|
||||
<!ATTLIST form
|
||||
%Common.attrib;
|
||||
action %URI.datatype; #REQUIRED
|
||||
method (get | post) "get"
|
||||
enctype CDATA "application/x-www-form-urlencoded"
|
||||
>
|
||||
<!ELEMENT fieldset ( #PCDATA | %Inline.class; | %BlkNoForm.class; )* >
|
||||
<!ATTLIST fieldset
|
||||
%Common.attrib;
|
||||
>
|
||||
<!ELEMENT label ( #PCDATA | %InlNoLabel.class; )* >
|
||||
<!ATTLIST label
|
||||
%Common.attrib;
|
||||
for IDREF #IMPLIED
|
||||
accesskey %Character.datatype; #IMPLIED
|
||||
>
|
||||
<!ELEMENT input EMPTY >
|
||||
<!ATTLIST input
|
||||
%Common.attrib;
|
||||
type (text | password | checkbox | radio | submit | reset | hidden) "text"
|
||||
name CDATA #IMPLIED
|
||||
value CDATA #IMPLIED
|
||||
checked (checked) #IMPLIED
|
||||
size %Number.datatype; #IMPLIED
|
||||
maxlength %Number.datatype; #IMPLIED
|
||||
accesskey %Character.datatype; #IMPLIED
|
||||
inputmode CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT select ( optgroup | option )+ >
|
||||
<!ATTLIST select
|
||||
%Common.attrib;
|
||||
name CDATA #IMPLIED
|
||||
multiple (multiple) #IMPLIED
|
||||
size %Number.datatype; #IMPLIED
|
||||
>
|
||||
<!ELEMENT optgroup ( option )+ >
|
||||
<!ATTLIST optgroup
|
||||
%Common.attrib;
|
||||
label %Text.datatype; #REQUIRED
|
||||
>
|
||||
<!ELEMENT option ( #PCDATA )* >
|
||||
<!ATTLIST option
|
||||
%Common.attrib;
|
||||
value CDATA #IMPLIED
|
||||
selected (selected) #IMPLIED
|
||||
>
|
||||
<!ELEMENT textarea ( #PCDATA )* >
|
||||
<!ATTLIST textarea
|
||||
%Common.attrib;
|
||||
name CDATA #IMPLIED
|
||||
rows %Number.datatype; #REQUIRED
|
||||
cols %Number.datatype; #REQUIRED
|
||||
accesskey %Character.datatype; #IMPLIED
|
||||
inputmode CDATA #IMPLIED
|
||||
>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,15 @@ THEME = TESTS / "theme"
|
|||
|
||||
BASE_SETTINGS = {
|
||||
"ARTICLE_PATHS": [],
|
||||
"MARKDOWN": {"output_format": "xhtml"},
|
||||
# Tables and definition lists are both in the Mews subset, and both need
|
||||
# an extension turned on before python-markdown will emit them.
|
||||
"MARKDOWN": {
|
||||
"output_format": "xhtml",
|
||||
"extension_configs": {
|
||||
"markdown.extensions.tables": {},
|
||||
"markdown.extensions.def_list": {},
|
||||
},
|
||||
},
|
||||
"PAGE_PATHS": ["pages"],
|
||||
"PAGE_SAVE_AS": "{slug}.xhtml",
|
||||
"PAGE_URL": "{slug}.xhtml",
|
||||
|
|
|
|||
35
pelican-mews/tests/fixtures/structure/expected.xhtml
vendored
Normal file
35
pelican-mews/tests/fixtures/structure/expected.xhtml
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title>Structure</title>
|
||||
<meta name="mews-profile" content="0.1"/>
|
||||
<meta name="viewport" content="width=device-width"/>
|
||||
<link rel="stylesheet" type="text/css" href="css/mews-0.1.css"/></head>
|
||||
<body>
|
||||
<p>A table, an ordered list and a definition list: everything the placeholder
|
||||
DTD used to throw away.</p>
|
||||
<table>
|
||||
<tr>
|
||||
|
||||
<th>Network</th>
|
||||
<th>Band</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
||||
<td>GSM 900</td>
|
||||
<td>900 MHz</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
<ol>
|
||||
<li>First</li>
|
||||
<li>Second</li>
|
||||
</ol>
|
||||
<dl>
|
||||
<dt>Term</dt>
|
||||
<dd>Its meaning</dd>
|
||||
</dl>
|
||||
</body>
|
||||
</html>
|
||||
16
pelican-mews/tests/fixtures/structure/input.md
vendored
Normal file
16
pelican-mews/tests/fixtures/structure/input.md
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
Title: Structure
|
||||
Slug: page
|
||||
Date: 2026-10-11
|
||||
|
||||
A table, an ordered list and a definition list: everything the placeholder
|
||||
DTD used to throw away.
|
||||
|
||||
| Network | Band |
|
||||
| --- | --- |
|
||||
| GSM 900 | 900 MHz |
|
||||
|
||||
1. First
|
||||
2. Second
|
||||
|
||||
Term
|
||||
: Its meaning
|
||||
|
|
@ -18,7 +18,7 @@ PACKAGE = "pelican.plugins.mews"
|
|||
STRICT_OVERRIDES = {"MEWS_STRICT": True}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("case", ["basic", "strip", "cssdir"])
|
||||
@pytest.mark.parametrize("case", ["basic", "strip", "cssdir", "structure"])
|
||||
def test_written_page_matches_expected(tmp_path, case):
|
||||
"""The written page matches the fixture, whatever was stripped."""
|
||||
overrides = {"MEWS_CSS_DIR": "style"} if case == "cssdir" else {}
|
||||
|
|
@ -28,7 +28,7 @@ def test_written_page_matches_expected(tmp_path, case):
|
|||
assert normalize(page) == normalize(expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("case", ["basic", "strip", "cssdir"])
|
||||
@pytest.mark.parametrize("case", ["basic", "strip", "cssdir", "structure"])
|
||||
def test_css_is_copied(tmp_path, case):
|
||||
"""The bundled stylesheet lands under the configured directory."""
|
||||
overrides = {"MEWS_CSS_DIR": "style"} if case == "cssdir" else {}
|
||||
|
|
@ -81,13 +81,28 @@ def test_parallel_output_folder(tmp_path):
|
|||
assert not (output / "css").exists()
|
||||
|
||||
|
||||
# Section 4.1 of the specification keeps this many elements. The plugin lists
|
||||
# none of them itself; the DTD is the only place they are written down.
|
||||
SECTION_4_1_ELEMENTS = 51
|
||||
|
||||
|
||||
def test_allowlist_is_read_from_the_dtd():
|
||||
"""The subset comes from the DTD, not from code."""
|
||||
dtd = files(PACKAGE).joinpath("dtd", "mews.dtd").read_text(encoding="utf-8")
|
||||
allowlist = parse_allowlist(dtd)
|
||||
assert allowlist["p"] == {"id", "title", "xml:lang"}
|
||||
assert allowlist["html"] == {"dir", "id", "lang", "title", "xml:lang", "xmlns"}
|
||||
assert len(allowlist) == SECTION_4_1_ELEMENTS
|
||||
# The common attributes, including the two the profile adds to XHTML-MP.
|
||||
assert allowlist["p"] == {"dir", "id", "lang", "title", "xml:lang"}
|
||||
# html takes no id or title; section 4.1 gives it these four and no more.
|
||||
assert allowlist["html"] == {"dir", "lang", "xml:lang", "xmlns"}
|
||||
assert "href" in allowlist["a"]
|
||||
# class is permitted on body and nowhere else (section 5.3).
|
||||
assert "class" in allowlist["body"]
|
||||
assert not [
|
||||
name for name, attrs in allowlist.items() if name != "body" and "class" in attrs
|
||||
]
|
||||
# The parts the placeholder DTD lacked, which the plugin was stripping.
|
||||
assert {"table", "td", "ol", "dl", "form", "input", "address"} <= set(allowlist)
|
||||
|
||||
|
||||
@pytest.mark.skipif(shutil.which("uv") is None, reason="uv is not installed")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue