From 1f06058af1e4c76a69276a6113eaf02f2bc4ab2f Mon Sep 17 00:00:00 2001 From: john gravois Date: Fri, 21 Sep 2018 11:39:56 -0700 Subject: [PATCH] docs(:book:): adapt built in acetate helper to fix sticky links ISSUES CLOSED: #284 --- docs/acetate.config.js | 109 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 2 deletions(-) diff --git a/docs/acetate.config.js b/docs/acetate.config.js index 4d4c7fcabc..3c9553e70a 100644 --- a/docs/acetate.config.js +++ b/docs/acetate.config.js @@ -2,10 +2,35 @@ const path = require("path"); const fs = require("fs"); const { inspect } = require("util"); const _ = require("lodash"); -const slug = require("slug"); const IS_DEV = process.env.ENV !== "prod"; -const BASE_URL = process.env.ENV === "prod" ? "/arcgis-rest-js" : ""; +const BASE_URL = IS_DEV ? "" : "/arcgis-rest-js"; + +const url = require("url"); +const PROTOCOL_REGEX = /^(.+:)?\/\//; +const HASH_REGEX = /^#/; + +function stripSlashes(string = "") { + var count = string.length - 1; + var index = 0; + + while (string.charCodeAt(index) === 47 && ++index); + while (string.charCodeAt(count) === 47 && --count); + + string = string.slice(index, count + 1); + + return string; +} + +function ensureTrailingSlash(baseUrl) { + let ext = path.extname(baseUrl); + + if (!ext && baseUrl[baseUrl.length - 1] !== "/") { + baseUrl = baseUrl + "/"; + } + + return baseUrl; +} module.exports = function(acetate) { /** @@ -211,4 +236,84 @@ module.exports = function(acetate) { : []; return `npm install ${package.name} ${peers.join(" ")}`; }); + + acetate.helper( + "link", + function(context, destinationUrl, text) { + const currentUrl = context.options.currentUrl || context.page.url; + const options = context.options; + let finalUrl; + let isActive = false; + + if ( + PROTOCOL_REGEX.test(destinationUrl) || + HASH_REGEX.test(destinationUrl) + ) { + finalUrl = destinationUrl; + } else { + finalUrl = url.resolve(currentUrl, destinationUrl); + + // strip all leading and trailing slashes + finalUrl = stripSlashes(finalUrl); + + // ensure we have leading slash unless this starts with a protocol + if (!PROTOCOL_REGEX.test(finalUrl) && finalUrl[0] !== "/") { + finalUrl = `/${finalUrl}`; + } + + // ensure there is a trailing slash unless there is a extension + // and remove index.html + let parsedUrl = url.parse(finalUrl); + parsedUrl.pathname = ensureTrailingSlash(parsedUrl.pathname).replace( + "index.html", + "" + ); + + finalUrl = url.format(parsedUrl); + } + + const hrefAttr = `href="${finalUrl}"`; + const idAttr = options.id ? `id="${options.id}"` : ""; + if (`${BASE_URL}${currentUrl}` === finalUrl) { + isActive = true; + } else if (PROTOCOL_REGEX.test(destinationUrl)) { + isActive = false; + } else if (HASH_REGEX.test(destinationUrl)) { + isActive = true; + } else if (options.requireExactMatch) { + isActive = `${BASE_URL}${currentUrl}` === finalUrl; + } else { + let parsedUrl = url.parse(finalUrl); + + isActive = `${BASE_URL}${currentUrl}`.match(parsedUrl.pathname) && finalUrl !== "/"; + } + + const classes = isActive + ? _([options.activeClass, options.class]) + .compact() + .join(" ") + : options.class; + const classAttr = classes && classes.length ? `class="${classes}"` : ""; + + delete options.id; + delete options.activeClass; + delete options.class; + delete options.requireExactMatch; + delete options.currentUrl; + + const attrs = _(options) + .map((value, key) => `${key}="${value}"`) + .reverse() + .concat([classAttr, idAttr, hrefAttr]) + .reverse() + .compact() + .join(" "); + + return `${text}`; + }, + { + activeClass: "is-active", + requireExactMatch: false + } + ); };