Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 21 additions & 12 deletions src/blocks.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -99,18 +99,27 @@ version="3.0">
<xsl:template name="rdfae:replace-rendering">
<xsl:param name="island" as="element()"/>
<xsl:param name="content" as="node()*"/>
<xsl:for-each select="$island/*[@data-role = 'rendering']">
<xsl:sequence select="ixsl:call(., 'remove', [])[current-date() lt xs:date('2000-01-01')]"/>
</xsl:for-each>
<xsl:variable name="rendering" as="element()" select="rdfae:element('div')"/>
<xsl:for-each select="$rendering">
<ixsl:set-attribute name="data-role" select="'rendering'"/>
</xsl:for-each>
<!-- html method: XML's self-closing tags read as OPEN tags to the HTML
fragment parser and swallow following siblings -->
<ixsl:set-property name="innerHTML"
select="serialize($content, map{ 'method': 'html' })" object="$rendering"/>
<xsl:sequence select="ixsl:call($island, 'appendChild', [ $rendering ])[current-date() lt xs:date('2000-01-01')]"/>
<xsl:variable name="rendering" as="element()">
<div data-role="rendering">
<xsl:copy-of select="$content"/>
</div>
</xsl:variable>
<xsl:choose>
<xsl:when test="$island/*[@data-role = 'rendering']">
<xsl:for-each select="($island/*[@data-role = 'rendering'])[1]">
<xsl:result-document href="?." method="ixsl:replace-element">
<xsl:copy-of select="$rendering"/>
</xsl:result-document>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:for-each select="$island">
<xsl:result-document href="?." method="ixsl:append-content">
<xsl:copy-of select="$rendering"/>
</xsl:result-document>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<!-- ............................ extension hooks ............................ -->
Expand Down
36 changes: 21 additions & 15 deletions src/edit.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,16 @@ version="3.0">
<xsl:template name="rdfae:init-region">
<xsl:param name="region" as="element()"/>

<!-- the region is the canvas' focusable floor. Only leaf text hosts are
contenteditable, so the surface between them - sibling margins, the
handle gutter, a structural container's own box, chrome on a structural
block - has no focusable ancestor at all, and a press there drops focus
out of the editor entirely (which hosts read as leaving it, and a press
on a drag handle cannot preventDefault without killing dragstart). With
tabindex the region absorbs that focus instead: same idiom as the block
images and object-block islands in rdfae:init-block, out of the tab
order, and stripped by the canonical form -->
<ixsl:set-attribute name="tabindex" select="'-1'" object="$region"/>
<!-- boundary-normalize invalid host markup (bare text in blockquote,
blocks inside p, stray inline at region level, ...) before
editability init; the probe keeps the valid case zero-churn -->
Expand All @@ -390,8 +400,11 @@ version="3.0">
<xsl:if test="$invalid">
<xsl:variable name="fixed" as="node()*"
select="cm:wrap-inline-runs(cm:normalize($region/node()), 'p')"/>
<ixsl:set-property name="innerHTML"
select="serialize($fixed, map{ 'method': 'html' })" object="$region"/>
<xsl:for-each select="$region">
<xsl:result-document href="?." method="ixsl:replace-content">
<xsl:copy-of select="$fixed"/>
</xsl:result-document>
</xsl:for-each>
</xsl:if>
<!-- an empty region cannot hold a caret: seed a paragraph (the
empty-blockquote idiom in rdfae:init-block) -->
Expand Down Expand Up @@ -1651,19 +1664,12 @@ version="3.0">
<xsl:with-param name="host" select="$host"/>
<xsl:with-param name="range" select="$range"/>
</xsl:call-template>
<!-- method html: XML's self-closing <p/> reads as an OPEN tag to the
HTML fragment parser and swallows following siblings -->
<xsl:variable name="stage" as="element()" select="rdfae:element('div')"/>
<ixsl:set-property name="innerHTML" select="serialize($blocks, map{ 'method': 'html' })" object="$stage"/>
<xsl:variable name="count" as="xs:integer" select="xs:integer(ixsl:get($stage, 'childNodes.length'))"/>
<xsl:iterate select="1 to $count">
<xsl:param name="anchor" select="$host"/>
<xsl:variable name="node" select="ixsl:get($stage, 'firstChild')"/>
<xsl:sequence select="ixsl:call($anchor, 'after', [ $node ])[current-date() lt xs:date('2000-01-01')]"/>
<xsl:next-iteration>
<xsl:with-param name="anchor" select="$node"/>
</xsl:next-iteration>
</xsl:iterate>
<xsl:variable name="count" as="xs:integer" select="count($blocks)"/>
<xsl:for-each select="$host">
<xsl:result-document href="?." method="ixsl:insert-after">
<xsl:copy-of select="$blocks"/>
</xsl:result-document>
</xsl:for-each>
<xsl:for-each select="$host/following-sibling::*[position() le $count]">
<xsl:call-template name="rdfae:init-block">
<xsl:with-param name="block" select="."/>
Expand Down
40 changes: 34 additions & 6 deletions src/select.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -247,12 +247,14 @@ version="3.0">

<!-- mousedown in a region: Shift extends the standing selection to the
clicked point (the anchor never moves - preventDefault stops the
native caret placement that would collapse it), a plain primary press
arms a sweep anchor for the mousemove takeover (no preventDefault:
native caret placement and in-host drags proceed untouched). SaxonJS
dispatches an event at the innermost matching template only, so a
press on the drag handle never reaches this (the handle owns its
gesture) and chrome is guarded out explicitly -->
native caret placement that would collapse it), a press on non-editable
canvas places the caret at the point itself (no native placement exists
there), and a plain primary press on a host arms a sweep anchor for the
mousemove takeover (no preventDefault: native caret placement and
in-host drags proceed untouched). SaxonJS dispatches an event at the
innermost matching template only, so a press on the drag handle never
reaches this (the handle owns its gesture) and chrome is guarded out
explicitly -->
<xsl:template match="*[contains-token(@class, 'rdfa-editor-content')]" mode="ixsl:onmousedown">
<xsl:variable name="event" select="ixsl:event()"/>
<xsl:variable name="region" as="element()" select="."/>
Expand Down Expand Up @@ -282,6 +284,32 @@ version="3.0">
<ixsl:set-property name="sweepAnchorHost" select="()" object="rdfae:editor-state()"/>
<ixsl:set-property name="sweepRegion" select="rdfae:root-of($anchor-node)" object="rdfae:editor-state()"/>
</xsl:when>
<!-- a press that landed outside every editable host: the surface
between blocks, the handle gutter, a structural container's own
box. The browser has no caret to place there and no focusable
element below the region to focus, so the placement is ours -
the nearest host takes focus and the caret lands at the point,
rather than focus dropping off the canvas. A point that resolves
into a non-editable parent (rdfae:caret-at-point escapes islands
and chrome to a position beside them) has no host to focus and
nothing to place: it falls through to the region's own tabindex -->
<xsl:when test="empty($target/ancestor-or-self::*[@contenteditable = 'true'])
and exists(rdfae:host-of($point?node))">
<xsl:sequence select="ixsl:call($event, 'preventDefault', [])[current-date() lt xs:date('2000-01-01')]"/>
<xsl:call-template name="rdfae:focus-caret">
<xsl:with-param name="node" select="$point?node"/>
<xsl:with-param name="offset" select="$point?offset"/>
</xsl:call-template>
<!-- the preventDefault killed the native drag session, so a sweep
dragged out of here is synthetic throughout (no anchor host) -->
<ixsl:set-property name="sweepAnchorNode" select="$point?node" object="rdfae:editor-state()"/>
<ixsl:set-property name="sweepAnchorOffset" select="$point?offset" object="rdfae:editor-state()"/>
<ixsl:set-property name="sweepAnchorHost" select="()" object="rdfae:editor-state()"/>
<ixsl:set-property name="sweepRegion" select="$region" object="rdfae:editor-state()"/>
<!-- focusin only fires when the host changes; a point in the same
host still moves the caret, so sync from the choke point -->
<xsl:call-template name="rdfae:update-breadcrumb"/>
</xsl:when>
<xsl:otherwise>
<xsl:for-each select="$point">
<ixsl:set-property name="sweepAnchorNode" select="?node" object="rdfae:editor-state()"/>
Expand Down
Loading