33import com .vladsch .flexmark .ast .Image ;
44import com .vladsch .flexmark .ast .Link ;
55import com .vladsch .flexmark .ast .Reference ;
6+ import com .vladsch .flexmark .docx .converter .DocxRenderer ;
7+ import com .vladsch .flexmark .docx .converter .internal .DocxLinkResolver ;
8+ import com .vladsch .flexmark .ext .jekyll .tag .JekyllTagBlock ;
69import com .vladsch .flexmark .html .HtmlRenderer ;
710import com .vladsch .flexmark .html .HtmlRenderer .Builder ;
811import com .vladsch .flexmark .html .HtmlRenderer .HtmlRendererExtension ;
@@ -33,36 +36,36 @@ public class CustomLinkResolverSample {
3336 static final HtmlRenderer RENDERER = HtmlRenderer .builder (OPTIONS ).build ();
3437
3538 public static class DocxLinkResolver implements LinkResolver {
36- protected static final String [] EMPTY_STRINGS = new String [0 ];
3739 final private String docRelativeURL ;
3840 final private String docRootURL ;
3941 final private String [] relativeParts ;
42+ final private boolean prefixWwwLinks ;
4043
4144 public DocxLinkResolver (LinkResolverBasicContext context ) {
4245 // can use context for custom settings
43- // context.getDocument();
44- // context.getHtmlOptions();
45- String docRelativeURL = DOC_RELATIVE_URL .get (context .getOptions ());
46- if (docRelativeURL != null ) {
47- docRelativeURL = Utils .removePrefix (docRelativeURL , '/' );
48- }
49-
50- String docRootURL = DOC_ROOT_URL .get (context .getOptions ());
51- if (docRootURL != null ) {
52- docRootURL = Utils .removePrefix (docRootURL , '/' );
53- }
46+ String docRelativeURL = DocxRenderer .DOC_RELATIVE_URL .get (context .getOptions ());
47+ String docRootURL = DocxRenderer .DOC_ROOT_URL .get (context .getOptions ());
5448 this .docRelativeURL = docRelativeURL ;
5549 this .docRootURL = docRootURL ;
56- relativeParts = docRelativeURL == null ? EMPTY_STRINGS : docRelativeURL .split ("/" );
50+
51+ docRelativeURL = Utils .removePrefix (docRelativeURL , '/' );
52+
53+ relativeParts = docRelativeURL .split ("/" );
54+ prefixWwwLinks = DocxRenderer .PREFIX_WWW_LINKS .get (context .getOptions ());
5755 }
5856
5957 @ NotNull
6058 @ Override
6159 public ResolvedLink resolveLink (@ NotNull Node node , @ NotNull LinkResolverBasicContext context , @ NotNull ResolvedLink link ) {
62- if (node instanceof Image || node instanceof Link || node instanceof Reference ) {
63- // resolve wiki image link
60+ if (node instanceof Image || node instanceof Link || node instanceof Reference || node instanceof JekyllTagBlock ) {
6461 String url = link .getUrl ();
6562
63+ if (docRelativeURL .isEmpty () && docRootURL .isEmpty ()) {
64+ // resolve url, return one of LinkStatus other than LinkStatus.UNKNOWN
65+ return link .withStatus (LinkStatus .VALID )
66+ .withUrl (url );
67+ }
68+
6669 if (url .startsWith ("http://" ) || url .startsWith ("https://" ) || url .startsWith ("ftp://" ) || url .startsWith ("sftp://" )) {
6770 // resolve url, return one of LinkStatus other than LinkStatus.UNKNOWN
6871 return link .withStatus (LinkStatus .VALID )
@@ -71,63 +74,78 @@ public ResolvedLink resolveLink(@NotNull Node node, @NotNull LinkResolverBasicCo
7174 // assume it is good
7275 return link .withStatus (LinkStatus .VALID )
7376 .withUrl (url );
77+ } else if (url .startsWith (DocxRenderer .EMOJI_RESOURCE_PREFIX )) {
78+ // assume it is good
79+ return link .withStatus (LinkStatus .VALID )
80+ .withUrl (url );
7481 } else if (url .startsWith ("/" )) {
7582 if (docRootURL != null && !docRootURL .isEmpty ()) {
7683 // this one is root url, prefix with root url, without the trailing /
7784 url = docRootURL + url ;
78-
85+ if (! url . startsWith ( "file:" )) url = "file://" + url ;
7986 return link .withStatus (LinkStatus .VALID )
8087 .withUrl (url );
8188 }
82- } else if (!url .matches ("^(?:[a-z]+:|#|\\ ?)" )) {
89+ } else if (prefixWwwLinks && url .startsWith ("www." )) {
90+ // should be prefixed with http://, we will just add it
91+ return link .withStatus (LinkStatus .INVALID )
92+ .withUrl ("http://" + url );
93+ } else if (!url .startsWith ("data:" ) && !url .matches ("^(?:[a-z]+:|#|\\ ?)" )) {
8394 // relative, we will process it as a relative path to the docRelativeURL
8495 String pageRef = url ;
8596 String suffix = "" ;
8697 int pos = url .indexOf ('#' );
87- if (pos > 0 ) {
88- // remove anchor
89- suffix = url .substring (pos );
90- pageRef = url .substring (0 , pos );
91- } else if (url .contains ("?" )) {
92- // remove query
93- suffix = url .substring (pos );
94- pageRef = url .substring (0 , pos );
95- }
98+ if (pos == 0 ) {
99+ return link .withStatus (LinkStatus .VALID );
100+ } else {
101+ if (pos > 0 ) {
102+ // remove anchor
103+ suffix = url .substring (pos );
104+ pageRef = url .substring (0 , pos );
105+ } else if (url .contains ("?" )) {
106+ // remove query
107+ pos = url .indexOf ("?" );
108+ suffix = url .substring (pos );
109+ pageRef = url .substring (0 , pos );
110+ }
111+
112+ String [] pathParts = pageRef .split ("/" );
113+ int docParts = relativeParts .length ;
114+ int iMax = pathParts .length ;
115+ StringBuilder resolved = new StringBuilder ();
116+ String sep = "" ;
117+
118+ for (int i = 0 ; i < iMax ; i ++) {
119+ String part = pathParts [i ];
120+ if (part .equals ("." )) {
121+ // skp
122+ } else if (part .equals (".." )) {
123+ // remove one doc part
124+ if (docParts == 0 ) return link ;
125+ docParts --;
126+ } else {
127+ resolved .append (sep );
128+ resolved .append (part );
129+ sep = "/" ;
130+ }
131+ }
96132
97- String [] pathParts = pageRef .split ("/" );
98- int docParts = relativeParts .length ;
99- int iMax = pathParts .length ;
100- StringBuilder resolved = new StringBuilder ();
101- String sep = "" ;
102-
103- for (int i = 0 ; i < iMax ; i ++) {
104- String part = pathParts [i ];
105- if (part .equals ("." )) {
106- // skp
107- } else if (part .equals (".." )) {
108- // remove one doc part
109- if (docParts == 0 ) return link ;
110- docParts --;
111- } else {
112- resolved .append (sep );
113- resolved .append (part );
133+ // prefix with remaining docParts
134+ sep = docRelativeURL .startsWith ("/" ) ? "/" : "" ;
135+ StringBuilder resolvedPath = new StringBuilder ();
136+ iMax = docParts ;
137+ for (int i = 0 ; i < iMax ; i ++) {
138+ resolvedPath .append (sep );
139+ resolvedPath .append (relativeParts [i ]);
114140 sep = "/" ;
115141 }
116- }
117142
118- // prefix with remaining docParts
119- sep = docRelativeURL .startsWith ("/" ) ? "/" : "" ;
120- StringBuilder resolvedURL = new StringBuilder ();
121- iMax = docParts ;
122- for (int i = 0 ; i < iMax ; i ++) {
123- resolvedURL .append (sep );
124- resolvedURL .append (relativeParts [i ]);
125- sep = "/" ;
143+ resolvedPath .append ('/' ).append (resolved ).append (suffix );
144+ String resolvedUri = resolvedPath .toString ();
145+ if (!resolvedUri .startsWith ("file:" )) resolvedUri = "file://" + resolvedUri ;
146+ return link .withStatus (LinkStatus .VALID )
147+ .withUrl (resolvedUri );
126148 }
127-
128- resolvedURL .append ('/' ).append (resolved ).append (suffix );
129- return link .withStatus (LinkStatus .VALID )
130- .withUrl (resolvedURL .toString ());
131149 }
132150 }
133151 return link ;
@@ -158,7 +176,7 @@ public LinkResolver apply(@NotNull LinkResolverBasicContext context) {
158176 }
159177 }
160178 }
161-
179+
162180 static class CustomExtension implements HtmlRendererExtension {
163181 @ Override
164182 public void rendererOptions (@ NotNull MutableDataHolder options ) {
0 commit comments