Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support xref aka cross reference link fix in adoc #649

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
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
12 changes: 5 additions & 7 deletions jbake-core/src/main/java/org/jbake/app/Crawler.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.jbake.app;

import com.orientechnologies.orient.core.record.impl.ODocument;
import org.apache.commons.configuration2.CompositeConfiguration;
import org.apache.commons.io.FilenameUtils;
import org.jbake.app.configuration.JBakeConfiguration;
Expand All @@ -19,7 +18,6 @@
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;

/**
* Crawls a file system looking for content.
Expand Down Expand Up @@ -269,9 +267,9 @@ private void processSourceFile(final File sourceFile, final String sha1, final S
if (DocumentTypes.contains(document.getType())) {
addAdditionalDocumentAttributes(document, sourceFile, sha1, uri);

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

db.addDocument(document);
Expand All @@ -293,8 +291,8 @@ private void addAdditionalDocumentAttributes(DocumentModel document, File source
document.setCached(true);

if (document.getStatus().equals(ModelAttributes.Status.PUBLISHED_DATE)
&& (document.getDate() != null)
&& new Date().after(document.getDate())) {
&& (document.getDate() != null)
&& new Date().after(document.getDate())) {
document.setStatus(ModelAttributes.Status.PUBLISHED);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static org.jbake.app.configuration.PropertyList.*;

Expand Down Expand Up @@ -228,7 +229,6 @@ public void setDatabaseStore(String storeType) {
}



@Override
public String getDateFormat() {
return getAsString(DATE_FORMAT.getKey());
Expand Down Expand Up @@ -586,7 +586,7 @@ private void setupDefaultDestination() {
String destinationPath = getAsString(DESTINATION_FOLDER.getKey());

File destination = new File(destinationPath);
if ( destination.isAbsolute() ) {
if (destination.isAbsolute()) {
setDestinationFolder(destination);
} else {
setDestinationFolder(new File(getSourceFolder(), destinationPath));
Expand All @@ -598,7 +598,7 @@ private void setupDefaultAssetFolder() {


File asset = new File(assetFolder);
if(asset.isAbsolute()) {
if (asset.isAbsolute()) {
setAssetFolder(asset);
} else {
setAssetFolder(new File(getSourceFolder(), assetFolder));
Expand All @@ -609,7 +609,7 @@ private void setupDefaultTemplateFolder() {
String templateFolder = getAsString(TEMPLATE_FOLDER.getKey());

File template = new File(templateFolder);
if(template.isAbsolute()) {
if (template.isAbsolute()) {
setTemplateFolder(template);
} else {
setTemplateFolder(new File(getSourceFolder(), templateFolder));
Expand All @@ -620,7 +620,7 @@ private void setupDefaultDataFolder() {
String dataFolder = getAsString(DATA_FOLDER.getKey());

File data = new File(dataFolder);
if(data.isAbsolute()) {
if (data.isAbsolute()) {
setDataFolder(data);
} else {
setDataFolder(new File(getSourceFolder(), dataFolder));
Expand All @@ -645,17 +645,36 @@ public boolean getImgPathPrependHost() {
return getAsBoolean(IMG_PATH_PREPEND_HOST.getKey());
}

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

public void setRelativePathPrependHost(boolean relativePathPrependHost) {
setBothPathPrependHost(relativePathPrependHost);
}

public void setImgPathPrependHost(boolean imgPathPrependHost) {
setProperty(IMG_PATH_PREPEND_HOST.getKey(), imgPathPrependHost);
setBothPathPrependHost(imgPathPrependHost);
}

private void setBothPathPrependHost(boolean prependHost) {
setProperty(RELATIVE_PATH_PREPEND_HOST.getKey(), prependHost);
setProperty(IMG_PATH_PREPEND_HOST.getKey(), prependHost);
}

@Override
public boolean getImgPathUpdate() {
return getAsBoolean(IMG_PATH_UPDATE.getKey());
}

public void setImgPathUPdate(boolean imgPathUpdate) {
setProperty(IMG_PATH_UPDATE.getKey(), imgPathUpdate);
public void setImgPathUpdate(boolean imgPathUpdate) {
setBothPathUpdate(imgPathUpdate);
}

public void setBothPathUpdate(boolean pathUpdate) {
setProperty(IMG_PATH_UPDATE.getKey(), pathUpdate);
setProperty(RELATIVE_PATH_UPDATE.getKey(), pathUpdate);
}

public List<Property> getJbakeProperties() {
Expand Down Expand Up @@ -693,4 +712,49 @@ public String getAbbreviatedGitHash() {
public String getJvmLocale() {
return getAsString(JVM_LOCALE.getKey());
}

@Override
public boolean getRelativePathUpdate() {
return getAsBoolean(RELATIVE_PATH_UPDATE.getKey());
}

public void setRelativePathUpdate(boolean relativePathUpdate) {
setBothPathUpdate(relativePathUpdate);
}

private static final String EQ = "=";
private static final String COMMA = ",";

@Override
public Map<String, String> getTagAttributes() {
List<String> pairs = getAsList(RELATIVE_TAG_ATTRIBUTE.getKey());
Map<String, String> tagAttribute = new HashMap<>();
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 addTagAttribute(String tag, String attr) {
Map<String, String> all = new HashMap<>();
Map<String, String> map = getTagAttributes();
if (null != map) {
all.putAll(map);
}
all.put(tag, attr);
String val = all.entrySet().stream()
.map(e -> String.join(EQ, e.getKey(), e.getValue()))
.collect(Collectors.joining(COMMA));

setProperty(RELATIVE_TAG_ATTRIBUTE.getKey(), val);
}

public void setTagAttributes(String... tagAttributes) {
setProperty(RELATIVE_TAG_ATTRIBUTE.getKey(), StringUtils.join(tagAttributes, COMMA));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

/**
* 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 @@ -325,12 +325,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 @@ -129,6 +129,20 @@ public abstract class PropertyList {
"img.path.update",
"update image path?"
);
public static final Property RELATIVE_PATH_UPDATE = new Property(
"relative.path.update",
"update relative path?"
);

public static final Property RELATIVE_PATH_PREPEND_HOST = new Property(
"relative.path.prepend.host",
"Prepend site.host to relative paths"
);

public static final Property RELATIVE_TAG_ATTRIBUTE = new Property(
"relative.tag.attribute",
"Define tag and it's attribute that may contains relative paths"
);

public static final Property IMG_PATH_PREPEND_HOST = new Property(
"img.path.prepend.host",
Expand Down
62 changes: 38 additions & 24 deletions jbake-core/src/main/java/org/jbake/util/HtmlUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,47 @@
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.util.Map;

/**
* @author Manik Magar
*/
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(DocumentModel fileContents, JBakeConfiguration configuration) {
public static void fixUrls(DocumentModel fileContents, JBakeConfiguration configuration) {
String htmlContent = fileContents.getBody();
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.
Expand All @@ -49,46 +62,47 @@ private static String getDocumentUri(DocumentModel 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);
}
}
6 changes: 6 additions & 0 deletions jbake-core/src/main/resources/default.properties
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@ 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

# file used to ignore a directory
ignore.file=.jbakeignore
Loading