Conal-Tuohy / swinburne

Algernon Charles Swinburne website
4 stars 0 forks source link

implement rendition/@selector #13

Closed Conal-Tuohy closed 3 years ago

Conal-Tuohy commented 3 years ago

Currently rendition elements can be associated with transcriptional elements in two ways:

  1. by the transcriptional element pointing to the rendition <p rendition="#foo-rendition">
  2. by a tagUsage element associating a rendition with a type of transcriptional element <tagUsage gi="p" rendition="#foo-rendition">

TEI has an additional and more flexible method for associating rendition elements with transcriptional elements, in which the rendition element points to the set of transcriptional elements to which it should reply, using a CSS selector <rendition selector="p:first-child">

Implementing this third method would require parsing and evaluating these CSS selectors, which is computationally a lot more work than the other methods require, but it can makes for much less clutter in the transcriptional markup, and provides a better separation of concerns than the first method, and has much more discriminatory power than the second method.

Conal-Tuohy commented 3 years ago

One approach could be to translate the CSS selector syntax to equivalent XPath, and add an XProc step which processes the rendition[@selector] elements; evaluates the XPath expressions and explicitly sets the @rendition value of each matching element to refer to the rendition element's @xml:id.

Conal-Tuohy commented 3 years ago

go ahead with universal selector (*), first-child, last-child, id, and attribute selectors, child, descendant combinators

Conal-Tuohy commented 3 years ago

https://www.w3.org/TR/selectors-3/#specificity

Conal-Tuohy commented 3 years ago

also added the following-sibling (~) and next-sibling (+) combinators

Conal-Tuohy commented 3 years ago

I finished the task, taking into account the specificity of the rendition/@selector selectors.

What happens in the HTML is that the various TEI rendition elements are rendered as CSS blocks with a class selector, and the various HTML elements have class attribute values based on the @rendition attribute of the TEI element which was their source.

e.g.

<rendition xml:id="example">
font-style: italic;
</rendition>

produces CSS in the HTML page:

.rendition-example {
font-style: italic;
}

and a TEI paragraph like so:

<p rendition="#example">this should be in italics</p>

ends up as an HTML paragraph something like:

<p class="rendition-example">this should be in italics</p>

In order for these "class-based" selectors to respect the priority ordering of the selectors specified in the TEI, they just need to be listed in ascending order of specificity in the CSS stylesheet in the HTML, as later ones override the earlier ones.

So to achieve that, I've made it so the selector-evaluation stylesheet also sorts the rendition elements in the same order. The stylesheet removes the original rendition[@selector] elements and outputs new versions, outputting them at the start of the tagsDecl in ascending order of specificity (so that the highest priority ones come last), and before any rendition elements which didn't have a selector (which the stylesheet leaves alone).

A rendition element in the source may actual contain several selectors in its @selector attribute (delimited with commas). Because those selectors may have different specificity, the same rendition styles may need to appear in multiple places within the priority order, so in those "multi-selector" cases there will be more of these "generated" rendition elements than there were "source" rendition elements. i.e. if a source rendition element has a @selector containing a general and also a very specific selector, then that will produce two rendition elements, one at the start of the list of rendition elements, and another at the end.

Conal-Tuohy commented 3 years ago

In 002dc0ee8e94a24f08493db9bc2274098f22ba67 I carefully read through the stylesheet and fixed up a bunch of misleading comments (mostly copy and paste errors) and a couple of minor logic errors; failing to always entirely deduplicate the list of @rendition attributes when they are modified, and failing to copy rendition[@selector][@xml:id] elements which might actually have been referred to by a @rendition.

Added support for the :lang pseudo-class, e.g. quote:lang(la) will now match Latin quotes, even if the xml:lang='la' tag is on an ancestor element of the quote element, where quote[@lang='la'] will not serve the purpose.

Added support for :only-child alongside the existing :first-child and :last-child (for completeness), and also added support for :first-of-type, :last-of-type, and :only-of-type pseudo-classes, which I think are likely to be better choices than :first-child etc in most cases, because e.g. in the poem below, l:last-of-type will match the last line, where l:last-child will not match anything.

<lg>
  <l>line one</l>
  <l>line two</l>
  <l>line three</l>
  <note>that's the end of the poem</note>
<lg>