| import org.jsoup.helper.W3CDom; | ||
| import org.jsoup.nodes.Document.OutputSettings.Syntax; | ||
| +import org.jsoup.nodes.DocumentType; | ||
| import org.jsoup.nodes.Node; | ||
| import org.jsoup.nodes.TextNode; | ||
| import static com.keenwrite.dom.DocumentParser.sDomImplementation; | ||
| import static com.keenwrite.processors.text.TextReplacementFactory.replace; | ||
| -import static java.util.Map.*; | ||
| +import static java.util.Map.entry; | ||
| +import static java.util.Map.ofEntries; | ||
| /** | ||
| * Responsible for converting JSoup document object model (DOM) to a W3C DOM. | ||
| * Provides a lighter implementation than the superclass by overriding the | ||
| * {@link #fromJsoup(org.jsoup.nodes.Document)} method to reuse factories, | ||
| * builders, and implementations. | ||
| */ | ||
| public final class DocumentConverter extends W3CDom { | ||
| + private static final DocumentType DOCTYPE = | ||
| + new DocumentType( "html", "", "" ); | ||
| + | ||
| /** | ||
| * Retain insertion order using an instance of {@link LinkedHashMap} so | ||
| final var parent = node.parentNode(); | ||
| final var name = parent == null ? "root" : parent.nodeName(); | ||
| - | ||
| - if( !("pre".equalsIgnoreCase( name ) || | ||
| + final var codeBlock = | ||
| + "pre".equalsIgnoreCase( name ) || | ||
| "code".equalsIgnoreCase( name ) || | ||
| "kbd".equalsIgnoreCase( name ) || | ||
| "var".equalsIgnoreCase( name ) || | ||
| - "tt".equalsIgnoreCase( name )) ) { | ||
| - // Calling getWholeText() will return newlines, which must be kept | ||
| + "tt".equalsIgnoreCase( name ); | ||
| + | ||
| + if( !codeBlock ) { | ||
| + // Obtaining the whole text will return newlines, which must be kept | ||
| // to ensure that preformatted text maintains its formatting. | ||
| textNode.text( replace( textNode.getWholeText(), LIGATURES ) ); | ||
| } | ||
| } | ||
| } | ||
| @Override | ||
| - public void tail( final @NotNull Node node, final int depth ) { } | ||
| + public void tail( final @NotNull Node node, final int depth ) {} | ||
| }; | ||
| document | ||
| .outputSettings() | ||
| - .syntax( Syntax.xml ) | ||
| + .syntax( Syntax.html ) | ||
| .prettyPrint( false ); | ||
| + | ||
| + document.prependChild( DOCTYPE ); | ||
| return document; | ||
| */ | ||
| private static final String HTML_HEAD = """ | ||
| - <!doctype html> | ||
| <html lang='%s'><head><title> </title><meta charset='utf-8'/> | ||
| %s%s%s<style>body{font-family:'%s';font-size: %dpx;}</style>%s</head><body> | ||
| public void render( final String html ) { | ||
| final var jsoupDoc = DocumentConverter.parse( decorate( html ) ); | ||
| + | ||
| + // Ensure the title (metadata) doesn't appear in the preview panel. | ||
| + jsoupDoc.select( "title" ).remove(); | ||
| + | ||
| final var doc = CONVERTER.fromJsoup( jsoupDoc ); | ||
| final var uri = getBaseUri(); | ||
| @Override | ||
| - public void componentMoved( final ComponentEvent e ) { } | ||
| + public void componentMoved( final ComponentEvent e ) {} | ||
| @Override | ||
| - public void componentShown( final ComponentEvent e ) { } | ||
| + public void componentShown( final ComponentEvent e ) {} | ||
| @Override | ||
| - public void componentHidden( final ComponentEvent e ) { } | ||
| + public void componentHidden( final ComponentEvent e ) {} | ||
| private static String toStylesheetString( final URL url ) { | ||
| import java.util.List; | ||
| +import static com.keenwrite.util.Strings.sanitize; | ||
| + | ||
| /** | ||
| * Responsible for parsing and rendering Markdown into HTML. This is required | ||
| * to break a circular dependency between the {@link MarkdownProcessor} and | ||
| * {@link RInlineExtension}. | ||
| */ | ||
| public class BaseMarkdownProcessor extends ExecutorProcessor<String> { | ||
| - | ||
| private final IParse mParser; | ||
| private final IRender mRenderer; | ||
| + private final String mTitle; | ||
| public BaseMarkdownProcessor( | ||
| final Processor<String> successor, final ProcessorContext context ) { | ||
| super( successor ); | ||
| + final var metadata = context.getMetadata(); | ||
| final var options = new MutableDataSet(); | ||
| options.set( HtmlRenderer.GENERATE_HEADER_ID, true ); | ||
| .extensions( extensions ) | ||
| .build(); | ||
| + mTitle = metadata.get( "title" ); | ||
| } | ||
| */ | ||
| private String toXhtml( final String html ) { | ||
| - return DocumentConverter.parse( html ).html(); | ||
| + final var document = DocumentConverter.parse( html ); | ||
| + final var title = sanitize( mTitle ); | ||
| + | ||
| + // Ensure the document title is written when generating HTML. | ||
| + if( !title.isBlank() ) { | ||
| + document.title( title ); | ||
| + } | ||
| + | ||
| + return document.html(); | ||
| } | ||
| Author | DaveJarvis <email> |
|---|---|
| Date | 2024-10-11 18:41:23 GMT-0700 |
| Commit | 6a09f4869c89a24f5f9d0fe3ae0b8a69c185cd89 |
| Parent | b61ace2 |
| Delta | 37 lines added, 13 lines removed, 24-line increase |