<
p:declare-step xmlns:p=
"http://www.w3.org/ns/xproc" xmlns:px=
"http://www.daisy.org/ns/pipeline/xproc" xmlns:pxi=
"http://www.daisy.org/ns/pipeline/xproc/internal" xmlns:pf=
"http://www.daisy.org/ns/pipeline/functions" xmlns:d=
"http://www.daisy.org/ns/pipeline/data" xmlns:c=
"http://www.w3.org/ns/xproc-step" xmlns:cx=
"http://xmlcalabash.com/ns/extensions" xmlns:xs=
"http://www.w3.org/2001/XMLSchema" version=
"1.0" exclude-inline-prefixes=
"#all" type=
"px:css-cascade" name=
"main">
<
p:documentation xmlns=
"http://www.w3.org/1999/xhtml">
<
p><
a href=
"http://braillespecs.github.io/braille-css/#h2_cascade">Cascade</
a> and inline
CSS and <
a href=
"https://sass-lang.com/documentation">SCSS</
a> style sheets in XML.</
p>
<
p>Inlining is done with <
code>style</
code> attributes with the <
a href=
"http://braillespecs.github.io/braille-css/#h2_style-attribute">syntax</
a> described in
braille CSS.</
p>
</
p:documentation>
<
p:input port=
"source" primary=
"true"/>
<
p:input port=
"source.in-memory" sequence=
"true">
<
p:documentation xmlns=
"http://www.w3.org/1999/xhtml">
<
p>The input fileset containing content and style files, if a <
code>d:fileset</
code>
document is received on the <
code>source</
code> port. Otherwise, the document that is
received on the <
code>source</
code> port is interpreted as the only content document,
and the <
code>source.in-memory</
code> port is checked for style files.</
p>
<
p>Style sheets can be associated with the source in several ways: linked (using an
<
code>xml-stylesheet</
code> processing instruction or a <
code>link</
code> element),
embedded (using a <
code>style</
code> element) and/or inlined (using <
code>style</
code>
attributes).</
p>
<
p>Style sheets that are linked to from the source document, or included via the
'user-stylesheet' option, must either exist on disk, or must be part of the source
fileset.</
p>
</
p:documentation>
<
p:empty/>
</
p:input>
<
p:input port=
"parameters" kind=
"parameter" primary=
"false">
<
p:documentation xmlns=
"http://www.w3.org/1999/xhtml">
<
p>Parameters that are passed to SCSS style sheets (as <
a href=
"https://sass-lang.com/documentation/variables#scope">global variables</
a>). They
are also passed to XSLT transformations that are included from CSS through
<
code>@xslt</
code> rules.</
p>
</
p:documentation>
</
p:input>
<
p:output port=
"result" primary=
"true"/>
<
p:output port=
"result.in-memory" sequence=
"true">
<
p:documentation xmlns=
"http://www.w3.org/1999/xhtml">
<
p>The output fileset, if a <
code>d:fileset</
code> document was received on the
<
code>source</
code> port. Otherwise, the <
code>result</
code> port holds the only output
content document, and the <
code>result.in-memory</
code> port is empty.</
p>
<
p>All styles are parsed, validated, normalized, cascaded and finally serialized into
<
code>style</
code> attributes.</
p>
<
p>Shorthand declarations such as <
code>margin: a b c d</
code> are decomposed as
<
code>margin-top: a; margin-right: b; margin-bottom: c; margin-left: d</
code>.</
p>
<
p>'before' and 'after' rules are serialized as <
code>&::before { ... }</
code> and
<
code>&::after { ... }</
code>.</
p>
<
p>'page' properties are replaced with the corresponding named 'page' rules (without the
page type selector). If the root element does not have a 'page' property, the default
page rule is inserted. 'page' rules are serialized as <
code>@page { ... } @page:left {
... } @page:right { ... }</
code>. The declarations that named page rules inherit from
the default page rule are made explicit. The declarations that 'left' and 'right' page
rules inherit from their principal page rule are also made explicit.</
p>
<
p>'volume' rules are serialized as <
code>@volume { ... } @volume:first { ... }
@volume:last { ... } @volume:nth(...) { ... } @volume:nth-last(...) { ... }</
code> and
inserted for the root element. The declarations that '@volume:first' etc. inherit from
the principal volume rule are made explicit. ':nth(1)' and ':nth-last(1)' are normalized
to ':first' and ':last'. A special '@volume:only' rule, which is a combination of the
'@volume:first' and '@volume:last' rules, is created for the case that there is only a
single volume.</
p>
</
p:documentation>
<
p:pipe step=
"result" port=
"in-memory"/>
</
p:output>
<
p:output port=
"result.parameters">
<
p:documentation xmlns=
"http://www.w3.org/1999/xhtml">
<
p>A <
a href=
"https://www.w3.org/TR/xproc/#cv.param-set"><
code>c:param-set</
code></
a>
document containing all the parameters on the <
code>parameters</
code> input port,
augmented with any <
a href=
"https://sass-lang.com/documentation/variables#scope">global
variables</
a> declared in SCSS style sheets. Variables that are declared later take
precedence, except if they are declared with <
code>!default</
code>.</
p>
</
p:documentation>
<
p:pipe step=
"parameters" port=
"result"/>
</
p:output>
<
p:option name=
"content-type" required=
"false" select=
"'text/html application/xhtml+xml application/x-dtbook+xml'">
<
p:documentation xmlns=
"http://www.w3.org/1999/xhtml">
<
p>The type of document to be processed. Other input documents will be left
unchanged.</
p>
<
p>Ignored if the <
code>source</
code> port holds a document that is not a
<
code>d:fileset</
code>.</
p>
</
p:documentation>
</
p:option>
<
p:option name=
"user-stylesheet" required=
"false" select=
"''">
<
p:documentation xmlns=
"http://www.w3.org/1999/xhtml">
<
p>Space separated list of URIs, absolute or relative to source. Applied prior to all
other style sheets defined within the source.</
p>
</
p:documentation>
</
p:option>
<
p:option name=
"type" required=
"false" select=
"'text/css text/x-scss'">
<
p:documentation xmlns=
"http://www.w3.org/1999/xhtml">
<
p>The type of associated style sheets to apply. May be a space separated list. Allowed
values are "text/css" and "text/x-scss". If omitted, all CSS and SCSS style sheets are
applied.</
p>
</
p:documentation>
</
p:option>
<
p:option name=
"media" required=
"false" select=
"'embossed'">
<
p:documentation xmlns=
"http://www.w3.org/1999/xhtml">
<
p>The target medium type as a <
a href=
"https://www.w3.org/TR/mediaqueries-4/">media
query</
a>. All rules that are contained in a style sheet that matches the specified
medium are included. Supported media types are "embossed", "speech" and "print". When
the target medium is "embossed", CSS is interpreted according to the rules of <
a href=
"http://braillespecs.github.io/braille-css">braille CSS</
a>. Supported media
features are '<
a href=
"https://www.w3.org/TR/mediaqueries-4/#width">width</
a>' and '<
a href=
"https://www.w3.org/TR/mediaqueries-4/#height">height</
a>' In addition,
'<
code>(counter-support: none)</
code>' can be used to transform lists to preformatted
lists.</
p>
</
p:documentation>
</
p:option>
<
p:option name=
"attribute-name" required=
"false" select=
"'style'">
<
p:documentation xmlns=
"http://www.w3.org/1999/xhtml">
<
p>Name of attribute to use for inlined styles. Default name is 'style'.</
p>
</
p:documentation>
</
p:option>
<
p:option name=
"multiple-attributes" required=
"false" cx:as=
"xs:boolean" select=
"false()">
<
p:documentation xmlns=
"http://www.w3.org/1999/xhtml">
<
p>Cascade the styles into multiple attributes per element. In this case the namespace
and prefix of <
code>attribute-name</
code> are used for the attributes, the local part is
ignored.</
p>
</
p:documentation>
</
p:option>
<
p:declare-step type=
"pxi:css-cascade">
<
p:input port=
"source" primary=
"true"/>
<
p:input port=
"context" sequence=
"true">
<
p:documentation xmlns=
"http://www.w3.org/1999/xhtml">
<
p>Style sheets that are linked to from the source document, or included via the
'user-stylesheet' option, must either exist on disk, or must be provided in
memory via this port. Style sheets on this port must be wrapped in <c:result
content-type="text/plain"> elements. Style sheet URIs are resolved by matching
against the context documents's base URIs.</
p>
</
p:documentation>
</
p:input>
<
p:input port=
"parameters" kind=
"parameter" primary=
"false"/>
<
p:output port=
"result"/>
<
p:option name=
"user-stylesheet"/>
<
p:option name=
"media"/>
<
p:option name=
"type"/>
<
p:option name=
"attribute-name"/>
<
p:option name=
"multiple-attributes"/>
</
p:declare-step>
<
p:declare-step type=
"pxi:css-analyze">
<
p:input port=
"source" primary=
"true"/>
<
p:input port=
"context" sequence=
"true">
<
p:documentation xmlns=
"http://www.w3.org/1999/xhtml">
<
p>Style sheets that are linked to from the source document, or included via the
'user-stylesheet' option, must either exist on disk, or must be provided in
memory via this port. Style sheets on this port must be wrapped in <c:result
content-type="text/plain"> elements. Style sheet URIs are resolved by matching
against the context documents's base URIs.</
p>
</
p:documentation>
</
p:input>
<
p:input port=
"parameters" kind=
"parameter" primary=
"false"/>
<
p:output port=
"result"/>
<
p:option name=
"user-stylesheet"/>
<
p:option name=
"media"/>
</
p:declare-step>
<
p:import href=
"http://www.daisy.org/pipeline/modules/common-utils/library.xpl">
<
p:documentation>
px:parse-xml-stylesheet-instructions
px:assert
</
p:documentation>
</
p:import>
<
p:import href=
"http://www.daisy.org/pipeline/modules/fileset-utils/library.xpl">
<
p:documentation>
px:fileset-load
px:fileset-update
</
p:documentation>
</
p:import>
<
p:variable name=
"fileset-mode" cx:as=
"xs:boolean" select=
"exists(/d:fileset)"/>
<
p:choose name=
"css">
<
p:when test=
"$fileset-mode">
<
p:output port=
"result" sequence=
"true"/>
<
px:fileset-load>
<
p:input port=
"in-memory">
<
p:pipe step=
"main" port=
"source.in-memory"/>
</
p:input>
<
p:with-option name=
"media-types" select=
"$type"/>
</
px:fileset-load>
</
p:when>
<
p:otherwise>
<
p:output port=
"result" sequence=
"true"/>
<
p:identity>
<
p:input port=
"source">
<
p:empty/>
</
p:input>
</
p:identity>
</
p:otherwise>
</
p:choose>
<
p:sink/>
<
p:identity>
<
p:input port=
"source">
<
p:pipe step=
"main" port=
"source"/>
</
p:input>
</
p:identity>
<
p:choose name=
"content">
<
p:when test=
"$fileset-mode">
<
p:output port=
"result" sequence=
"true" primary=
"true"/>
<
p:output port=
"fileset" sequence=
"true">
<
p:pipe step=
"load" port=
"result.fileset"/>
</
p:output>
<
px:fileset-load name=
"load">
<
p:input port=
"in-memory">
<
p:pipe step=
"main" port=
"source.in-memory"/>
</
p:input>
<
p:with-option name=
"media-types" select=
"$content-type"/>
</
px:fileset-load>
</
p:when>
<
p:otherwise>
<
p:output port=
"result" sequence=
"true" primary=
"true"/>
<
p:output port=
"fileset" sequence=
"true">
<
p:empty/>
</
p:output>
<
p:identity/>
</
p:otherwise>
</
p:choose>
<
p:for-each name=
"content-with-inlined-css">
<
p:output port=
"result"/>
<
px:parse-xml-stylesheet-instructions name=
"xml-stylesheet-instructions" px:progress=
".05"/>
<
p:group px:progress=
".95">
<
p:variable name=
"stylesheets-from-xml-stylesheet-instructions" cx:as=
"xs:string*" select=
"/d:fileset/d:file [not(@stylesheet-media) or pf:media-query-matches(@stylesheet-media,$media)] [(@media-type=('text/css','text/x-scss') and @media-type=tokenize($type,'\s+'))] /string(@href)">
<
p:pipe step=
"xml-stylesheet-instructions" port=
"fileset"/>
</
p:variable>
<
p:sink/>
<
p:identity>
<
p:input port=
"source">
<
p:pipe step=
"content-with-inlined-css" port=
"current"/>
</
p:input>
</
p:identity>
<
p:choose px:progress=
"1">
<
p:when test=
"$user-stylesheet!='' or exists($stylesheets-from-xml-stylesheet-instructions) or //*[local-name()='style'] [not(@media) or pf:media-query-matches(@media,$media)] [(@type=('text/css','text/x-scss') and @type=tokenize($type,'\s+')) or ('text/css'=tokenize($type,'\s+') and not(@type))] or //*[local-name()='link' and @rel='stylesheet'] [not(@media) or pf:media-query-matches($media,@media)] [(@type=('text/css','text/x-scss') and @type=tokenize($type,'\s+')) or ('text/css'=tokenize($type,'\s+') and not(@type) and matches(@href,'\.css$')) or ('text/x-scss'=tokenize($type,'\s+') and not(@type) and matches(@href,'\.scss$'))] or //@style">
<
pxi:css-cascade px:progress=
"1">
<
p:input port=
"context">
<
p:pipe step=
"css" port=
"result"/>
</
p:input>
<
p:input port=
"parameters">
<
p:pipe step=
"main" port=
"parameters"/>
</
p:input>
<
p:with-option name=
"user-stylesheet" select=
"string-join(($user-stylesheet[not(.='')],$stylesheets-from-xml-stylesheet-instructions),' ')"/>
<
p:with-option name=
"media" select=
"$media"/>
<
p:with-option name=
"type" select=
"$type"/>
<
p:with-option name=
"attribute-name" select=
"$attribute-name"/>
<
p:with-option name=
"multiple-attributes" select=
"$multiple-attributes"/>
</
pxi:css-cascade>
</
p:when>
<
p:otherwise>
<
p:identity/>
</
p:otherwise>
</
p:choose>
</
p:group>
</
p:for-each>
<
p:sink/>
<
p:identity>
<
p:input port=
"source">
<
p:pipe step=
"main" port=
"source"/>
</
p:input>
</
p:identity>
<
p:group name=
"parameters" cx:pure=
"true">
<
p:output port=
"result"/>
<
px:assert message=
"parameters output not supported when input is a d:fileset" error-code=
"XXXXX">
<
p:with-option name=
"test" select=
"not($fileset-mode)"/>
</
px:assert>
<
px:parse-xml-stylesheet-instructions name=
"xml-stylesheet-instructions"/>
<
p:group>
<
p:variable name=
"stylesheets-from-xml-stylesheet-instructions" cx:as=
"xs:string*" select=
"/d:fileset/d:file [not(@stylesheet-media) or pf:media-query-matches(@stylesheet-media,$media)] [(@media-type=('text/css','text/x-scss') and @media-type=tokenize($type,'\s+'))] /string(@href)">
<
p:pipe step=
"xml-stylesheet-instructions" port=
"fileset"/>
</
p:variable>
<
p:sink/>
<
p:identity>
<
p:input port=
"source">
<
p:pipe step=
"main" port=
"source"/>
</
p:input>
</
p:identity>
<
p:choose>
<
p:when test=
"$user-stylesheet!='' or exists($stylesheets-from-xml-stylesheet-instructions) or //*[local-name()='style'] [not(@media) or pf:media-query-matches(@media,$media)] [(@type=('text/css','text/x-scss') and @type=tokenize($type,'\s+')) or ('text/css'=tokenize($type,'\s+') and not(@type))] or //*[local-name()='link' and @rel='stylesheet'] [not(@media) or pf:media-query-matches($media,@media)] [(@type=('text/css','text/x-scss') and @type=tokenize($type,'\s+')) or ('text/css'=tokenize($type,'\s+') and not(@type) and matches(@href,'\.css$')) or ('text/x-scss'=tokenize($type,'\s+') and not(@type) and matches(@href,'\.scss$'))]">
<
pxi:css-analyze>
<
p:input port=
"context">
<
p:pipe step=
"css" port=
"result"/>
</
p:input>
<
p:input port=
"parameters">
<
p:pipe step=
"main" port=
"parameters"/>
</
p:input>
<
p:with-option name=
"user-stylesheet" select=
"string-join(($user-stylesheet[not(.='')], $stylesheets-from-xml-stylesheet-instructions),' ')"/>
<
p:with-option name=
"media" select=
"$media"/>
</
pxi:css-analyze>
</
p:when>
<
p:otherwise>
<
p:sink/>
<
p:parameters name=
"param-set">
<
p:input port=
"parameters">
<
p:pipe step=
"main" port=
"parameters"/>
</
p:input>
</
p:parameters>
<
p:identity>
<
p:input port=
"source">
<
p:pipe step=
"param-set" port=
"result"/>
</
p:input>
</
p:identity>
</
p:otherwise>
</
p:choose>
</
p:group>
</
p:group>
<
p:sink/>
<
p:choose name=
"result">
<
p:when test=
"$fileset-mode">
<
p:output port=
"fileset-or-single-content-document" primary=
"true"/>
<
p:output port=
"in-memory" sequence=
"true">
<
p:pipe step=
"update" port=
"result.in-memory"/>
</
p:output>
<
px:fileset-update name=
"update">
<
p:input port=
"source.fileset">
<
p:pipe step=
"main" port=
"source"/>
</
p:input>
<
p:input port=
"source.in-memory">
<
p:pipe step=
"main" port=
"source.in-memory"/>
</
p:input>
<
p:input port=
"update.fileset">
<
p:pipe step=
"content" port=
"fileset"/>
</
p:input>
<
p:input port=
"update.in-memory">
<
p:pipe step=
"content-with-inlined-css" port=
"result"/>
</
p:input>
</
px:fileset-update>
</
p:when>
<
p:otherwise>
<
p:output port=
"fileset-or-single-content-document" primary=
"true"/>
<
p:output port=
"in-memory" sequence=
"true">
<
p:empty/>
</
p:output>
<
p:identity>
<
p:input port=
"source">
<
p:pipe step=
"content-with-inlined-css" port=
"result"/>
</
p:input>
</
p:identity>
</
p:otherwise>
</
p:choose>
</
p:declare-step>