Skip to content

Commit

Permalink
Fix tag <a href='../path' /> url
Browse files Browse the repository at this point in the history
  • Loading branch information
georgecao committed Jun 15, 2020
1 parent c9989a3 commit c056e6a
Show file tree
Hide file tree
Showing 7 changed files with 275 additions and 48 deletions.
6 changes: 3 additions & 3 deletions jbake-core/src/main/java/org/jbake/app/Crawler.java
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,9 @@ private void crawlSourceFile(final File sourceFile, final String sha1, final Str
fileContents.put(Attributes.NO_EXTENSION_URI, uri.replace("/index.html", "/"));
}

if (config.getImgPathUpdate()) {
// Prevent image source url's from breaking
HtmlUtil.fixImageSourceUrls(fileContents, config);
if (config.getImgPathUpdate() || config.getRelativePathUpdate()) {
// Prevent image or other tag's source url's from breaking
HtmlUtil.fixUrls(fileContents, config);
}

ODocument doc = new ODocument(documentType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand Down Expand Up @@ -532,6 +529,15 @@ public boolean getImgPathPrependHost() {
return getAsBoolean(JBakeProperty.IMG_PATH_PREPEND_HOST);
}

@Override
public boolean getRelativePathPrependHost() {
return getAsBoolean(JBakeProperty.RELATIVE_PATH_PREPEND_HOST);
}

public void setRelativePathPrependHost(boolean relativePathPrependHost) {
setProperty(JBakeProperty.RELATIVE_PATH_PREPEND_HOST, relativePathPrependHost);
}

public void setImgPathPrependHost(boolean imgPathPrependHost) {
setProperty(JBakeProperty.IMG_PATH_PREPEND_HOST, imgPathPrependHost);
}
Expand All @@ -541,7 +547,36 @@ public boolean getImgPathUpdate() {
return getAsBoolean(JBakeProperty.IMG_PATH_UPDATE);
}

public void setImgPathUPdate(boolean imgPathUpdate) {
@Override
public boolean getRelativePathUpdate() {
return getAsBoolean(JBakeProperty.RELATIVE_PATH_UPDATE);
}

public void setRelativePathUpdate(String relativePathUpdate) {
setProperty(JBakeProperty.RELATIVE_PATH_UPDATE, relativePathUpdate);
}

@Override
public Map<String, String> getTagAttributes() {
List<String> pairs = getAsList(JBakeProperty.RELATIVE_TAG_ATTRIBUTE);
Map<String, String> tagAttribute = new HashMap<>();
char eq = '=';
for (String pair : pairs) {
int idx = pair.indexOf(eq);
if (idx > 0) {
String tag = pair.substring(0, idx);
String attr = pair.substring(idx + 1);
tagAttribute.put(tag, attr);
}
}
return tagAttribute;
}

public void setTagAttributes(String... tagAttributes) {
setProperty(JBakeProperty.RELATIVE_TAG_ATTRIBUTE, StringUtils.join(tagAttributes, ","));
}

public void setImgPathUpdate(boolean imgPathUpdate) {
setProperty(JBakeProperty.IMG_PATH_UPDATE, imgPathUpdate);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
import java.io.File;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
* JBakeConfiguration gives you access to the project configuration. Typically located in a file called jbake.properties.
*
* <p>
* Use one of {@link JBakeConfigurationFactory} methods to create an instance.
*/
public interface JBakeConfiguration {
Expand Down Expand Up @@ -288,12 +289,29 @@ public interface JBakeConfiguration {
*/
boolean getImgPathPrependHost();

/**
* @return Flag indicating if a relative paths should be prepended with {@link #getSiteHost()} value - only has an effect if
* {@link #getRelativePathUpdate()} is set to true
*/
boolean getRelativePathPrependHost();

/**
* @return Flag indicating if image paths in content should be updated with absolute path (using URI value of content file),
* see {@link #getImgPathUpdate()} which allows you to control the absolute path used
*/
boolean getImgPathUpdate();

/**
* @return Flag indicating if relative paths in content should be updated with absolute path (using URI value of content file),
* see {@link #getRelativePathUpdate()} which allows you to control the absolute path used
*/
boolean getRelativePathUpdate();

/**
* @return Tag and it's attribute name which contains a path that maybe relative.
*/
Map<String, String> getTagAttributes();

/**
* @return Version of JBake
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,12 @@ public class JBakeProperty {
public static final String URI_NO_EXTENSION_PREFIX = "uri.noExtension.prefix";
public static final String IMG_PATH_UPDATE = "img.path.update";
public static final String IMG_PATH_PREPEND_HOST = "img.path.prepend.host";
public static final String RELATIVE_PATH_UPDATE = "relative.path.update";
public static final String RELATIVE_PATH_PREPEND_HOST = "relative.path.prepend.host";
public static final String RELATIVE_TAG_ATTRIBUTE = "relative.tag.attribute";
public static final String VERSION = "version";

private JBakeProperty() {}
private JBakeProperty() {
}

}
61 changes: 36 additions & 25 deletions jbake-core/src/main/java/org/jbake/util/HtmlUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,41 @@
*/
public class HtmlUtil {

private static final char SLASH = '/';
private static final String SLASH_TEXT = String.valueOf(SLASH);
private static final String HTTP = "http://";
private static final String HTTPS = "https://";
private static final String WORKING_DIR = "\\./";
private static final String EMPTY = "";

private HtmlUtil() {
}

/**
* Image paths are specified as w.r.t. assets folder. This function prefix site host to all img src except
* Images or file paths are specified as w.r.t. assets folder. This function prefix site host to all path except
* the ones that starts with http://, https://.
* <p>
* If image path starts with "./", i.e. relative to the source file, then it first replace that with output file directory and the add site host.
* If path starts with "./", i.e. relative to the source file, then it first replace that with output file directory and the add site host.
*
* @param fileContents Map representing file contents
* @param configuration Configuration object
*/
public static void fixImageSourceUrls(Map<String, Object> fileContents, JBakeConfiguration configuration) {
public static void fixUrls(Map<String, Object> fileContents, JBakeConfiguration configuration) {
String htmlContent = fileContents.get(Attributes.BODY).toString();
boolean prependSiteHost = configuration.getImgPathPrependHost();
boolean prependSiteHost = configuration.getImgPathPrependHost() && configuration.getRelativePathPrependHost();
String siteHost = configuration.getSiteHost();
String uri = getDocumentUri(fileContents);

Document document = Jsoup.parseBodyFragment(htmlContent);
Elements allImgs = document.getElementsByTag("img");

for (Element img : allImgs) {
transformImageSource(img, uri, siteHost, prependSiteHost);
Map<String, String> pairs = configuration.getTagAttributes();
for (Map.Entry<String, String> entry : pairs.entrySet()) {
String tagName = entry.getKey();
String attKey = entry.getValue();
Elements allTags = document.getElementsByTag(tagName);
for (Element tag : allTags) {
transformPath(tag, attKey, uri, siteHost, prependSiteHost);
}
}

//Use body().html() to prevent adding <body></body> from parsed fragment.
fileContents.put(Attributes.BODY, document.body().html());
}
Expand All @@ -51,46 +61,47 @@ private static String getDocumentUri(Map<String, Object> fileContents) {
uri = removeTrailingSlash(uri);
}

if (uri.contains("/")) {
if (uri.contains(SLASH_TEXT)) {
uri = removeFilename(uri);
}
return uri;
}

private static void transformImageSource(Element img, String uri, String siteHost, boolean prependSiteHost) {
String source = img.attr("src");
private static void transformPath(Element tag, String attrKey, String uri, String siteHost, boolean prependSiteHost) {
String path = tag.attr(attrKey);

// Now add the root path
if (!source.startsWith("http://") && !source.startsWith("https://")) {

if (isRelative(source)) {
source = uri + source.replaceFirst("\\./", "");
if (!isUrl(path)) {
if (isRelative(path)) {
path = uri + path.replaceFirst(WORKING_DIR, EMPTY);
}

if (prependSiteHost) {
if (!siteHost.endsWith("/") && isRelative(source)) {
siteHost = siteHost.concat("/");
if (!siteHost.endsWith(SLASH_TEXT) && isRelative(path)) {
siteHost = siteHost.concat(SLASH_TEXT);
}
source = siteHost + source;
path = siteHost + path;
}

img.attr("src", source);
tag.attr(attrKey, path);
}
}

private static String removeFilename(String uri) {
uri = uri.substring(0, uri.lastIndexOf('/') + 1);
uri = uri.substring(0, uri.lastIndexOf(SLASH) + 1);
return uri;
}

private static String removeTrailingSlash(String uri) {
if (uri.endsWith("/")) {
if (uri.endsWith(SLASH_TEXT)) {
uri = uri.substring(0, uri.length() - 1);
}
return uri;
}

private static boolean isUrl(String path) {
return path.startsWith(HTTP) || path.startsWith(HTTPS);
}

private static boolean isRelative(String source) {
return !source.startsWith("/");
return !source.startsWith(SLASH_TEXT);
}
}
10 changes: 8 additions & 2 deletions jbake-core/src/main/resources/default.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# application version
version=v${jbakeVersion}
# build timestamp
build.timestamp=${timestamp}
build.timestamp=${timestamp}
# path to destination folder by default
destination.folder=output
# folder that contains all template files
Expand Down Expand Up @@ -58,7 +58,7 @@ render.tagsindex=false
# folder name to use for tag files
tag.path=tags
# sanitize tag value before it is used as filename (i.e. replace spaces with hyphens)
tag.sanitize=false
tag.sanitize=false

# file extension for output content files
output.extension=.html
Expand Down Expand Up @@ -124,3 +124,9 @@ header.separator=~~~~~~
img.path.update=false
# Prepend site.host to image paths
img.path.prepend.host=true
# update relative path
relative.path.update=false
# prepend site.host to tag paths
relative.path.prepend.host=true
# relative tag and attribute, for img's src and a's href.
relative.tag.attribute=img=src,a=href
Loading

0 comments on commit c056e6a

Please sign in to comment.