Made secondaryTabs, socialLinks and footerSiteMap config more compact. Added support for "olink:" and "id:" URL-s to them. Some code cleanup and somewhat better error messages.
diff --git a/src/main/org/freemarker/docgen/Transform.java b/src/main/org/freemarker/docgen/Transform.java
index f3f384e..62c6c79 100644
--- a/src/main/org/freemarker/docgen/Transform.java
+++ b/src/main/org/freemarker/docgen/Transform.java
@@ -40,6 +40,7 @@
import java.nio.charset.Charset;
import java.text.Collator;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
@@ -483,6 +484,9 @@
private static final String PAGE_TYPE_DETAILED_TOC = "docgen:detailed_toc";
private static final String PAGE_TYPE_SEARCH_RESULTS = "docgen:search_results";
+ private static final String OLINK_SCHEMA_START = "olink:";
+ private static final String ID_SCHEMA_START = "id:";
+
private static final Charset UTF_8 = Charset.forName("UTF-8");
// Docgen-specific XML attributes (added during DOM-tree postediting):
@@ -624,8 +628,6 @@
private String searchKey;
- private Object footerSiteMap;
-
private boolean disableJavaScript;
private boolean validate = true;
@@ -638,11 +640,12 @@
private LinkedHashMap<String, String> internalBookmarks = new LinkedHashMap<String, String>();
private LinkedHashMap<String, String> externalBookmarks = new LinkedHashMap<>();
+ private Map<String, Map<String, String>> footerSiteMap;
private LinkedHashMap<String, String> tabs = new LinkedHashMap<>();
- private Object secondaryTabs;
- private Object socialLinks;
+ private Map<String, Map<String, String>> secondaryTabs;
+ private Map<String, Map<String, String>> socialLinks;
private HashMap<String, String> logo;
@@ -746,41 +749,41 @@
final Object settingValue = cfgEnt.getValue();
if (settingName.equals(SETTING_OLINKS)) {
- Map<String, Object> m = itIsAMapSetting(
+ Map<String, Object> m = castSettingToMap(
cfgFile, settingName, settingValue);
for (Entry<String, Object> ent : m.entrySet()) {
String name = ent.getKey();
- String target = itIsAStringValueInAMapSetting(
+ String target = castSettingValueMapValueToString(
cfgFile, settingName, ent.getValue());
olinks.put(name, target);
}
} else if (settingName.equals(SETTING_INTERNAL_BOOKMARKS)) {
- Map<String, Object> m = itIsAMapSetting(
+ Map<String, Object> m = castSettingToMap(
cfgFile, settingName, settingValue);
for (Entry<String, Object> ent : m.entrySet()) {
String name = ent.getKey();
- String target = itIsAStringValueInAMapSetting(
+ String target = castSettingValueMapValueToString(
cfgFile, settingName, ent.getValue());
internalBookmarks.put(name, target);
}
// Book-mark targets will be checked later, when the XML
// document is already loaded.
} else if (settingName.equals(SETTING_EXTERNAL_BOOKMARKS)) {
- Map<String, Object> m = itIsAMapSetting(
+ Map<String, Object> m = castSettingToMap(
cfgFile, settingName, settingValue);
for (Entry<String, Object> ent : m.entrySet()) {
String name = ent.getKey();
- String target = itIsAStringValueInAMapSetting(
+ String target = castSettingValueMapValueToString(
cfgFile, settingName, ent.getValue());
externalBookmarks.put(name, target);
}
} else if (settingName.equals(SETTING_LOGO)) {
- Map<String, Object> m = itIsAMapSetting(
+ Map<String, Object> m = castSettingToMap(
cfgFile, settingName, settingValue);
logo = new HashMap<>();
for (Entry<String, Object> ent : m.entrySet()) {
String k = ent.getKey();
- String v = itIsAStringValueInAMapSetting(cfgFile, settingName, ent.getValue());
+ String v = castSettingValueMapValueToString(cfgFile, settingName, ent.getValue());
if (!(k.equals(SETTING_LOGO_SRC) || k.equals(SETTING_LOGO_ALT)
|| k.equals(SETTING_LOGO_HREF))) {
throw newCfgFileException(cfgFile, SETTING_LOGO, "Unknown logo option: " + k);
@@ -797,39 +800,55 @@
throw newCfgFileException(cfgFile, SETTING_LOGO, "Missing logo option: " + SETTING_LOGO_HREF);
}
} else if (settingName.equals(SETTING_TABS)) {
- Map<String, Object> m = itIsAMapSetting(
+ Map<String, Object> m = castSettingToMap(
cfgFile, settingName, settingValue);
for (Entry<String, Object> ent : m.entrySet()) {
- String name = ent.getKey();
- String target = itIsAStringValueInAMapSetting(
- cfgFile, settingName, ent.getValue());
- tabs.put(name, target);
+ String k = ent.getKey();
+ String v = castSettingValueMapValueToString(cfgFile, settingName, ent.getValue());
+ tabs.put(k, v);
}
} else if (settingName.equals(SETTING_SECONDARY_TABS)) {
- // @todo: How can I check this?
- secondaryTabs = settingValue;
+ Map<String, Object> m = castSettingToMap(
+ cfgFile, settingName, settingValue);
+ secondaryTabs = new LinkedHashMap<>();
+ for (Entry<String, Object> ent : m.entrySet()) {
+ String k = ent.getKey();
+ Map<String, String> v = castSettingValueMapValueToMapOfStringString(
+ cfgFile, settingName, ent.getValue(),
+ "class", "href");
+ secondaryTabs.put(k, v);
+ }
} else if (settingName.equals(SETTING_SOCIAL_LINKS)) {
- // @todo: How can I check this?
- socialLinks = settingValue;
+ Map<String, Object> m = castSettingToMap(
+ cfgFile, settingName, settingValue);
+ socialLinks = new LinkedHashMap<>();
+ for (Entry<String, Object> ent : m.entrySet()) {
+ String entName = ent.getKey();
+ Map<String, String> entValue = castSettingValueMapValueToMapOfStringString(
+ cfgFile, settingName, ent.getValue(),
+ "class", "href");
+ socialLinks.put(entName, entValue);
+ }
} else if (settingName.equals(SETTING_FOOTER_SITEMAP)) {
- // @todo: How can I check this?
- footerSiteMap = settingValue;
+ // TODO Check value in more details
+ footerSiteMap = (Map) castSettingToMap(
+ cfgFile, settingName, settingValue);
}else if (settingName.equals(SETTING_VALIDATION)) {
- Map<String, Object> m = itIsAMapSetting(
+ Map<String, Object> m = castSettingToMap(
cfgFile, SETTING_VALIDATION, settingValue);
for (Entry<String, Object> ent : m.entrySet()) {
String name = ent.getKey();
if (name.equals(
SETTING_VALIDATION_PROGRAMLISTINGS_REQ_ROLE)) {
validationOps.setProgramlistingRequiresRole(
- itIsABooleanSetting(
+ caseSettingToBoolean(
cfgFile,
settingName + "." + name,
ent.getValue()));
} else if (name.equals(
SETTING_VALIDATION_PROGRAMLISTINGS_REQ_LANG)) {
validationOps.setProgramlistingRequiresLanguage(
- itIsABooleanSetting(
+ caseSettingToBoolean(
cfgFile,
settingName + "." + name,
ent.getValue()));
@@ -837,7 +856,7 @@
SETTING_VALIDATION_OUTPUT_FILES_CAN_USE_AUTOID)
) {
validationOps.setOutputFilesCanUseAutoID(
- itIsABooleanSetting(
+ caseSettingToBoolean(
cfgFile,
settingName + "." + name,
ent.getValue()));
@@ -845,7 +864,7 @@
SETTING_VALIDATION_MAXIMUM_PROGRAMLISTING_WIDTH)
) {
validationOps.setMaximumProgramlistingWidth(
- itIsAnIntSetting(
+ castSettingToInt(
cfgFile,
settingName + "." + name,
ent.getValue()));
@@ -857,14 +876,14 @@
}
} else if (settingName.equals(SETTING_OFFLINE)) {
if (offline == null) { // Ignore if the caller has already set this
- offline = itIsABooleanSetting(cfgFile, settingName, settingValue);
+ offline = caseSettingToBoolean(cfgFile, settingName, settingValue);
}
} else if (settingName.equals(SETTING_SIMPLE_NAVIGATION_MODE)) {
- simpleNavigationMode = itIsABooleanSetting(cfgFile, settingName, settingValue);
+ simpleNavigationMode = caseSettingToBoolean(cfgFile, settingName, settingValue);
} else if (settingName.equals(SETTING_DEPLOY_URL)) {
- deployUrl = itIsAStringSetting(cfgFile, settingName, settingValue);
+ deployUrl = castSettingToString(cfgFile, settingName, settingValue);
} else if (settingName.equals(SETTING_ONLINE_TRACKER_HTML)) {
- String onlineTrackerHtmlPath = itIsAStringSetting(cfgFile, settingName, settingValue);
+ String onlineTrackerHtmlPath = castSettingToString(cfgFile, settingName, settingValue);
File f = new File(getSourceDirectory(), onlineTrackerHtmlPath);
if (!f.exists()) {
throw newCfgFileException(
@@ -873,12 +892,12 @@
}
onlineTrackerHTML = FileUtil.loadString(f, UTF_8);
} else if (settingName.equals(SETTING_ECLIPSE)) {
- Map<String, Object> m = itIsAMapSetting(
+ Map<String, Object> m = castSettingToMap(
cfgFile, SETTING_ECLIPSE, settingValue);
for (Entry<String, Object> ent : m.entrySet()) {
String name = ent.getKey();
if (name.equals(SETTING_ECLIPSE_LINK_TO)) {
- String value = itIsAStringSetting(
+ String value = castSettingToString(
cfgFile,
settingName + "." + name,
ent.getValue());
@@ -890,30 +909,30 @@
}
}
} else if (settingName.equals(SETTING_LOCALE)) {
- String s = itIsAStringSetting(
+ String s = castSettingToString(
cfgFile, settingName, settingValue);
locale = StringUtil.deduceLocale(s);
} else if (settingName.equals(SETTING_TIME_ZONE)) {
- String s = itIsAStringSetting(
+ String s = castSettingToString(
cfgFile, settingName, settingValue);
timeZone = TimeZone.getTimeZone(s);
} else if (settingName.equals(SETTING_GENERATE_ECLIPSE_TOC)) {
- generateEclipseTOC = itIsABooleanSetting(
+ generateEclipseTOC = caseSettingToBoolean(
cfgFile, settingName, settingValue);
} else if (settingName.equals(SETTING_SHOW_EDITORAL_NOTES)) {
- showEditoralNotes = itIsABooleanSetting(
+ showEditoralNotes = caseSettingToBoolean(
cfgFile, settingName, settingValue);
} else if (settingName.equals(SETTING_SHOW_XXE_LOGO)) {
- showXXELogo = itIsABooleanSetting(
+ showXXELogo = caseSettingToBoolean(
cfgFile, settingName, settingValue);
} else if (settingName.equals(SETTING_SEARCH_KEY)) {
- searchKey = itIsAStringSetting(
+ searchKey = castSettingToString(
cfgFile, settingName, settingValue);
}else if (settingName.equals(SETTING_DISABLE_JAVASCRIPT)) {
- disableJavaScript = itIsABooleanSetting(
+ disableJavaScript = caseSettingToBoolean(
cfgFile, settingName, settingValue);
} else if (settingName.equals(SETTING_CONTENT_DIRECTORY)) {
- String s = itIsAStringSetting(
+ String s = castSettingToString(
cfgFile, settingName, settingValue);
contentDir = new File(srcDir, s);
if (!contentDir.isDirectory()) {
@@ -925,7 +944,7 @@
|| settingName.equals(
SETTING_LOWEST_PAGE_TOC_ELEMENT_RANK)) {
DocumentStructureRank rank;
- String strRank = itIsAStringSetting(
+ String strRank = castSettingToString(
cfgFile, settingName, settingValue);
try {
rank = DocumentStructureRank.valueOf(
@@ -955,7 +974,7 @@
throw new BugException("Unexpected setting name.");
}
} else if (settingName.equals(SETTING_MAX_TOF_DISPLAY_DEPTH)) {
- maxTOFDisplayDepth = itIsAnIntSetting(
+ maxTOFDisplayDepth = castSettingToInt(
cfgFile, settingName, settingValue);
if (maxTOFDisplayDepth < 1) {
throw newCfgFileException(cfgFile, settingName,
@@ -963,14 +982,14 @@
}
} else if (settingName.equals(
SETTING_MAX_MAIN_TOF_DISPLAY_DEPTH)) {
- maxMainTOFDisplayDepth = itIsAnIntSetting(
+ maxMainTOFDisplayDepth = castSettingToInt(
cfgFile, settingName, settingValue);
if (maxTOFDisplayDepth < 1) {
throw newCfgFileException(cfgFile, settingName,
"Value must be at least 1.");
}
} else if (settingName.equals(SETTING_NUMBERED_SECTIONS)) {
- numberedSections = itIsABooleanSetting(
+ numberedSections = caseSettingToBoolean(
cfgFile, settingName, settingValue);
} else {
throw newCfgFileException(cfgFile, "Unknown setting: \""
@@ -1069,6 +1088,30 @@
// - Post-edit and examine the DOM:
preprocessDOM(doc);
+
+ // Resolve Docgen URL schemes in setting values:
+ if (tabs != null) {
+ for (Entry<String, String> tabEnt : tabs.entrySet()) {
+ tabEnt.setValue(resolveDocgenURL(SETTING_TABS, tabEnt.getValue()));
+ }
+ }
+ if (secondaryTabs != null) {
+ for (Map<String, String> tab : secondaryTabs.values()) {
+ tab.put("href", resolveDocgenURL(SETTING_SECONDARY_TABS, tab.get("href")));
+ }
+ }
+ if (socialLinks != null) {
+ for (Map<String, String> tab : socialLinks.values()) {
+ tab.put("href", resolveDocgenURL(SETTING_SOCIAL_LINKS, tab.get("href")));
+ }
+ }
+ if (footerSiteMap != null) {
+ for (Map<String, String> links : footerSiteMap.values()) {
+ for (Map.Entry<String, String> link : links.entrySet()) {
+ link.setValue(resolveDocgenURL(SETTING_FOOTER_SITEMAP, link.getValue()));
+ }
+ }
+ }
// - Create destination directory:
if (!destDir.isDirectory() && !destDir.mkdirs()) {
@@ -1270,6 +1313,34 @@
+ (generateEclipseTOC ? " + Eclipse ToC" : ""));
}
+ /**
+ * Resolves the URL if it uses the {@code "olink:"} schema, returns it as if otherwise.
+ */
+ private String resolveDocgenURL(String settingName, String url) throws DocgenException {
+ if (url.startsWith(OLINK_SCHEMA_START)) {
+ String oLinkName = url.substring(OLINK_SCHEMA_START.length());
+ String resolvedOLink = olinks.get(oLinkName);
+ if (resolvedOLink == null) {
+ throw new DocgenException("Undefined olink used inside configuration setting "
+ + StringUtil.jQuote(settingName)
+ + ": " + StringUtil.jQuote(oLinkName));
+ }
+ return resolvedOLink;
+ } else if (url.startsWith(ID_SCHEMA_START)) {
+ String id = url.substring(ID_SCHEMA_START.length());
+ try {
+ return createLinkFromId(id);
+ } catch (DocgenException e) {
+ throw new DocgenException("Can't resolve id inside configuration setting "
+ + StringUtil.jQuote(settingName)
+ + ": " + StringUtil.jQuote(id),
+ e);
+ }
+ } else {
+ return url;
+ }
+ }
+
private DocgenException newCfgFileException(
File cfgFile, String settingName, String desc) {
settingName = settingName.replace(".", "\" per \"");
@@ -1296,7 +1367,7 @@
}
@SuppressWarnings("unchecked")
- private Map<String, Object> itIsAMapSetting(
+ private Map<String, Object> castSettingToMap(
File cfgFile, String settingName, Object settingValue)
throws DocgenException {
if (!(settingValue instanceof Map)) {
@@ -1309,7 +1380,21 @@
return (Map<String, Object>) settingValue;
}
- private String itIsAStringSetting(File cfgFile,
+ @SuppressWarnings("unchecked")
+ private Map<String, Object> castSettingToList(
+ File cfgFile, String settingName, Object settingValue)
+ throws DocgenException {
+ if (!(settingValue instanceof List)) {
+ throw newCfgFileException(
+ cfgFile, settingName,
+ "Should be a list (like [value1, value2, ... valueN]), but "
+ + "it's a " + CJSONInterpreter.cjsonTypeOf(settingValue)
+ + ".");
+ }
+ return (Map<String, Object>) settingValue;
+ }
+
+ private String castSettingToString(File cfgFile,
String settingName, Object settingValue) throws DocgenException {
if (!(settingValue instanceof String)) {
throw newCfgFileException(
@@ -1320,7 +1405,7 @@
return (String) settingValue;
}
- private boolean itIsABooleanSetting(File cfgFile,
+ private boolean caseSettingToBoolean(File cfgFile,
String settingName, Object settingValue) throws DocgenException {
if (!(settingValue instanceof Boolean)) {
throw newCfgFileException(
@@ -1331,7 +1416,7 @@
return (Boolean) settingValue;
}
- private int itIsAnIntSetting(File cfgFile,
+ private int castSettingToInt(File cfgFile,
String settingName, Object settingValue)
throws DocgenException {
@@ -1352,7 +1437,7 @@
/* Unused at the moment
@SuppressWarnings("unchecked")
- private List<String> itIsAListOfStringsSetting(File cfgFile,
+ private List<String> castSettingToListOfStrings(File cfgFile,
String settingName, Object settingValue) throws DocgenException {
if (!(settingValue instanceof List)) {
throw newCfgFileException(
@@ -1375,7 +1460,7 @@
}
*/
- private String itIsAStringValueInAMapSetting(File cfgFile,
+ private String castSettingValueMapValueToString(File cfgFile,
String settingName, Object mapEntryValue) throws DocgenException {
if (!(mapEntryValue instanceof String)) {
throw newCfgFileException(cfgFile, settingName,
@@ -1386,6 +1471,54 @@
return (String) mapEntryValue;
}
+ @SuppressWarnings("unchecked")
+ private Map<String, String> castSettingValueMapValueToMapOfStringString(File cfgFile,
+ String settingName, Object mapEntryValue, String... expectedKeys) throws DocgenException {
+ if (!(mapEntryValue instanceof Map)) {
+ throw newCfgFileException(cfgFile, settingName,
+ "The values in the key-value pairs of this map must be "
+ + "Map-s, but some of them is a "
+ + CJSONInterpreter.cjsonTypeOf(mapEntryValue) + ".");
+ }
+ Map<?, ?> mapEntryValueAsMap = (Map<?, ?>) mapEntryValue;
+ for (Entry<?, ?> valueEnt : mapEntryValueAsMap.entrySet()) {
+ Object key = valueEnt.getKey();
+ if (!(key instanceof String)) {
+ throw newCfgFileException(cfgFile, settingName,
+ "The values in the key-value pairs of this map must be "
+ + "Map<String, String>-s, but some of the keys is a "
+ + CJSONInterpreter.cjsonTypeOf(mapEntryValue) + ".");
+ }
+ if (!(valueEnt.getValue() instanceof String)) {
+ throw newCfgFileException(cfgFile, settingName,
+ "The values in the key-value pairs of this map must be "
+ + "Map<String, String>-s, but some of the values is a "
+ + CJSONInterpreter.cjsonTypeOf(valueEnt.getValue()) + ".");
+ }
+ if (!Arrays.asList(expectedKeys).contains(key)) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Unsupported key: ");
+ sb.append(StringUtil.jQuote(key));
+ sb.append(". Supported keys are: ");
+ for (int i = 0; i < expectedKeys.length; i++) {
+ String expectedKey = expectedKeys[i];
+ if (i != 0) {
+ sb.append(", ");
+ }
+ sb.append(StringUtil.jQuote(expectedKey));
+ }
+ throw newCfgFileException(cfgFile, settingName, sb.toString());
+ }
+ }
+ for (String expectedKey : expectedKeys) {
+ if (!mapEntryValueAsMap.containsKey(expectedKey)) {
+ throw newCfgFileException(cfgFile, settingName,
+ "Missing map key from nested Map: " + expectedKey);
+ }
+ }
+ return (Map<String, String>) mapEntryValue;
+ }
+
private void copyCommonStatic(String path) throws IOException {
FileUtil.copyResourceIntoFile(
Transform.class, "statics", path,
@@ -2412,23 +2545,25 @@
}
String id = getArgString(args, 0);
- Element elem = elementsById.get(id);
- if (elem == null) {
- throw new TemplateModelException(
- "No element exists with this id: \"" + id + "\"");
- }
-
try {
- String url = createElementLinkURL(elem);
- return url != null ? new SimpleScalar(url) : null;
+ return createLinkFromId(id);
} catch (DocgenException e) {
- throw new TemplateModelException(
- "CreateLinkFromID failed to create link.", e);
+ throw new TemplateModelException("Can't resolve id " + StringUtil.jQuote(id) + " to URL", e);
}
}
};
+ private String createLinkFromId(String id) throws DocgenException {
+ Element elem = elementsById.get(id);
+ if (elem == null) {
+ throw new DocgenException(
+ "No element exists with this id: \"" + id + "\"");
+ }
+
+ return createElementLinkURL(elem);
+ }
+
private TemplateMethodModelEx createLinkFromNode
= new TemplateMethodModelEx() {
diff --git a/src/main/org/freemarker/docgen/templates/footer.ftl b/src/main/org/freemarker/docgen/templates/footer.ftl
index 99f7bf3..1ad8351 100644
--- a/src/main/org/freemarker/docgen/templates/footer.ftl
+++ b/src/main/org/freemarker/docgen/templates/footer.ftl
@@ -1,6 +1,6 @@
<#ftl nsPrefixes={"D":"http://docbook.org/ns/docbook"} stripText = true>
+<#escape x as x?html>
-<#import "ui.ftl" as ui>
<#import "util.ftl" as u>
<#macro footer>
@@ -19,12 +19,12 @@
<div class="footer-top"><#t>
<div class="col-left sitemap"><#t>
<#if footerSiteMap??>
- <@siteMap links=footerSiteMap /><#t>
+ <@siteMap columns=footerSiteMap /><#t>
</#if>
</div><#t>
<div class="col-right"><#t>
<#if socialLinks??>
- <@ui.social links=socialLinks />
+ <@social links=socialLinks />
</#if>
<#if showXXELogo>
<a class="xxe" href="http://www.xmlmind.com/xmleditor/" rel="nofollow" title="Edited with XMLMind XML Editor"><#t>
@@ -66,15 +66,30 @@
</#macro>
-<#macro siteMap links>
- <#list links?keys as column>
+<#macro social links>
+ <ul class="social-icons"><#t>
+ <#list links?keys as linkTitle>
+ <#local link = links[linkTitle]>
+ <li><#t>
+ <a class="${link.class}" href="${link.href}">${linkTitle}</a><#t>
+ </li><#t>
+ </#list>
+ </ul><#t>
+</#macro>
+
+
+<#macro siteMap columns>
+ <#list columns?keys as columnTitle>
<div class="column"><#t>
- <h3 class="column-header">${column}</h3><#t>
+ <h3 class="column-header">${columnTitle}</h3><#t>
<ul><#t>
- <#list links[column] as link>
- <li><a href="${link.href}">${link.text}</a></li><#t>
+ <#local links = columns[columnTitle]>
+ <#list links?keys as linkTitle>
+ <li><a href="${links[linkTitle]}">${linkTitle}</a></li><#t>
</#list>
</ul><#t>
</div><#t>
</#list>
</#macro>
+
+</#escape>
\ No newline at end of file
diff --git a/src/main/org/freemarker/docgen/templates/header.ftl b/src/main/org/freemarker/docgen/templates/header.ftl
index 5e31e1e..315958c 100644
--- a/src/main/org/freemarker/docgen/templates/header.ftl
+++ b/src/main/org/freemarker/docgen/templates/header.ftl
@@ -1,4 +1,5 @@
<#ftl nsPrefixes={"D":"http://docbook.org/ns/docbook"} stripText = true>
+<#escape x as x?html>
<#import "navigation.ftl" as nav>
<#import "google.ftl" as google>
@@ -9,13 +10,13 @@
<div class="header-top-bg"><#t>
<div class="site-width header-top"><#t>
<#if logo??>
- <a class="logo" href="${logo.href?html}" role="banner"><#t>
- <img src="${logo.src?html}" alt="${logo.alt?html}">
+ <a class="logo" href="${logo.href}" role="banner"><#t>
+ <img src="${logo.src}" alt="${logo.alt}">
</a><#t>
</#if>
<@nav.tabs /><#t>
<#if secondaryTabs??>
- <@notices tabs=secondaryTabs /><#t>
+ <@secondaryTabs tabs=secondaryTabs /><#t>
</#if>
</div><#t>
</div><#t>
@@ -59,20 +60,24 @@
</#macro>
-<#macro notices tabs>
+<#macro secondaryTabs tabs>
+ <#local secondaryTabs = .dataModel.secondaryTabs>
<ul class="secondary-tabs"><#t>
- <#list tabs as tab>
+ <#list secondaryTabs?keys as tabTitle>
+ <#local tab = secondaryTabs[tabTitle]>
<li><#t>
- <#if (tab.href)?hasContent>
- <a class="tab<#if tab.class??> ${tab.class}</#if>" href="${tab.href}" title="${tab.text?html}"><#t>
- <span>${tab.text}</span><#t>
+ <#if tab.href??>
+ <a class="tab<#if tab.class??> ${tab.class}</#if>" href="${tab.href}" title="${tabTitle}"><#t>
+ <span>${tabTitle}</span><#t>
</a><#t>
<#else>
- <div class="tab<#if tab.class??> ${tab.class}</#if>" title="${tab.text?html}"><#t>
- <span>${tab.text}</span><#t>
+ <div class="tab<#if tab.class??> ${tab.class}</#if>" title="${tabTitle}"><#t>
+ <span>${tabTitle}</span><#t>
</div><#t>
</#if>
</li><#t>
</#list>
</ul><#t>
</#macro>
+
+</#escape>
\ No newline at end of file
diff --git a/src/main/org/freemarker/docgen/templates/page.ftl b/src/main/org/freemarker/docgen/templates/page.ftl
index b77f14a..1b7838c 100644
--- a/src/main/org/freemarker/docgen/templates/page.ftl
+++ b/src/main/org/freemarker/docgen/templates/page.ftl
@@ -142,10 +142,7 @@
<@toc att="docgen_page_toc_element" maxDepth=99 minLength=2 title="Page Contents" /><#t>
<#-- - Render the usual content, like <para>-s etc.: -->
<#list .node.* as child>
- <#if child.@docgen_file_element?size == 0
- && child?nodeName != "title"
- && child?nodeName != "subtitle"
- && child?nodeName != "info">
+ <#if child.@docgen_file_element?size == 0 && !["title", "subtitle", "info"]?seqContains(child?nodeName)>
<#visit child using nodeHandlers>
</#if>
</#list>
diff --git a/src/main/org/freemarker/docgen/templates/ui.ftl b/src/main/org/freemarker/docgen/templates/ui.ftl
deleted file mode 100644
index 9083b2b..0000000
--- a/src/main/org/freemarker/docgen/templates/ui.ftl
+++ /dev/null
@@ -1,11 +0,0 @@
-<#ftl stripText = true />
-
-<#macro social links>
- <ul class="social-icons"><#t>
- <#list links as link>
- <li><#t>
- <a class="${link.class}" href="${link.href}">${link.text}</a><#t>
- </li><#t>
- </#list>
- </ul><#t>
-</#macro>