Tutorial 2: writing page elements¶
Step-by-step demonstration on how page elements work and get related to the target DOM.
Note
The example below includes code snippets from MDN site, by Mozilla Contributors and licensed under CC-BY-SA 2.5.
Note
MDN site’s HTML is too good for manners. It is well written, clean and structured. Manners can do much worse than that.
HTML vs HTML¶
Open MDN in the div element . Open the inspector to examine the DOM of that page.
The body of the page, contracted, looks like this:
<body data-slug="Web/HTML/Element/div" contextmenu="edit-history-menu" data-search-url="" class="document">
<script>... </script>
<ul id="nav-access">... </ul>
<header id="main-header" class="header-main">...</header>
<main id="content" role="main">...</main>
<footer id="nav-footer" class="nav-footer">...</footer>
</body>
And, focusing a part of the <main>
element we could see a snippet like:
<div id="toc" class="toc">
<div class="center">
<div class="toc-head">Jump to:</div>
<ol class="toc-links">
<li><a href="#Attributes" rel="internal" class="">Attributes</a></li>
<li><a href="#Usage_notes" rel="internal" class="">Usage notes</a></li>
<li><a href="#Examples" rel="internal" class="">Examples</a></li>
<li><a href="#Specifications" rel="internal" class="">Specifications</a></li>
<li><a href="#Browser_compatibility" rel="internal" class="">Browser compatibility</a></li>
<li><a href="#See_also" rel="internal" class="toc-current">See also</a>
</li></ol>
</div>
</div>
In principle, pasting the above section into a pagelem template file, should work. It would match 1:1 to the MDN site DOM, that page.
Removing redundant elements¶
Not all html elements are worth matching. Say, that <div class="center">
needs
not be that specific, nor the “Jump to:” text is any more specific than the id="toc"
of the outer <div>
So, the above snippet could be cleaned like:
<div id="toc">
<div>
<ol class="toc-links">
<li><a href="#Attributes">Attributes</a></li>
<li><a href="#Usage_notes">Usage notes</a></li>
<li><a href="#Examples">Examples</a></li>
<li><a href="#Specifications">Specifications</a></li>
<li><a href="#Browser_compatibility">Browser compatibility</a></li>
<li><a href="#See_also" class="toc-current">See also</a>
</li>
</ol>
</div>
</div>
Adding components¶
The above will not emit any matched components, until this
attributes are
set in the interesting elements:
<div id="toc" this="page-toc">
<div>
<ol class="toc-links" this="links">
<li this="Attributes"><a href="#Attributes">Attributes</a></li>
<li><a href="#Usage_notes">Usage notes</a></li>
<li><a href="#Examples">Examples</a></li>
<li this="Specifications"><a href="#Specifications">Specifications</a></li>
<li><a href="#Browser_compatibility">Browser compatibility</a></li>
<li><a href="#See_also" class="toc-current">See also</a>
</li>
</ol>
</div>
</div>
That would produce a structure of components like:
[page-toc]
- [links]
- [Attributes]
- [Specifications]
Generalizing¶
Then, the indidual <li>
elements should be covered all with one rule, rather
than hard-coding their exact attributes. This allows the same toc code to match
any table of contents that conforms to this layout.
Pagelem code now can be simplified like:
<div id="toc" this="page-toc">
<div>
<ol class="toc-links" this="links">
<li this="[title]"><a href="[href]">[title]</a></li>
</ol>
</div>
</div>
Getting simpler, and will also match all entries in the TOC this way.
href="[href]"
syntax means that the value of href=
attribute will be assigned
to a href
attribute of the resulting component. Will match anything in there.
Likewise [title]
as text of an element will copy whatever text into a title
attribute.
Then, this="[title]"
means that the value assigned to title
becomes the name
of the resulting component.
Thus, the resulting component structure after this generalisation should now be:
[page-toc]
- [links]
- [Attributes]
href = #Attributes
title = Attributes
- [Usage notes]
href = #Usage_notes
title = Usage notes
- [Examples]
href = #Examples
title = Examples
...
Full page¶
The above example cannot work standalone; rather it needs to be put in context of a full HTML page. Assuming the earlier structure, it would need to be written as:
<html>
<body>
<main id="content" role="main">
<div id="toc" this="page-toc">
<div>
<ol class="toc-links" this="links">
<li this="[title]"><a href="[href]">[title]</a></li>
</ol>
</div>
</div>
</main>
</body>
</html>
This works for the MDN case, because “toc” is just one level down from “main”. But would become worse if “toc” had been somewhere deep within the page DOM.
In that case, intermediate levels could be skipped with:
<html>
<body>
<div pe-deep id="toc" this="page-toc">
<ol pe-deep class="toc-links" this="links">
<li this="[title]"><a href="[href]">[title]</a></li>
</ol>
</div>
</body>
</html>
making code now more compact.
Templating¶
Since the TOC, footer and menu of this site are expected to be re-occuring across all pages, makes sense to write them as re-usable templates
gallery.html
<html>
<body>
<template id="toc">
<div pe-deep id="toc" this="page-toc">
<ol pe-deep class="toc-links" this="links">
<li this="[title]"><a href="[href]">[title]</a></li>
</ol>
</div>
</template>
<template id="header">
<header id="main-header" class="header-main">...</header>
</template>
<template id="footer">
<footer id="nav-footer" class="nav-footer">... </footer>
</template>
</body>
</html>
div-element.html
<html>
<head>
<link rel="import" href="gallery.html">
</head>
<body>
<use-template id="header"/>
<main id="content" role="main">
<use-template id="toc"/>
<!--custom code for catching the div-element page content -->
</main>
<use-template id="footer"/>
</body>
</html>
Templates may be called repeatedly in some page, even recursively.
Attribute matching¶
Attributes of pagelems will match same attributes on remote DOM, by default.
Example:
<div class="toc">
will match a div only if it’s class equals to “toc”. That’s not always convenient, since other classes may exist along “toc”, that matching should ignore.
<div class="+toc">
will then match if the div’s class contains “toc”.
Then, several values could be or-ed by mentioning them each:
<div role="document" role="article">
Writing title="[tooltip]"
will NOT attempt any match, but transfer the value
of remote DOM attribute title
to Component attribute .tooltip
. That can
co-exist with a matcher, like:
<div class="[class_]" class="+important">
Note here the underscore after class_
, because attribute names need to be
valid Python variable names, class
is a reserved word.
Attribute matching can be negated with the !
operator:
<div role="!contentinfo">
or, when the element should not contain a class:
<div class="!+hidden">
Other pagelems¶
The pagelem HTML-like language offers some other extra elements and attributes that help match remote DOM with less code on the testing side.
Components may be tagged as pe-optional
rather than failing the match. Pagelem
can match regardless of DOM tag with <pe-any>
element.
Alternate structures may be matched with <pe-choice>
.
Within a repetition or <pe-choice>
, collections of elements can be forced to
go together in a <pe-group>
.
More about them can be read in the reference and supplied examples.