Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git

Updates libraries, starts cross-references parsing

AuthorDaveJarvis <email>
Date2023-11-20 17:31:23 GMT-0800
Commit420e1e207fbb29c3271809692392b29f2160604f
Parent2fd2028
Delta179 lines added, 89 lines removed, 90-line increase
www/downloads/counter.php
$method = isset( $_SERVER[ 'REQUEST_METHOD' ] )
- ? $_SERVER[ 'REQUEST_METHOD ' ]
+ ? $_SERVER[ 'REQUEST_METHOD' ]
: 'GET';
src/main/java/com/keenwrite/processors/markdown/extensions/tex/TeXInlineDelimiterProcessor.java
-/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */
-package com.keenwrite.processors.markdown.extensions.tex;
-
-import com.vladsch.flexmark.parser.InlineParser;
-import com.vladsch.flexmark.parser.core.delimiter.Delimiter;
-import com.vladsch.flexmark.parser.delimiter.DelimiterProcessor;
-import com.vladsch.flexmark.parser.delimiter.DelimiterRun;
-import com.vladsch.flexmark.util.ast.Node;
-
-public class TeXInlineDelimiterProcessor implements DelimiterProcessor {
-
- @Override
- public void process( final Delimiter opener,
- final Delimiter closer,
- final int delimitersUsed ) {
- final var node = new TexNode( opener, closer );
- opener.moveNodesBetweenDelimitersTo( node, closer );
- }
-
- @Override
- public char getOpeningCharacter() {
- return '$';
- }
-
- @Override
- public char getClosingCharacter() {
- return '$';
- }
-
- @Override
- public int getMinLength() {
- return 1;
- }
-
- /**
- * Allow for $ or $$.
- *
- * @param opener One or more opening delimiter characters.
- * @param closer One or more closing delimiter characters.
- * @return The number of delimiters to use to determine whether a valid
- * opening delimiter expression is found.
- */
- @Override
- public int getDelimiterUse(
- final DelimiterRun opener, final DelimiterRun closer ) {
- return 1;
- }
-
- @Override
- public boolean canBeOpener( final String before,
- final String after,
- final boolean leftFlanking,
- final boolean rightFlanking,
- final boolean beforeIsPunctuation,
- final boolean afterIsPunctuation,
- final boolean beforeIsWhitespace,
- final boolean afterIsWhiteSpace ) {
- return leftFlanking;
- }
-
- @Override
- public boolean canBeCloser( final String before,
- final String after,
- final boolean leftFlanking,
- final boolean rightFlanking,
- final boolean beforeIsPunctuation,
- final boolean afterIsPunctuation,
- final boolean beforeIsWhitespace,
- final boolean afterIsWhiteSpace ) {
- return rightFlanking;
- }
-
- @Override
- public Node unmatchedDelimiterNode(
- final InlineParser inlineParser, final DelimiterRun delimiter ) {
- return null;
- }
-
- @Override
- public boolean skipNonOpenerCloser() {
- return false;
- }
-}
src/main/java/com/keenwrite/processors/markdown/extensions/tex/TexNode.java
public class TexNode extends DelimitedNodeImpl {
/**
- * TeX expression wrapped in a {@code <tex>} element.
+ * A TeX expression wrapped in a {@code <tex>} element.
*/
public static final String HTML_TEX = "tex";
- public static final String TOKEN_OPEN = "$";
- public static final String TOKEN_CLOSE = "$";
+ static final String TOKEN_OPEN = "$";
+ static final String TOKEN_CLOSE = "$";
private final String mOpener;
* @return Either '$' or '$$'.
*/
- public String getOpeningDelimiter() { return mOpener; }
+ public String getOpeningDelimiter() {
+ return mOpener;
+ }
/**
* @return Either '$' or '$$'.
*/
- public String getClosingDelimiter() { return mCloser; }
+ public String getClosingDelimiter() {
+ return mCloser;
+ }
private String getDelimiter( final Delimiter delimiter ) {
src/main/java/com/keenwrite/processors/markdown/extensions/references/AnchorXrefNode.java
+/* Copyright 2023 White Magic Software, Ltd. -- All rights reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ */
+package com.keenwrite.processors.markdown.extensions.references;
+
+import com.vladsch.flexmark.util.ast.Node;
+import com.vladsch.flexmark.util.sequence.BasedSequence;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Responsible for writing HTML anchor cross-references in the form
+ * {@code <a data-type="..." href="#name" />} where {@code name} refers
+ * to an anchor name.
+ *
+ * @see AnchorNameNode
+ */
+class AnchorXrefNode extends Node implements CrossReferenceNode {
+ private final String mTypeName;
+ private final String mIdName;
+
+ AnchorXrefNode( final String type, final String id ) {
+ mTypeName = type;
+ mIdName = STR. "#\{ id }" ;
+ }
+
+ @Override
+ public String getTypeName() {
+ return mTypeName;
+ }
+
+ @Override
+ public String getIdName() {
+ return mIdName;
+ }
+
+ @Override
+ public String getRefAttrName() {
+ return "href";
+ }
+
+ @NotNull
+ @Override
+ public BasedSequence[] getSegments() {
+ return BasedSequence.EMPTY_SEGMENTS;
+ }
+}
src/main/java/com/keenwrite/processors/markdown/extensions/references/CrossReferenceExtension.java
+/* Copyright 2023 White Magic Software, Ltd. -- All rights reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ */
+package com.keenwrite.processors.markdown.extensions.references;
+
+import com.keenwrite.processors.markdown.extensions.HtmlRendererAdapter;
+import com.vladsch.flexmark.html.HtmlRenderer;
+import com.vladsch.flexmark.parser.Parser;
+import com.vladsch.flexmark.parser.Parser.ParserExtension;
+import com.vladsch.flexmark.util.data.MutableDataHolder;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Responsible for processing {@code {@type:id}} anchors and their corresponding
+ * {@code [@type:id]} cross-references.
+ */
+public class CrossReferenceExtension extends HtmlRendererAdapter
+ implements ParserExtension {
+
+ @Override
+ public void extend( final Parser.Builder builder ) {
+ builder.customInlineParserFactory( AnchorXrefInlineParser::new );
+ builder.customDelimiterProcessor( new AnchorNameDelimiterProcessor() );
+ }
+
+ @Override
+ public void extend( @NotNull final HtmlRenderer.Builder builder,
+ @NotNull final String rendererType ) {
+ if( "HTML".equalsIgnoreCase( rendererType ) ) {
+ builder.nodeRendererFactory( new CrossReferencesNodeRenderer.Factory() );
+ }
+ }
+
+ @Override
+ public void parserOptions( final MutableDataHolder options ) {}
+}
src/main/java/com/keenwrite/processors/markdown/extensions/references/CrossReferenceNode.java
+/* Copyright 2023 White Magic Software, Ltd. -- All rights reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ */
+package com.keenwrite.processors.markdown.extensions.references;
+
+import com.vladsch.flexmark.html.HtmlWriter;
+
+/**
+ * Responsible for generating anchor links, either named or cross-referenced.
+ */
+interface CrossReferenceNode {
+ String getTypeName();
+
+ String getIdName();
+
+ String getRefAttrName();
+
+ default String toHtml() {
+ final String typeName = getTypeName();
+ final String idName = getIdName();
+
+ return toHtml( typeName, idName );
+ }
+
+ default String toHtml( final String type, final String id ) {
+ return STR.
+ "<a data-type=\"\{ type }\" \{ getRefAttrName() }=\"\{ id }\" />" ;
+ }
+
+ default void write( final HtmlWriter html ) {
+ html.raw( toHtml() );
+ }
+}
src/main/java/com/keenwrite/processors/markdown/extensions/references/CrossReferencesNodeRenderer.java
+/* Copyright 2023 White Magic Software, Ltd. -- All rights reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ */
+package com.keenwrite.processors.markdown.extensions.references;
+
+import com.vladsch.flexmark.html.HtmlWriter;
+import com.vladsch.flexmark.html.renderer.NodeRenderer;
+import com.vladsch.flexmark.html.renderer.NodeRendererContext;
+import com.vladsch.flexmark.html.renderer.NodeRendererFactory;
+import com.vladsch.flexmark.html.renderer.NodeRenderingHandler;
+import com.vladsch.flexmark.util.data.DataHolder;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Responsible for rendering HTML elements that correspond to cross-references.
+ */
+class CrossReferencesNodeRenderer implements NodeRenderer {
+
+ @Override
+ public Set<NodeRenderingHandler<?>> getNodeRenderingHandlers() {
+ return new HashSet<>( Arrays.asList(
+ new NodeRenderingHandler<>( AnchorNameNode.class, this::render ),
+ new NodeRenderingHandler<>( AnchorXrefNode.class, this::render )
+ ) );
+ }
+
+ private void render( final CrossReferenceNode node,
+ final NodeRendererContext context,
+ final HtmlWriter html ) {
+ node.write( html );
+ }
+
+ public static class Factory implements NodeRendererFactory {
+ private final NodeRenderer mNodeRenderer;
+
+ public Factory() {
+ mNodeRenderer = new CrossReferencesNodeRenderer();
+ }
+
+ @NotNull
+ @Override
+ public NodeRenderer apply( @NotNull final DataHolder options ) {
+ return mNodeRenderer;
+ }
+ }
+}