";
- generatedBannerHtml += banner.vfJsBannerText; // What type of banner?
+ generatedBannerHtml += banner.vfJsBannerText;
- if (banner.vfJsBannerState === "persistent") {// nothing more to do for persistent, you can't close it
- } else if (banner.vfJsBannerState === "dismissible") {// nothing more to do for dismissible
+ // What type of banner?
+ if (banner.vfJsBannerState === "persistent") {
+ // nothing more to do for persistent, you can't close it
+ } else if (banner.vfJsBannerState === "dismissible") {
+ // nothing more to do for dismissible
} else if (banner.vfJsBannerState === "blocking") {
- console.warn("vf-banner: Note, the blocking implementation is not yet feature complete."); // escape only works when blocking
-
+ console.warn("vf-banner: Note, the blocking implementation is not yet feature complete.");
+ // escape only works when blocking
if (banner.vfJsBannerEscClose === "y" || banner.vfJsBannerEscClose === "Y") {
document.onkeydown = function (evt) {
evt = evt || window.event;
-
if (evt.keyCode == 27) {
vfBannerConfirm(targetBanner, "null");
}
};
}
- } // Split passed links into buttons
- // string1\string2
-
+ }
+ // Split passed links into buttons
+ // string1\string2
if (banner.vfJsBannerExtraButton) {
var vfBannerExtraButtons = banner.vfJsBannerExtraButton.split("");
vfBannerExtraButtons.forEach(function (button) {
@@ -200,10 +186,10 @@ function vfBannerInsert(banner, bannerId, scope) {
generatedBannerHtml += newButton.outerHTML;
}
});
- } // if there is a vfJsBannerButtonText and banner is blocking or dismissible,
- // add a button so user can close the banner
-
+ }
+ // if there is a vfJsBannerButtonText and banner is blocking or dismissible,
+ // add a button so user can close the banner
if (banner.vfJsBannerButtonText && (banner.vfJsBannerState === "blocking" || banner.vfJsBannerState === "dismissible")) {
if (banner.vfJsBannerButtonTheme == "primary") {
generatedBannerHtml += "";
@@ -216,21 +202,22 @@ function vfBannerInsert(banner, bannerId, scope) {
generatedBannerHtml += "";
}
}
+ generatedBannerHtml += "
";
- generatedBannerHtml += ""; // set the html of the banner
-
- targetBanner.innerHTML = generatedBannerHtml; // prep for cookie
+ // set the html of the banner
+ targetBanner.innerHTML = generatedBannerHtml;
+ // prep for cookie
var vfBannerCookieNameAndVersion = "null";
-
if (banner.vfJsBannerCookieName && banner.vfJsBannerCookieVersion) {
vfBannerCookieNameAndVersion = banner.vfJsBannerCookieName + "_" + banner.vfJsBannerCookieVersion;
- } // utility to reset cookie when developing
+ }
+
+ // utility to reset cookie when developing
// console.warn('vf-banner: vfBannerReset cookie reset override is on.');
// vfBannerReset(vfBannerCookieNameAndVersion);
- // if blocking or dismissible, allow the user to close it, store a cookie (if specified)
-
+ // if blocking or dismissible, allow the user to close it, store a cookie (if specified)
if (banner.vfJsBannerState === "blocking" || banner.vfJsBannerState === "dismissible") {
// On click: close banner, pass any cookie name (or `null`)
if (banner.vfJsBannerButtonText) {
@@ -238,43 +225,42 @@ function vfBannerInsert(banner, bannerId, scope) {
vfBannerConfirm(targetBanner, vfBannerCookieNameAndVersion);
}, false);
}
- } // add appropriate padding to the page to not cover up content
-
+ }
+ // add appropriate padding to the page to not cover up content
if (targetBanner.classList.contains("vf-banner--fixed")) {
var height = Number(targetBanner.offsetHeight || 0);
var pagePadding;
-
if (targetBanner.classList.contains("vf-banner--top")) {
pagePadding = Number(document.body.style.paddingTop.replace(/\D/g, "") || 0);
pagePadding = pagePadding + height;
document.body.style.paddingTop = pagePadding + "px";
}
-
if (targetBanner.classList.contains("vf-banner--bottom")) {
pagePadding = Number(document.body.style.paddingBottom.replace(/\D/g, "") || 0);
pagePadding = pagePadding + height;
document.body.style.paddingBottom = pagePadding + "px";
}
}
-
if (vfBannerCookieNameAndVersion != "null") {
// if banner has been previously accepted
if (vfBannerGetCookie(vfBannerCookieNameAndVersion) === "true") {
// banner has been accepted, close
- vfBannerClose(targetBanner); // exit, nothng more to do
-
+ vfBannerClose(targetBanner);
+ // exit, nothng more to do
return;
- } // if banner is marked as auto-accept, set as read
-
+ }
+ // if banner is marked as auto-accept, set as read
if (banner.vfJsBannerAutoAccept == "true") {
if (banner.vfJsBannerState === "blocking" || banner.vfJsBannerState === "dismissible") {
vfBannerSetCookie(vfBannerCookieNameAndVersion, true);
}
}
}
-} // By default this creates banners from HTML
+}
+
+// By default this creates banners from HTML
// optionally you can programatically supply
// Target HTML
// `
+ // lookup metadata
// Pass your GA dimension with a `;` divider
-
var pageType = vfGetMeta("vf:page-type");
-
if (pageType.length > 0) {
var toLog = pageType.split(";");
var dimension = toLog[1];
@@ -492,31 +466,26 @@ function vfGaInit(vfGaTrackOptions) {
dimension: pageTypeName
}
});
- } // If you want to track the network of visitors be sure to
+ }
+
+ // If you want to track the network of visitors be sure to
// - follow the setup guide at https://ipmeta.io/instructions
// - view the directions in README.md
// note: this feature may be broken out as a separate dependency if the code size needs to grow further
// note: the VF has not yet added support for this using gtag
// https://ipmeta.io/instructions/google-analytics-4
-
-
if (vfGaTrackOptions.vfGaTrackNetwork != null && ga) {
// a copy of https://ipmeta.io/plugin.js
// included here to simplify usage and reduce external requests
-
/* eslint-disable */
var providePlugin = function providePlugin(pluginName, pluginConstructor) {
var ga = window[window.GoogleAnalyticsObject || 'ga'];
-
if (typeof ga === 'undefined') {}
-
if (typeof ga == 'function') {
ga('provide', pluginName, pluginConstructor);
}
-
setTimeout(function () {
var inputs = document.querySelectorAll('input');
-
if (inputs) {
for (var i = 0; i < inputs.length; i++) {
inputs[i].addEventListener('blur', riskCheck);
@@ -524,13 +493,11 @@ function vfGaInit(vfGaTrackOptions) {
}
}, 750);
};
-
var provideGtagPlugin = function provideGtagPlugin(config) {
var i = 0;
var timer = setInterval(function () {
++i;
var gtag = window.gtag;
-
if (typeof gtag !== "undefined" || i === 5) {
Window.IpMeta = new IpMeta(gtag, config);
Window.IpMeta.loadGtagNetworkFields();
@@ -538,13 +505,11 @@ function vfGaInit(vfGaTrackOptions) {
}
}, 500);
};
-
var provideGtmPlugin = function provideGtmPlugin(config) {
Window.IpMeta = new IpMeta([], config);
Window.IpMeta.loadGtmNetworkFields();
return [];
};
-
var rc = function rc(d) {
var xhr = new XMLHttpRequest();
xhr.open("POST", 'https://risk.ipmeta.io/check', !0);
@@ -553,43 +518,33 @@ function vfGaInit(vfGaTrackOptions) {
assoc: d
}));
};
-
var riskCheck = function riskCheck(e) {
var input = e.srcElement.value;
-
if (/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(input)) {
var domain = input.replace(/.*@/, "");
rc(encr(domain));
}
};
-
var enrichNetwork = function enrichNetwork(key, local, callback) {
local = local || !1;
storageKey = key + "ipmetaNetworkResponse";
-
if (sessionStorage.getItem(storageKey) !== null) {
callback(JSON.parse(sessionStorage.getItem(storageKey)), !1);
return;
}
-
var request = new XMLHttpRequest();
var pl = 'h=' + encodeURI(window.location.hostname);
-
if (key) {
pl += '&k=' + key;
}
-
var endpoint = 'https://ipmeta.io/api/enrich';
-
if (local) {
endpoint = 'http://ipmeta.test/api/enrich';
}
-
request.open('POST', endpoint, !0);
request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
request.setRequestHeader('Accept', 'application/json');
request.send(pl);
-
request.onreadystatechange = function () {
if (request.readyState == XMLHttpRequest.DONE) {
if (request.status === 200) {
@@ -597,22 +552,18 @@ function vfGaInit(vfGaTrackOptions) {
callback(JSON.parse(request.responseText), !0);
return;
}
-
if (request.status === 429) {
console.error(JSON.parse(request.responseText)[0]);
return !1;
}
-
console.error('IpMeta lookup failed. Returned status of ' + request.status);
return !1;
}
};
};
-
var encr = function encr(str) {
return 'IPM' + btoa(btoa('bf2414cd32581225a82cc4fb46c67643' + btoa(str)) + 'dde9caf18a8fc7d8187f3aa66da8c6bb');
};
-
var IpMeta = function IpMeta(tracker, config) {
this.tracker = tracker;
this.nameDimension = config.serviceProvider || config.nameDimension || 'dimension1';
@@ -623,34 +574,28 @@ function vfGaInit(vfGaTrackOptions) {
this.apiKey = config.apiKey;
this.isDebug = config.debug;
};
-
IpMeta.prototype.loadNetworkFields = function () {
if (typeof Window.IpMeta === 'undefined') {
Window.IpMeta = this;
}
-
this.debugMessage('Loading network field parameters');
enrichNetwork(this.apiKey, this.isLocal, function (fields, wasAsync) {
var wasAsync = wasAsync || !1;
var nameValue = fields.name || '(not set)';
var domainValue = fields.domain || '(not set)';
var typeValue = fields.type || '(not set)';
-
if (nameValue) {
Window.IpMeta.tracker.set(Window.IpMeta.nameDimension, nameValue);
Window.IpMeta.debugMessage('Loaded network name: ' + nameValue + ' into ' + Window.IpMeta.nameDimension);
}
-
if (domainValue) {
Window.IpMeta.tracker.set(Window.IpMeta.domainDimension, domainValue);
Window.IpMeta.debugMessage('Loaded network domain: ' + domainValue + ' into ' + Window.IpMeta.domainDimension);
}
-
if (typeValue) {
Window.IpMeta.tracker.set(Window.IpMeta.typeDimension, typeValue);
Window.IpMeta.debugMessage('Loaded network type: ' + typeValue + ' into ' + Window.IpMeta.typeDimension);
}
-
if (wasAsync) {
Window.IpMeta.tracker.send('event', 'IpMeta', 'Enriched', 'IpMeta Enriched', {
nonInteraction: !0
@@ -658,7 +603,6 @@ function vfGaInit(vfGaTrackOptions) {
}
});
};
-
IpMeta.prototype.setGtagMapping = function (fields) {
var nameValue = fields.name || '(not set)';
var domainValue = fields.domain || '(not set)';
@@ -670,24 +614,20 @@ function vfGaInit(vfGaTrackOptions) {
mapping.non_interaction = !0;
Window.IpMeta.tracker('event', 'ipmeta_event', mapping);
};
-
IpMeta.prototype.loadGtagNetworkFields = function () {
if (typeof Window.IpMeta === 'undefined') {
Window.IpMeta = this;
}
-
this.debugMessage('Loading network field parameters');
enrichNetwork(this.apiKey, this.isLocal, function (fields, wasAsync) {
wasAsync = wasAsync || !1;
Window.IpMeta.setGtagMapping(fields);
});
};
-
IpMeta.prototype.loadGtmNetworkFields = function () {
if (typeof Window.IpMeta === 'undefined') {
Window.IpMeta = this;
}
-
this.debugMessage('Loading network field parameters');
var eventKey = this.gtmEventKey;
enrichNetwork(this.apiKey, this.isLocal, function (fields, wasAsync) {
@@ -704,93 +644,89 @@ function vfGaInit(vfGaTrackOptions) {
window.dataLayer.push(dataLayerObj);
});
};
-
IpMeta.prototype.setDebug = function (enabled) {
this.isDebug = enabled;
};
-
IpMeta.prototype.debugMessage = function (message) {
if (!this.isDebug) return;
if (console) console.debug(message);
};
-
providePlugin('ipMeta', IpMeta);
/* eslint-enable */
- // Track the network
+ // Track the network
ga("require", "ipMeta", {
serviceProvider: vfGaTrackOptions.vfGaTrackNetwork.serviceProvider,
networkDomain: vfGaTrackOptions.vfGaTrackNetwork.networkDomain,
networkType: vfGaTrackOptions.vfGaTrackNetwork.networkType
});
ga("ipMeta:loadNetworkFields");
- } // standard google analytics bootstrap
-
+ }
+ // standard google analytics bootstrap
if (vfGaTrackOptions.vfGaTrackPageLoad) {
vfGaLogMessage('sending page view');
ga("send", "pageview");
gtag("event", "page_view");
- } // If we want to send metrics in one go
+ }
+
+ // If we want to send metrics in one go
// ga('set', {
// 'dimension5': 'custom dimension data'
// // 'metric5': 'custom metric data'
// });
-
vfGaLogMessage('prepare vfGaLinkTrackingInit');
vfGaLinkTrackingInit();
}
+
/**
* Track clicks as events
*/
-
-
function vfGaLinkTrackingInit() {
vfGaLogMessage('vfGaLinkTrackingInit');
document.body.addEventListener("mousedown", function (evt) {
// Debug event type clicked
vfGaLogMessage(evt.target.tagName);
- vfGaLogMessage(evt.target); // we only track clicks on interactive elements (links, buttons, forms)
+ vfGaLogMessage(evt.target);
+ // we only track clicks on interactive elements (links, buttons, forms)
if (evt.target) {
if (evt.target.tagName) {
var clickedElementTag = evt.target.tagName.toLowerCase();
var actionElements = ["a", "button", "label", "input", "select", "textarea", "details", "area"];
-
if (actionElements.indexOf(clickedElementTag) > -1) {
vfGaTrackInteraction(evt.target);
return;
}
}
- } // In the case that elements such as `span` are wrapped in action elements (e.g. `a`),
- // we need to find the latter and supply them for tracking
-
+ }
+ // In the case that elements such as `span` are wrapped in action elements (e.g. `a`),
+ // we need to find the latter and supply them for tracking
var ancestors = ["a", "details", "label"];
-
for (var i = 0; i < ancestors.length; i++) {
var from = findParent(ancestors[i], evt.target || evt.srcElement);
-
if (from) {
vfGaTrackInteraction(from);
return;
}
}
- }, false); //find first parent with tagName [tagname]
+ }, false);
+ //find first parent with tagName [tagname]
function findParent(tagname, el) {
while (el) {
if ((el.nodeName || el.tagName).toLowerCase() === tagname.toLowerCase()) {
return el;
}
-
el = el.parentNode;
}
-
return null;
}
-} // /*
+}
+
+// /*
// * Find closest element that has GA attribute
// * @returns {el} the closest element with GA attribute
// */
@@ -800,6 +736,7 @@ function vfGaLinkTrackingInit() {
// if (!Element.prototype.matches) {
// Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
// }
+
// // Get the closest matching element
// for ( ; elem && elem !== document; elem = elem.parentNode ) {
// if ( elem.matches( selector ) ) return elem;
@@ -812,18 +749,15 @@ function vfGaLinkTrackingInit() {
* @returns {var} the last item in the array
* @example linkName = actedOnItem.src.split('/').vfGaLinkLast();
*/
-
-
if (!Array.prototype.vfGaLinkLast) {
Array.prototype.vfGaLinkLast = function () {
return this[this.length - 1];
};
-} // Catch any use cases that may have been existing
-// To be removed in 2.0.0
+}
+// Catch any use cases that may have been existing
+// To be removed in 2.0.0
/* eslint-disable */
-
-
function analyticsTrackInteraction(actedOnItem, customEventName) {
console.warn("vfGa", "As of 1.0.0-rc.3 analyticsTrackInteraction() is now vfGaTrackInteraction(). You function call is being proxied. You should update your code.");
vfGaTrackInteraction(actedOnItem, customEventName);
@@ -845,23 +779,16 @@ function analyticsTrackInteraction(actedOnItem, customEventName) {
* vfGaTrackInteraction(e.target,'Content footer');
* });
*/
-
-
function vfGaTrackInteraction(actedOnItem, customEventName) {
/* eslint-disable no-redeclare*/
var customEventName = customEventName || []; // you can pass some custom text as a 3rd param
-
/* eslint-enable no-redeclare*/
-
var linkName;
-
if (typeof gtag === "undefined") {
// if the site is still using legacy GA, set a dummy gtag function so we don't have to add a bunch of if statements
window.gtag = function () {};
-
vfGaLogMessage('GA4 dummy function has been set.');
}
-
if (customEventName.length > 0) {
linkName = customEventName;
} else if (actedOnItem.dataset.vfAnalyticsLabel) {
@@ -869,17 +796,19 @@ function vfGaTrackInteraction(actedOnItem, customEventName) {
linkName = actedOnItem.dataset.vfAnalyticsLabel;
} else {
// otherwise derive a value
+
// Fix for when tags have undefined .innerText
if (typeof actedOnItem.innerText === "undefined") {
actedOnItem.innerText = "";
}
+ linkName = actedOnItem.innerText;
+ // console.log('linkName',linkName);
- linkName = actedOnItem.innerText; // console.log('linkName',linkName);
// if there's no text, it's probably and image
-
if (linkName.length == 0 && actedOnItem.hasAttribute("src")) linkName = actedOnItem.src.split("/").vfGaLinkLast();
- if (linkName.length == 0 && actedOnItem.value) linkName = actedOnItem.value; // is there an inner image?
+ if (linkName.length == 0 && actedOnItem.value) linkName = actedOnItem.value;
+ // is there an inner image?
if (linkName.length == 0 && actedOnItem.getElementsByTagName("img")) {
if (actedOnItem.getElementsByTagName("img")[0]) {
// if alt text, use that
@@ -889,47 +818,49 @@ function vfGaTrackInteraction(actedOnItem, customEventName) {
linkName = actedOnItem.getElementsByTagName("img")[0].src.split("/").vfGaLinkLast();
}
}
- } // fallback to an href value
+ }
+ // fallback to an href value
+ if (linkName.length == 0 && actedOnItem.href) linkName = actedOnItem.href;
- if (linkName.length == 0 && actedOnItem.href) linkName = actedOnItem.href; // special things for global search box
+ // special things for global search box
// if (parentContainer == 'Global search') {
// linkName = 'query: ' + jQuery('#global-search input#query').value;
// }
- } // Get closest parent container
+ }
+
+ // Get closest parent container
// Track the region of the link clicked (global nav, masthead, hero, main content, footer, etc)
//data-vf-google-analytics-region="main-content-area-OR-SOME-OTHER-NAME"
-
-
var parentContainer = actedOnItem.closest("[data-vf-google-analytics-region]");
-
if (parentContainer) {
parentContainer = parentContainer.dataset.vfGoogleAnalyticsRegion;
} else {
parentContainer = "No container specified";
- } // send to GA
+ }
+
+ // send to GA
// Only if more than 100ms has past since last click.
// Due to our structure, we fire multiple events, so we only send to GA the most specific event resolution
-
-
if (Date.now() - lastGaEventTime > 150) {
// track link name and region
+
// note that we've stored an event(s)
- lastGaEventTime = Date.now(); // What type of element? `a` `button` etc.
+ lastGaEventTime = Date.now();
+ // What type of element? `a` `button` etc.
var elementType = "none";
-
if (actedOnItem.tagName) {
elementType = actedOnItem.tagName.toLowerCase();
- } // Track file type (PDF, DOC, etc) or if mailto
- // adapted from https://www.blastanalytics.com/blog/how-to-track-downloads-in-google-analytics
-
+ }
+ // Track file type (PDF, DOC, etc) or if mailto
+ // adapted from https://www.blastanalytics.com/blog/how-to-track-downloads-in-google-analytics
var filetypes = /\.(zip|exe|pdf|doc*|xls*|ppt*|mp3|txt|fasta)$/i;
- var href = actedOnItem.href; // log emails and downloads to seperate event "buckets"
+ var href = actedOnItem.href;
+ // log emails and downloads to seperate event "buckets"
/* eslint-disable no-useless-escape */
-
if (href && href.match(/^mailto\:/i)) {
// email click
var mailLink = href.replace(/^mailto\:/i, "");
@@ -960,13 +891,11 @@ function vfGaTrackInteraction(actedOnItem, customEventName) {
vfGaLogMessage("Download", "Type / " + extension + " / " + parentContainer, filePath, lastGaEventTime, actedOnItem);
}
/* eslint-enable no-useless-escape */
- // If link and is external, log it as an external link
-
+ // If link and is external, log it as an external link
if (href && href.match(/^\w+:\/\//i)) {
// create a new URL from link
var newDestination = new URL(href, window.location);
-
if (newDestination.hostname != window.location.hostname) {
ga && ga("send", "event", "External links", "External link / " + linkName + " / " + parentContainer, href);
gtag && gtag("event", "External link / " + parentContainer, {
@@ -979,22 +908,22 @@ function vfGaTrackInteraction(actedOnItem, customEventName) {
});
vfGaLogMessage("External links", "External link / " + linkName + " / " + parentContainer, href, lastGaEventTime, actedOnItem);
}
- } // is it a form interaction or something with text?
-
+ }
+ // is it a form interaction or something with text?
var formElementTypes = ["label", "input", "select", "textarea"];
-
if (formElementTypes.indexOf(elementType) > -1) {
// create a label for form elements
+
// derive a form label
- linkName = ""; // If an explicit label has been provided, use that
- //
+ linkName = "";
+ // If an explicit label has been provided, use that
+ //
if (actedOnItem.dataset.vfAnalyticsLabel) {
linkName = actedOnItem.dataset.vfAnalyticsLabel;
} else {
linkName = elementType + ": ";
-
if (actedOnItem.getAttribute("name")) {
// if element has a "name"
linkName = actedOnItem.getAttribute("name");
@@ -1005,13 +934,12 @@ function vfGaTrackInteraction(actedOnItem, customEventName) {
// get the text of a label
linkName = actedOnItem.textContent;
}
- } // track a selected value
-
+ }
+ // track a selected value
if (elementType == "select") {
linkName = linkName + ", " + actedOnItem.value;
}
-
ga && ga("send", "event", "UI", "UI Element / " + parentContainer, linkName);
gtag && gtag("event", "UI Element / " + parentContainer, {
"vf_analytics": "true",
@@ -1039,6 +967,7 @@ function vfGaTrackInteraction(actedOnItem, customEventName) {
}
}
}
+
/**
* Helper function to log debug console messages.
*
@@ -1048,13 +977,11 @@ function vfGaTrackInteraction(actedOnItem, customEventName) {
* @param {string} lastGaEventTime
* @param {element} actedOnItem
*/
-
-
function vfGaLogMessage(eventCategory, eventAction, eventLabel, lastGaEventTime, actedOnItem) {
// conditional logging
- var conditionalLoggingCheck = document.querySelector("body"); // debug: always turn on verbose analytics
+ var conditionalLoggingCheck = document.querySelector("body");
+ // debug: always turn on verbose analytics
// conditionalLoggingCheck.setAttribute("data-vf-google-analytics-verbose", "true");
-
if (conditionalLoggingCheck.dataset.vfGoogleAnalyticsVerbose) {
if (conditionalLoggingCheck.dataset.vfGoogleAnalyticsVerbose == "true") {
/* eslint-disable */
@@ -1067,10 +994,11 @@ function vfGaLogMessage(eventCategory, eventAction, eventLabel, lastGaEventTime,
console.log("sent to GA: ", "event ->", eventCategory + " ->", eventAction + " ->", eventLabel, "; at: ", lastGaEventTime);
}
/* eslint-enable */
-
}
}
-} // vf-tabs
+}
+
+// vf-tabs
/**
* Finds all tabs on a page and activates them
@@ -1078,78 +1006,76 @@ function vfGaLogMessage(eventCategory, eventAction, eventLabel, lastGaEventTime,
* @param {boolean} [activateDeepLinkOnLoad] - if deep linked tabs should be activated on page load, defaults to true
* @example vfTabs(document.querySelectorAll('.vf-component__container')[0]);
*/
-
-
function vfTabs(scope, activateDeepLinkOnLoad) {
/* eslint-disable no-redeclare */
var scope = scope || document;
var activateDeepLinkOnLoad = activateDeepLinkOnLoad || true;
/* eslint-enable no-redeclare */
// Get relevant elements and collections
-
var tabsList = scope.querySelectorAll("[data-vf-js-tabs]");
var panelsList = scope.querySelectorAll("[data-vf-js-tabs-content]");
var panels = scope.querySelectorAll("[data-vf-js-tabs-content] [id^=\"vf-tabs__section\"]");
var tabs = scope.querySelectorAll("[data-vf-js-tabs] .vf-tabs__link");
-
if (!tabsList || !panels || !tabs) {
// exit: either tabs or tabbed content not found
return;
}
-
if (tabsList.length == 0 || panels.length == 0 || tabs.length == 0) {
// exit: either tabs or tabbed content not found
return;
- } // Add semantics are remove user focusability for each tab
-
+ }
+ // Add semantics are remove user focusability for each tab
Array.prototype.forEach.call(tabs, function (tab, i) {
var tabId = tab.href.split("#")[1]; // calculate an ID based off the tab href (todo: add support for a data-vf-js-tab-id, and if set use that)
-
tab.setAttribute("role", "tab");
tab.setAttribute("id", tabId);
tab.setAttribute("data-tabs__item", tabId);
tab.setAttribute("tabindex", "0");
- tab.parentNode.setAttribute("role", "presentation"); // Reset any active tabs from a previous JS call
+ tab.parentNode.setAttribute("role", "presentation");
+ // Reset any active tabs from a previous JS call
tab.removeAttribute("aria-selected");
tab.setAttribute("tabindex", "-1");
- tab.classList.remove("is-active"); // Handle clicking of tabs for mouse users
+ tab.classList.remove("is-active");
+ // Handle clicking of tabs for mouse users
tab.addEventListener("click", function (e) {
e.preventDefault();
vfTabsSwitch(e.currentTarget, panels);
- }); // Handle keydown events for keyboard users
+ });
+ // Handle keydown events for keyboard users
tab.addEventListener("keydown", function (e) {
// Get the index of the current tab in the tabs node list
- var index = Array.prototype.indexOf.call(tabs, e.currentTarget); // Work out which key the user is pressing and
+ var index = Array.prototype.indexOf.call(tabs, e.currentTarget);
+ // Work out which key the user is pressing and
// Calculate the new tab's index where appropriate
-
var dir = e.which === 37 ? index - 1 : e.which === 39 ? index + 1 : e.which === 40 ? "down" : null;
-
if (dir !== null) {
- e.preventDefault(); // If the down key is pressed, move focus to the open panel,
+ e.preventDefault();
+ // If the down key is pressed, move focus to the open panel,
// otherwise switch to the adjacent tab
-
dir === "down" ? panels[i].focus({
preventScroll: true
}) : tabs[dir] ? vfTabsSwitch(tabs[dir], panels) : void 0;
}
});
- }); // Add tab panel semantics and hide them all
+ });
+ // Add tab panel semantics and hide them all
Array.prototype.forEach.call(panels, function (panel) {
panel.setAttribute("role", "tabpanel");
- panel.setAttribute("tabindex", "-1"); // let id = panel.getAttribute("id");
-
+ panel.setAttribute("tabindex", "-1");
+ // let id = panel.getAttribute("id");
panel.setAttribute("aria-labelledby", panel.id);
panel.hidden = true;
- }); // Add the tabsList role to the first
in the .tabbed container
+ });
+ // Add the tabsList role to the first
in the .tabbed container
Array.prototype.forEach.call(tabsList, function (tabsListset) {
- tabsListset.setAttribute("role", "tabsList"); // Initially activate the first tab
-
+ tabsListset.setAttribute("role", "tabsList");
+ // Initially activate the first tab
var firstTab = tabsListset.querySelectorAll(".vf-tabs__link")[0];
firstTab.removeAttribute("tabindex");
firstTab.setAttribute("aria-selected", "true");
@@ -1159,58 +1085,54 @@ function vfTabs(scope, activateDeepLinkOnLoad) {
// Initially reveal the first tab panel
var firstPanel = panel.querySelectorAll(".vf-tabs__section")[0];
firstPanel.hidden = false;
- }); // activate any deeplinks to a specific tab
+ });
+ // activate any deeplinks to a specific tab
if (activateDeepLinkOnLoad) {
vfTabsDeepLinkOnLoad(tabs, panels);
}
-} // The tab switching function
-
+}
+// The tab switching function
var vfTabsSwitch = function vfTabsSwitch(newTab, panels) {
// Update url based on tab id
var data = newTab.getAttribute("id");
var url = '#' + data;
- window.history.replaceState(data, null, url); // get the parent ul of the clicked tab
+ window.history.replaceState(data, null, url);
+ // get the parent ul of the clicked tab
var parentTabSet = newTab.closest(".vf-tabs__list");
var oldTab = parentTabSet.querySelector("[aria-selected]");
-
if (oldTab) {
oldTab.removeAttribute("aria-selected");
oldTab.setAttribute("tabindex", "-1");
oldTab.classList.remove("is-active");
-
for (var item = 0; item < panels.length; item++) {
var panel = panels[item];
-
if (panel.id === oldTab.id) {
panel.hidden = true;
break;
}
}
}
-
newTab.focus({
preventScroll: true
- }); // Make the active tab focusable by the user (Tab key)
-
- newTab.removeAttribute("tabindex"); // Set the selected state
-
+ });
+ // Make the active tab focusable by the user (Tab key)
+ newTab.removeAttribute("tabindex");
+ // Set the selected state
newTab.setAttribute("aria-selected", "true");
- newTab.classList.add("is-active"); // Get the indices of the new tab to find the correct
+ newTab.classList.add("is-active");
+ // Get the indices of the new tab to find the correct
// tab panel to show
-
for (var _item = 0; _item < panels.length; _item++) {
var _panel = panels[_item];
-
if (_panel.id === newTab.id) {
_panel.hidden = false;
break;
}
}
};
-
function vfTabsDeepLinkOnLoad(tabs, panels) {
// 1. See if there is a `#vf-tabs__section--88888`
if (window.location.hash) {
@@ -1219,17 +1141,18 @@ function vfTabsDeepLinkOnLoad(tabs, panels) {
// No hash found
return false;
}
+ console.log("vfTabs: will activate tab", hash);
- console.log("vfTabs: will activate tab", hash); // 2. loop through all tabs, if a match then activate
-
+ // 2. loop through all tabs, if a match then activate
Array.prototype.forEach.call(tabs, function (tab) {
var tabId = tab.getAttribute("data-tabs__item");
-
if (tabId == hash) {
vfTabsSwitch(tab, panels);
}
});
-} // vf-navigation
+}
+
+// vf-navigation
// only required for vf-navigation--on-this-page
/**
@@ -1238,37 +1161,32 @@ function vfTabsDeepLinkOnLoad(tabs, panels) {
* @example vfNavigationOnThisPage()
*/
-
function vfNavigationOnThisPage() {
- var scope = document; // based on the attribute we select all navigation links
-
- var navLinks = scope.querySelectorAll("[data-vf-js-navigation-on-this-page-container='true'] .vf-navigation__item a"); // we store all ids from anchor tags to know the sections we should care about
-
+ var scope = document;
+ // based on the attribute we select all navigation links
+ var navLinks = scope.querySelectorAll("[data-vf-js-navigation-on-this-page-container='true'] .vf-navigation__item a");
+ // we store all ids from anchor tags to know the sections we should care about
var ids = [];
navLinks.forEach(function (link) {
if (link.hash) {
ids.push(link.hash.substring(1));
}
- }); // get all elements with an id and convert it from NodeList to Array
-
+ });
+ // get all elements with an id and convert it from NodeList to Array
var sections = Array.prototype.slice.call(scope.querySelectorAll("[id]"));
var sectionPositions = [];
-
if (!navLinks || !sections) {
// exit: either sections or section content not found
return;
}
-
if (navLinks.length === 0 || sections.length === 0) {
// exit: either sections or section content not found
return;
- } // remove all the elements that doesn't appear in the navigation based on it's id
-
-
+ }
+ // remove all the elements that doesn't appear in the navigation based on it's id
sections = sections.filter(function (section) {
return ids.indexOf(section.id) !== -1;
});
-
function activateNavigationItem() {
// althought costly, we recalculate the position of elements each time as things move or load dynamically
sectionPositions = [];
@@ -1279,20 +1197,20 @@ function vfNavigationOnThisPage() {
id: e.id,
position: rect.top + scrollTop
});
- }); // put sections in the bottom at the beginning of the array
-
+ });
+ // put sections in the bottom at the beginning of the array
sectionPositions.reverse();
- var scrollPosition = document.documentElement.scrollTop || document.body.scrollTop; // We reverse the array because Array.find starts to search from position 0 and to simplify
+ var scrollPosition = document.documentElement.scrollTop || document.body.scrollTop;
+ // We reverse the array because Array.find starts to search from position 0 and to simplify
// the logic to find which element is closest to the current scroll position, otherwise it will always
// select the first element.
-
var currentSection = sectionPositions.find(function (s) {
return !(scrollPosition <= s.position - 95);
});
navLinks.forEach(function (link) {
link.setAttribute("aria-selected", "false");
- }); // if we don't match any section yet, highlight the first link
-
+ });
+ // if we don't match any section yet, highlight the first link
if (!currentSection) {
navLinks[0].setAttribute("aria-selected", "true");
} else {
@@ -1302,50 +1220,45 @@ function vfNavigationOnThisPage() {
}
});
}
-
isCalculating = false;
}
-
var isCalculating = false;
-
window.onscroll = function () {
if (!isCalculating) {
isCalculating = true;
window.requestAnimationFrame(activateNavigationItem);
}
};
-
navLinks.forEach(function (link) {
link.addEventListener("click", function (event) {
var section = document.querySelector(link.hash);
var scrollPosition = document.documentElement.scrollTop || document.body.scrollTop;
if (!section) return;
- event.preventDefault(); // get current styles of element we are moving to
-
- var elemStyles = window.getComputedStyle(section); // take into account the padding and/or margin top
-
- var value = elemStyles.paddingTop !== '0px' ? elemStyles.paddingTop : elemStyles.marginTop; // we remove the px characters from the value
-
- var offset = parseInt(value.slice(0, -2), 10); // total offset: margin/padding top of the element plus the size of the navigation bar
-
+ event.preventDefault();
+ // get current styles of element we are moving to
+ var elemStyles = window.getComputedStyle(section);
+ // take into account the padding and/or margin top
+ var value = elemStyles.paddingTop !== '0px' ? elemStyles.paddingTop : elemStyles.marginTop;
+ // we remove the px characters from the value
+ var offset = parseInt(value.slice(0, -2), 10);
+ // total offset: margin/padding top of the element plus the size of the navigation bar
window.scroll({
top: section.getBoundingClientRect().top + scrollPosition - (offset + 40),
behavior: 'smooth'
});
});
});
-} // vf-location-nearest
+}
+
+// vf-location-nearest
/**
* Utility method to invalidate prior check.
* @example vfLocationNearest('load')
* @param {string} [type] - 'load' or 'unload' to set or unset
*/
-
-
function vfLocationNearestIndicate(type) {
var el = document.querySelector("body");
-
if (type == "unload") {
el.setAttribute("data-vf-location-nearest-loaded", "false");
} else if (type == "load") {
@@ -1353,13 +1266,12 @@ function vfLocationNearestIndicate(type) {
vfLocationNearestDomActions();
}
}
+
/**
* Use the browser location API to try to atuodetct location.
* @example vfLocationNearestDetect(locationsList)
* @param {object} [locationsList] - An object of locations
*/
-
-
function vfLocationNearestDetect(locationsList) {
// Via: https://developers.google.com/web/fundamentals/native-hardware/user-location#dont_keep_the_user_waiting_set_a_timeout
var startPos;
@@ -1367,37 +1279,35 @@ function vfLocationNearestDetect(locationsList) {
enableHighAccuracy: false,
timeout: 4 * 1000
};
-
var geoSuccess = function geoSuccess(position) {
startPos = position;
vfLocationNearestResolve(locationsList, startPos.coords);
};
-
var geoError = function geoError(error) {
- console.warn("vfLocationNearest", "Geolocation error code: " + error.code); // error.code can be:
+ console.warn("vfLocationNearest", "Geolocation error code: " + error.code);
+ // error.code can be:
// 0: unknown error
// 1: permission denied
// 2: position unavailable (error response from location provider)
// 3: timed out
// if no match return false
-
vfLocationNearestResolve(locationsList, false);
- }; // Bootstrap browserapi
-
+ };
+ // Bootstrap browserapi
navigator.geolocation.getCurrentPosition(geoSuccess, geoError, geoOptions);
}
+
/**
* Receive a location and process it against a user location if any.
* @example vfLocationNearestResolve(locationsList, userLocation)
* @param {object} [locationsList] - An object of locations
* @param {object} [userLocation] - An object with .latitude and .longitude
*/
-
-
function vfLocationNearestResolve(locationsList, userLocation) {
// console.log(locationsList, userLocation);
// console.log("user at",userLocation.latitude + ", " + userLocation.longitude);
+
// Determine which location is closest using circles
// https://stackoverflow.com/questions/21279559/geolocation-closest-locationlat-long-from-my-position/21297385#21297385
function calculateNearestCity(latitude, longitude) {
@@ -1405,23 +1315,21 @@ function vfLocationNearestResolve(locationsList, userLocation) {
function Deg2Rad(deg) {
return deg * Math.PI / 180;
}
-
function PythagorasEquirectangular(lat1, lon1, lat2, lon2) {
lat1 = Deg2Rad(lat1);
lat2 = Deg2Rad(lat2);
lon1 = Deg2Rad(lon1);
lon2 = Deg2Rad(lon2);
var R = 6371; // km
-
var x = (lon2 - lon1) * Math.cos((lat1 + lat2) / 2);
var y = lat2 - lat1;
var d = Math.sqrt(x * x + y * y) * R;
return d;
}
-
var minDif = 99999;
- var closest = locationsList.default; // loop through each location, matching a close city then the next closest and so on
+ var closest = locationsList.default;
+ // loop through each location, matching a close city then the next closest and so on
for (var key in locationsList) {
/* eslint-disable no-prototype-builtins */
if (locationsList.hasOwnProperty(key)) {
@@ -1429,7 +1337,6 @@ function vfLocationNearestResolve(locationsList, userLocation) {
if (key != "default") {
var evalutedLocation = locationsList[key];
var dif = PythagorasEquirectangular(latitude, longitude, evalutedLocation.latlon.split(", ")[0], evalutedLocation.latlon.split(", ")[1]);
-
if (dif < minDif) {
closest = evalutedLocation;
closest.id = key;
@@ -1438,10 +1345,8 @@ function vfLocationNearestResolve(locationsList, userLocation) {
}
}
}
-
return closest;
}
-
if (userLocation == false) {
// if no match, use the default location
console.warn("vfLocationNearest", "No user location detected, will use default");
@@ -1452,23 +1357,25 @@ function vfLocationNearestResolve(locationsList, userLocation) {
vfLocationNearestSave(closestCity.name, closestCity.id);
}
}
+
/**
* Receive a resolved location and assign it to the DOM
* @example vfLocationNearestSave(locationsList, userLocation)
* @param {object} [locationName] - A user-facing string
* @param {string} [locationId] - The ID
*/
-
-
function vfLocationNearestSave(locationName, locationId) {
// console.log('vfLocationNearestSave location',locationName,locationId)
+
// assign to the body
var el = document.querySelector("body");
el.setAttribute("data-vf-location-nearest-location", locationId);
- el.setAttribute("data-vf-location-nearest-name", locationName); // indicate we've loaded
+ el.setAttribute("data-vf-location-nearest-name", locationName);
+ // indicate we've loaded
vfLocationNearestIndicate("load");
}
+
/**
* Observe an element for changes to specify a manual location
* This may support a "type" but for now it's only a select list
@@ -1476,27 +1383,23 @@ function vfLocationNearestSave(locationName, locationId) {
* @param {object} [scope] - the html scope to process, optional, defaults to `document`
* @example vfLocationNearestOverridePopulate(locationsList, document.vfLocationNearestDomActions('.vf-component__container')[0]);
*/
-
-
function vfLocationNearestOverridePopulate(locationsList, scope) {
/* eslint-disable no-redeclare */
var scope = scope || document;
/* eslint-enable no-redeclare */
var locationWidget = scope.querySelectorAll("[data-vf-js-location-nearest-override-widget]");
-
if (!locationWidget) {
// exit: container not found
return;
}
-
if (locationWidget.length == 0) {
// exit: content not found
return;
}
+ var widget = "" + ""; // assign values to widget
-
+ // assign values to widget
locationWidget[0].innerHTML = widget;
}
+
/**
* Observe an element for changes to specify a manual location
* @param {object} [scope] - the html scope to process, optional, defaults to `document`
* @example vfLocationNearestOverrideActivate(locationsList, document.vfLocationNearestDomActions('.vf-component__container')[0]);
*/
-
-
function vfLocationNearestOverrideActivate(scope) {
/* eslint-disable no-redeclare */
var scope = scope || document;
/* eslint-enable no-redeclare */
var overrideElement = scope.querySelectorAll("[data-vf-js-location-nearest-override-widget]");
-
if (!overrideElement) {
// exit: container not found
return;
}
-
if (overrideElement.length == 0) {
// exit: content not found
return;
}
-
overrideElement[0].addEventListener("change", function (e) {
- var activeItem = e.target; // console.log('You selected: ', activeItem.options[activeItem.target.selectedIndex].text);
-
+ var activeItem = e.target;
+ // console.log('You selected: ', activeItem.options[activeItem.target.selectedIndex].text);
vfLocationNearestSave(activeItem.options[activeItem.selectedIndex].text, activeItem.value);
});
}
+
/**
* With attributes saved to the dom, we can take further action
* = 200 && xhr.status < 300) {
resolve(xhr.response);
@@ -1677,20 +1574,18 @@ function emblContentHubLoaderHtmlImports() {
reject(new Error("Failed to fetch '" + url + "': " + xhr.status + " " + xhr.statusText));
}
};
-
xhr.onerror = reject;
xhr.open("GET", url);
xhr.responseType = responseType;
xhr.send();
});
}
-
function _AddImport(url, preFetchedDoc, rootContext, progressObject) {
/* eslint-disable no-unused-vars */
var isRoot = false;
/* eslint-enable no-unused-vars */
- // The initial import creates a root context, which is passed along to all sub-imports.
+ // The initial import creates a root context, which is passed along to all sub-imports.
if (!rootContext) {
isRoot = true;
rootContext = {
@@ -1699,24 +1594,23 @@ function emblContentHubLoaderHtmlImports() {
stylePromises: [],
scriptPromises: [],
progress: progressObject || {} // progress written to this object (loaded, total)
-
};
+
rootContext.progress.loaded = 0;
rootContext.progress.total = 1; // add root import
- } // Each import also tracks its own state with its own context.
+ }
+ // Each import also tracks its own state with its own context.
/* eslint-disable no-unused-vars */
-
-
var context = {
importDoc: null,
baseUrl: GetPathFromURL(url),
dependencies: []
};
/* eslint-enable no-unused-vars */
+
// preFetchedDoc is passed for sub-imports which pre-fetch their documents as an optimisation. If it's not passed,
// fetch the URL to get the document.
-
var loadDocPromise;
if (preFetchedDoc) loadDocPromise = Promise.resolve(preFetchedDoc);else loadDocPromise = FetchAs(url, "document");
return loadDocPromise.then(function (doc) {
@@ -1725,44 +1619,41 @@ function emblContentHubLoaderHtmlImports() {
// calculate the correct URL and use Object.defineProperty to override the returned document URL.
Object.defineProperty(doc, "URL", {
value: new URL(url, GetBaseURL()).toString()
- }); // we don't need the `body` wrapper, so return the first child
+ });
+ // we don't need the `body` wrapper, so return the first child
return doc.body.firstChild;
});
}
-
function AddImport(url, async, progressObject) {
// Note async attribute ignored (was only used for old native implementation).
return _AddImport(url, null, null, progressObject);
}
-
window["addImport"] = AddImport;
-} // embl-conditional-edit
+}
+
+// embl-conditional-edit
/**
* Invoke emblConditionalEditDetectParam scopped to objects where
* data-embl-js-conditional-edit is present
* This will be dynamically run once emblContentHubSignalFinished is triggered.
*/
-
-
function emblConditionalEdit() {
var emblConditionalEditItems = document.querySelectorAll("[data-embl-js-conditional-edit]");
-
if (!emblConditionalEditItems) {
// exit: lists not found
return;
}
-
if (emblConditionalEditItems.length == 0) {
// exit: lists not found
return;
}
-
Array.prototype.forEach.call(emblConditionalEditItems, function (element) {
emblConditionalEditDetectParam(location.href, element);
});
}
+
/**
* Detects `?embl-conditional-edit=enabled` or `?embl-conditional-edit=1` or ?embl-conditional-edit=true`
* and adds `.embl-coditional-edit__enabled` to display the edit links
@@ -1770,72 +1661,63 @@ function emblConditionalEdit() {
* @param {element} [element] - the scopped element to be processed
* @param {string} [referrer] - what part of the page is asking for a check, we pass this to avoid recursion
*/
-
-
function emblConditionalEditDetectParam(url, element, referrer) {
var captured = /embl-conditional-edit=([^&]+)/.exec(url);
-
if (captured == null && referrer != "iframe") {
// value not found
+
// also try against any parent iframe url
if (window.self !== window.top) {
console.log(url, parent.window.location.href);
emblConditionalEditDetectParam(parent.window.location.href, element, "iframe");
}
-
return;
}
-
captured = captured || false; // avoid null
-
captured = captured[1];
-
if (captured == "1" || captured == "enabled" || captured == "true") {
element.className += " " + "embl-coditional-edit__enabled";
}
-} // embl-notifications
+}
+
+// embl-notifications
/**
* After a notifications has been chosen, build it and insert into the document
* @example emblNotificationsInject(notification)
* @param {object} [message] - An object to be show on a page
*/
-
-
function emblNotificationsInject(message) {
- var output = document.createElement("div"); // @todo:
+ var output = document.createElement("div");
+
+ // @todo:
// - add support in contentHub for extra button text, link
- // preparation
+ // preparation
message.body = message.body.replace(/<[/]?[p>]+>/g, " "); // no
tags allowed in inline messages, preserve a space to not collide words
// add vf-link to link
-
message.body = message.body.replaceAll("Learn more");
- } // custom button text
-
-
- message.field_notification_button_text = message.field_notification_button_text || "Close notice"; // notification memory and cookie options
-
+ }
+ // custom button text
+ message.field_notification_button_text = message.field_notification_button_text || "Close notice";
+ // notification memory and cookie options
if (message.field_notification_cookie == "True") {
output.dataset.vfJsBannerCookieName = message.cookieName;
output.dataset.vfJsBannerCookieVersion = message.cookieVersion;
-
if (message.field_notification_auto_accept == "True") {
output.dataset.vfJsBannerAutoAccept = true;
}
}
-
if (message.field_notification_position == "fixed") {
output.classList.add("vf-banner", "vf-banner--fixed", "vf-banner--bottom", "vf-banner--notice");
output.dataset.vfJsBanner = true;
output.dataset.vfJsBannerState = message.field_notification_presentation;
- output.dataset.vfJsBannerButtonText = message.field_notification_button_text; // These features are not yet supported by the notification content type in the EMBL contentHub
+ output.dataset.vfJsBannerButtonText = message.field_notification_button_text;
+ // These features are not yet supported by the notification content type in the EMBL contentHub
// output.dataset.vfJsBannerExtraButton = "Optional buttonNew tab button";
-
output.innerHTML = "\n
\n
".concat(message.body, "
\n
");
var target = document.body.firstChild;
target.parentNode.prepend(output);
@@ -1844,49 +1726,45 @@ function emblNotificationsInject(message) {
output.classList.add("vf-grid", "vf-u-margin__top--400"); // we wrap in vf-grid for layout
// we use vf-u-margin__top--400 as this element is usually inserted inside a contentHub wrapper and not affected by body.vf-stack
// if vf-stack is set, this will have no practical affect
+ output.innerHTML = "\n
\n
\n
".concat(message.body, "
\n
\n
");
- output.innerHTML = "\n
\n
\n
".concat(message.body, "
\n
\n
"); // insert after `vf-header` or at after `vf-body`
+ // insert after `vf-header` or at after `vf-body`
// @todo: add support for where "inline" message should be shown
// @todo: don't rely on the presence of vf-header to show inline notification, maybe
-
var _target = document.getElementsByClassName("vf-header");
-
if (_target.length > 0) {
_target[0].parentNode.insertBefore(output, _target[0].nextSibling);
} else {
// if no vf-header, perhaps there's a masthead-black-bar?
var _target2 = document.getElementsByClassName("masthead-black-bar");
-
if (_target2.length > 0) {
_target2[0].parentNode.insertBefore(output, _target2[0].nextSibling);
} else {
// if no vf-header, show at vf-body
// @thought: we might instead make this show as "top"
var _target3 = document.getElementsByClassName("vf-body");
-
if (_target3.length > 0) {
// output.classList.add('vf-u-grid--reset');
_target3[0].prepend(output);
} // if still no success, we soft fail
-
}
}
} else if (message.field_notification_position == "top") {
output.classList.add("vf-banner", "vf-banner--fixed", "vf-banner--top", "vf-banner--phase");
output.dataset.vfJsBanner = true;
output.dataset.vfJsBannerState = message.field_notification_presentation;
- output.dataset.vfJsBannerButtonText = message.field_notification_button_text; // These features are not yet supported by the notification content type in the EMBL contentHub
+ output.dataset.vfJsBannerButtonText = message.field_notification_button_text;
+ // These features are not yet supported by the notification content type in the EMBL contentHub
// output.dataset.vfJsBannerExtraButton = "Optional buttonNew tab button";
-
output.innerHTML = "\n
\n
".concat(message.body, "
\n
");
var _target4 = document.body.firstChild;
-
_target4.parentNode.prepend(output);
-
vfBanner();
- } // console.log('emblNotifications, showing:', message);
+ }
+ // console.log('emblNotifications, showing:', message);
}
+
/**
* The global function for this component
* Note: if you use embl-content-hub-loader, it will automatically invoke emblNotifications
@@ -1894,54 +1772,60 @@ function emblNotificationsInject(message) {
* @param {string} [currentHost] - a host url www.embl.org
* @param {string} [currentPath] - a path /people/name
*/
-
-
function emblNotifications(currentHost, currentPath) {
currentHost = currentHost || window.location.hostname;
- currentPath = currentPath || window.location.pathname; // don't treat `wwwdev` as distinct from `www`
+ currentPath = currentPath || window.location.pathname;
+ // don't treat `wwwdev` as distinct from `www`
+ currentHost = currentHost.replace(/wwwdev/g, "www");
- currentHost = currentHost.replace(/wwwdev/g, "www"); // console.log('emblNotifications','Checking for notifications.');
+ // console.log('emblNotifications','Checking for notifications.');
// console.log('emblNotifications, Current url info:', currentHost + "," + currentPath);
- // Process each message against a URLs
+ // Process each message against a URLs
function matchNotification(message, targetUrl) {
var matchFound = false;
-
if (message.hasBeenShown == true) {
// console.warn('emblNotifications', 'This message has already been displayed on the page.')
return;
- } // console.log('emblNotifications, targetUrl:', targetUrl);
- // console.log('emblNotifications, matching:', currentHost+currentPath);
- // Is there an exact match?
+ }
+ // console.log('emblNotifications, targetUrl:', targetUrl);
+ // console.log('emblNotifications, matching:', currentHost+currentPath);
- matchFound = compareUrls(currentHost + currentPath, targetUrl); // Handle wildcard matches like `/about/*`
+ // Is there an exact match?
+ matchFound = compareUrls(currentHost + currentPath, targetUrl);
+ // Handle wildcard matches like `/about/*`
if (targetUrl.slice(-1) == "*") {
matchFound = compareUrls(currentHost + currentPath, targetUrl, true);
- } // if a match has been made on the current url path, show the message
-
+ }
+ // if a match has been made on the current url path, show the message
if (matchFound == true) {
// console.log('emblNotifications: MATCH FOUND 🎉', targetUrl, currentHost, currentPath);
message.hasBeenShown = true;
emblNotificationsInject(message);
}
- } // Handle string comparisons for URLs
-
+ }
+ // Handle string comparisons for URLs
function compareUrls(url1, url2, isWildCard) {
- isWildCard = isWildCard || false; // we ignore case
- // we could probably optimise by moving this higher in the logic, but it's more maintainable to have it here
+ isWildCard = isWildCard || false;
+ // we ignore case
+ // we could probably optimise by moving this higher in the logic, but it's more maintainable to have it here
url1 = url1.toLowerCase();
- url2 = url2.toLowerCase(); // don't allow matches to end in `*`
+ url2 = url2.toLowerCase();
+ // don't allow matches to end in `*`
if (url1.slice(-1) == "*") url1 = url1.substring(0, url1.length - 1);
- if (url2.slice(-1) == "*") url2 = url2.substring(0, url2.length - 1); // don't allow matches to end in `/`
+ if (url2.slice(-1) == "*") url2 = url2.substring(0, url2.length - 1);
+ // don't allow matches to end in `/`
if (url1.slice(-1) == "/") url1 = url1.substring(0, url1.length - 1);
- if (url2.slice(-1) == "/") url2 = url2.substring(0, url2.length - 1); // console.log('emblNotifications, comparing:', url1 + "," + url2);
+ if (url2.slice(-1) == "/") url2 = url2.substring(0, url2.length - 1);
+
+ // console.log('emblNotifications, comparing:', url1 + "," + url2);
if (url1 == url2) {
return true;
@@ -1954,38 +1838,37 @@ function emblNotifications(currentHost, currentPath) {
return true;
}
}
-
return false;
- } // Process each message, and its URL fragments
-
+ }
+ // Process each message, and its URL fragments
function processNotifications(messages) {
// console.log('emblNotifications', messages);
+
// Process each message
for (var index = 0; index < messages.length; index++) {
- var currentMessage = messages[index]; // track if a message has already been show on the page
- // we want to be sure a message isn't accidently shown twice
+ var currentMessage = messages[index];
- currentMessage.hasBeenShown = false; // Process the URLs for each path in a message
+ // track if a message has already been show on the page
+ // we want to be sure a message isn't accidently shown twice
+ currentMessage.hasBeenShown = false;
+ // Process the URLs for each path in a message
var currentUrls = currentMessage.field_notification_urls.split(",");
-
for (var indexUrls = 0; indexUrls < currentUrls.length; indexUrls++) {
var url = currentUrls[indexUrls].trim();
matchNotification(currentMessage, url); // pass the notification and active url to compare
}
}
- } // Utility to fetch a file, process the JSON
-
+ }
+ // Utility to fetch a file, process the JSON
function loadRemoteNotifications(file) {
// console.log('emblNotifications','Opening URL :' + file);
if (window.XMLHttpRequest) {
var xmlhttp = new XMLHttpRequest();
}
-
xmlhttp.open("GET", file, true);
-
xmlhttp.onload = function () {
if (xmlhttp.readyState === 4) {
if (xmlhttp.status === 200) {
@@ -1997,38 +1880,37 @@ function emblNotifications(currentHost, currentPath) {
}
}
};
-
xmlhttp.onerror = function () {
console.error(xmlhttp.statusText);
};
-
xmlhttp.send(null);
- } // Bootstrap the message fetching
- // If on dev, reference dev server
-
+ }
+ // Bootstrap the message fetching
+ // If on dev, reference dev server
if (window.location.hostname.indexOf("wwwdev.") === 0) {
loadRemoteNotifications("https://wwwdev.embl.org/api/v1/notifications?_format=json&source=contenthub");
} else if (window.location.hostname.indexOf("localhost") === 0) {
loadRemoteNotifications("https://wwwdev.embl.org/api/v1/notifications?_format=json&source=contenthub");
} else {
loadRemoteNotifications("https://www.embl.org/api/v1/notifications?_format=json&source=contenthub");
- } // Check fallback notifications
-
+ }
+ // Check fallback notifications
loadRemoteNotifications("https://embl-communications.github.io/embl-notifcations-fallback/notifications.js");
-} // Add this to your ./components/vf-component-rollup/scripts.js
+}
+
+// Add this to your ./components/vf-component-rollup/scripts.js
// import { emblNotifications } from '../components/raw/embl-notifications/embl-notifications.js';
// And invoke it
// Note: if you use embl-content-hub-loader, it will automatically invoke emblNotifications
// emblNotifications();
+
// embl-content-hub-loader__fetch
/**
* Fetch html links from content.embl.org
*/
-
-
function emblContentHubFetch() {
// Some JS utilities
// via https://stackoverflow.com/a/32135318
@@ -2038,91 +1920,97 @@ function emblContentHubFetch() {
Element.prototype.appendAfter = function (element) {
element.parentNode.insertBefore(this, element.nextSibling);
}, false;
+
/**
* Get the number of days between two dates.
*/
-
function days_between(date1, date2) {
// The number of milliseconds in one day
- var ONE_DAY = 1000 * 60 * 60 * 24; // Convert both dates to milliseconds
+ var ONE_DAY = 1000 * 60 * 60 * 24;
+ // Convert both dates to milliseconds
var date1_ms = date1.getTime();
- var date2_ms = date2.getTime(); // Calculate the difference in milliseconds
+ var date2_ms = date2.getTime();
- var difference_ms = Math.abs(date1_ms - date2_ms); // Convert back to days and return
+ // Calculate the difference in milliseconds
+ var difference_ms = Math.abs(date1_ms - date2_ms);
+ // Convert back to days and return
return Math.round(difference_ms / ONE_DAY) + 1;
- } // A list of all the links
-
+ }
+ // A list of all the links
var emblContentHubLinks = document.querySelectorAll("[data-embl-js-content-hub-loader]");
var emblContentHubLinkLoadingProgress = {};
- var emblContentHubShowTimers = false; // Handle the import of each element
+ var emblContentHubShowTimers = false;
+ // Handle the import of each element
for (var i = 0; i < emblContentHubLinks.length; ++i) {
(function () {
- var linkPosition = i; // track time it takes for link to be shown
+ var linkPosition = i;
+ // track time it takes for link to be shown
if (emblContentHubShowTimers) {
console.time("timer for import " + linkPosition);
- } // await the load of the html import from the polyfill
- // note: we use polyfill in all cases; see https://github.com/visual-framework/vf-core/issues/508
-
+ }
+ // await the load of the html import from the polyfill
+ // note: we use polyfill in all cases; see https://github.com/visual-framework/vf-core/issues/508
emblContentHubAwaitLoading(emblContentHubLinks[linkPosition], linkPosition);
})();
- } // If nothing to import
-
+ }
+ // If nothing to import
if (emblContentHubLinks.length == 0) {
emblContentHubSignalFinished();
- } // Add a class to the body once the last item has been processed
-
+ }
+ // Add a class to the body once the last item has been processed
function emblContentHubSignalFinished() {
// @todo, shouldn't require the body element
- document.querySelectorAll("body")[0].classList.add("embl-content-hub-loaded"); // if the JS to run embl-conditional-edit is present, run it now
+ document.querySelectorAll("body")[0].classList.add("embl-content-hub-loaded");
+ // if the JS to run embl-conditional-edit is present, run it now
if (typeof emblConditionalEdit === "function") {
emblConditionalEdit();
- } // if the JS to run embl-notifications is present, run it now
-
+ }
+ // if the JS to run embl-notifications is present, run it now
if (typeof emblNotifications === "function") {
emblNotifications();
}
- } // Dispatch load to the pollyfill
-
+ }
+ // Dispatch load to the pollyfill
function emblContentHubAwaitLoading(targetLink, position) {
/* global addImport */
// Docs: https://github.com/AshleyScirra/html-imports-polyfill#usage
addImport(targetLink.href, null, emblContentHubLinkLoadingProgress).then(function (value) {
emblContentHubGrabTheContent(targetLink, position, value);
-
if (position + 1 == emblContentHubLinks.length) {
emblContentHubSignalFinished();
}
});
- } // Generate a unique ID for the target element on the page
-
+ }
+ // Generate a unique ID for the target element on the page
function emblContentHubGenerateID(position) {
return "contentDbItem" + ("0000" + position).slice(-5);
- } // Show the remote content
-
+ }
+ // Show the remote content
function emblContentHubGrabTheContent(targetLink, position, exportedContent) {
// pickup the "meat" of the exported content
- exportedContent = exportedContent || targetLink.import.querySelector(".vf-content-hub-html"); // make sure we have something
+ exportedContent = exportedContent || targetLink.import.querySelector(".vf-content-hub-html");
+ // make sure we have something
if (!exportedContent) {
console.log("No content found for this import, exiting. The import may have already been preformed.", targetLink);
return;
- } // if there is just one child element and it is a div, use that
- // (this helps with css grid layout)
-
+ }
+ // if there is just one child element and it is a div, use that
+ // (this helps with css grid layout)
if (exportedContent.childElementCount === 1 && exportedContent.firstElementChild.innerHTML.trimLeft().substr(0, 4) === "
// This would make the ul a two-column grid.
-
-
function emblContentHubAssignClasses(targetLink, position) {
// var injectRequests = document.querySelectorAll('[data-inject-class][data-inject-class-target]');
//
// for (var i = 0; i < injectRequests.length; ++i) {
+
var classesToInject = targetLink.getAttribute("data-inject-class");
var targetSelectorToInject = targetLink.getAttribute("data-inject-class-target");
-
if (classesToInject && targetSelectorToInject) {
// Limit scope to the imported element
- var targetElement = document.querySelector("." + emblContentHubGenerateID(position)).querySelector(targetSelectorToInject); // We can't inject space separated classes to we need to split it into arrays and add one by one.
+ var targetElement = document.querySelector("." + emblContentHubGenerateID(position)).querySelector(targetSelectorToInject);
+ // We can't inject space separated classes to we need to split it into arrays and add one by one.
classesToInject = classesToInject.split(" ");
-
for (var classNumber = 0; classNumber < classesToInject.length; classNumber++) {
targetElement.classList.add(classesToInject[classNumber]);
}
}
}
+
/**
* Update the format of close date.
*/
-
-
function emblContentHubUpdateDatesFormat(position) {
var dateRemainingList = document.querySelector("." + emblContentHubGenerateID(position)).querySelectorAll(".date-days-remaining");
var todayDate = new Date();
-
if (dateRemainingList.length > 0) {
for (var dateRemainingIndex = 0; dateRemainingIndex < dateRemainingList.length; dateRemainingIndex++) {
var dateValue = parseInt(dateRemainingList[dateRemainingIndex].getAttribute("data-datetime")) * 1000;
dateValue = new Date(dateValue);
- var numberOfDiffDays = days_between(dateValue, todayDate); // Update to 'Closes in 6 Days.' format if number of days is less than 30 days.
-
+ var numberOfDiffDays = days_between(dateValue, todayDate);
+ // Update to 'Closes in 6 Days.' format if number of days is less than 30 days.
if (numberOfDiffDays < 30 && numberOfDiffDays > 1) {
dateRemainingList[dateRemainingIndex].innerHTML = "Closes in " + "" + numberOfDiffDays + " Days.";
}
-
if (numberOfDiffDays == 1) {
dateRemainingList[dateRemainingIndex].innerHTML = "Closes in " + "" + numberOfDiffDays + " Day.";
}
}
}
}
-} // embl-content-hub-loader
+}
+// embl-content-hub-loader
function emblContentHub() {
// 1. make sure we have imports or a polyfill
- emblContentHubLoaderHtmlImports(); // 2. import the content
+ emblContentHubLoaderHtmlImports();
+ // 2. import the content
emblContentHubFetch();
-} // embl-content-meta-properties
+}
+
+// embl-content-meta-properties
+
// In addition to being queried by other components' JS, this could
// also add classes to a page to affect the overall look of a page.
@@ -2280,34 +2163,33 @@ function emblContentHub() {
* Read metaProperties from page's metatags
* @example emblContentMetaProperties_Read()
*/
-
-
function emblContentMetaProperties_Read() {
- var metaProperties = {}; //
+ var metaProperties = {};
+ //
//
//
//
//
-
metaProperties.who = metaProperties.who || document.querySelector("meta[name='embl:who']");
metaProperties.what = metaProperties.what || document.querySelector("meta[name='embl:what']");
metaProperties.where = metaProperties.where || document.querySelector("meta[name='embl:where']");
- metaProperties.active = metaProperties.active || document.querySelector("meta[name='embl:active']"); //
+ metaProperties.active = metaProperties.active || document.querySelector("meta[name='embl:active']");
+
+ //
//
//
-
metaProperties.utility = metaProperties.utility || document.querySelector("meta[name='embl:utility']");
- metaProperties.reach = metaProperties.reach || document.querySelector("meta[name='embl:reach']"); //
+ metaProperties.reach = metaProperties.reach || document.querySelector("meta[name='embl:reach']");
+
+ //
//
//
//
//
-
metaProperties.maintainer = metaProperties.maintainer || document.querySelector("meta[name='embl:maintainer']");
metaProperties.lastReview = metaProperties.lastReview || document.querySelector("meta[name='embl:last-review']");
metaProperties.reviewCycle = metaProperties.reviewCycle || document.querySelector("meta[name='embl:review-cycle']");
metaProperties.expiry = metaProperties.expiry || document.querySelector("meta[name='embl:expiry']");
-
for (var key in metaProperties) {
if (metaProperties[key] != null && metaProperties[key].getAttribute("content").length != 0) {
metaProperties[key] = metaProperties[key].getAttribute("content");
@@ -2315,26 +2197,28 @@ function emblContentMetaProperties_Read() {
metaProperties[key] = 'notSet';
}
}
-
return metaProperties;
-} // embl-breadcrumbs-lookup
-// to hold the EMBL taxonomy
+}
+// embl-breadcrumbs-lookup
-var emblTaxonomy = {}; // placeholders for our new breadcrumbs
+// to hold the EMBL taxonomy
+var emblTaxonomy = {};
+// placeholders for our new breadcrumbs
var emblBreadcrumbPrimary = document.createElement("ul");
emblBreadcrumbPrimary.classList.add("vf-breadcrumbs__list", "vf-list", "vf-list--inline");
var emblBreadcrumbRelated = document.createElement("ul");
-emblBreadcrumbRelated.classList.add("vf-breadcrumbs__list", "vf-breadcrumbs__list--related", "vf-list", "vf-list--inline"); // we store the primairy breadcrumb so it can be accessed by related crumbs, if needed
+emblBreadcrumbRelated.classList.add("vf-breadcrumbs__list", "vf-breadcrumbs__list--related", "vf-list", "vf-list--inline");
+// we store the primairy breadcrumb so it can be accessed by related crumbs, if needed
var primaryBreadcrumb;
+
/**
* Look up a breadcrumb by its uuid and return the entry
* @example emblBreadcumbLookupByUuid(uuid)
* @param {string} [uuid] - the uuid of a term
*/
-
function emblBreadcumbLookupByUuid(uuid) {
// console.log('emblBreadcumbLookupByUuid',uuid);
if (emblTaxonomy.terms[uuid]) {
@@ -2342,63 +2226,60 @@ function emblBreadcumbLookupByUuid(uuid) {
return emblTaxonomy.terms[uuid];
}
}
+
/**
* Take any appropriate actions depending on present metaTags
* @example emblBreadcrumbsLookup()
* @param {object} [metaProperties] - if you do not have meta tags on the page,
* you can explicitly pass options
*/
-
-
function emblBreadcrumbsLookup(metaProperties) {
var emblBreadcrumbTarget = document.querySelectorAll("[data-embl-js-breadcrumbs-lookup]");
-
if (emblBreadcrumbTarget.length === 0) {
// console.warn('There is no `[data-embl-js-breadcrumbs-lookup]` in which to insert the breadcrumbs; exiting');
return false;
}
-
if (emblBreadcrumbTarget.length > 1) {
console.warn("There is more than one `[data-embl-js-breadcrumbs-lookup]` in which to insert the breadcrumbs; continuing but only the first element will be updated.");
}
-
if (metaProperties.active == "notSet") {
// @todo: we could infer the active breadcrumb if only one is passed
console.warn("There is no active EMBL breadcrumb specified, cannot proceed looking up breadcrumbs.");
return false;
}
+ var majorFacets = ["who", "what", "where"];
- var majorFacets = ["who", "what", "where"]; // do the primairy breadcrumb first
+ // do the primairy breadcrumb first
+ emblBreadcrumbAppend(emblBreadcrumbTarget, metaProperties[metaProperties.active], metaProperties.active, "primary");
- emblBreadcrumbAppend(emblBreadcrumbTarget, metaProperties[metaProperties.active], metaProperties.active, "primary"); // do the non-primairy meta terms
+ // do the non-primairy meta terms
// @todo: we probably shouldn't do related if there is no primairy
-
for (var i = 0; i < majorFacets.length; i++) {
if (majorFacets[i] != metaProperties.active) {
emblBreadcrumbAppend(emblBreadcrumbTarget, metaProperties[majorFacets[i]], majorFacets[i], "related");
}
- } // make a 'related' label
-
+ }
+ // make a 'related' label
var relatedLabel = document.createElement("span");
relatedLabel.innerHTML = "Related:";
- relatedLabel.classList.add("vf-breadcrumbs__heading"); // If no related terms were found, hide the related label
- // we only hide it as we could add related terms later
+ relatedLabel.classList.add("vf-breadcrumbs__heading");
+ // If no related terms were found, hide the related label
+ // we only hide it as we could add related terms later
if (emblBreadcrumbRelated.childNodes.length == 0) {
relatedLabel.classList.add("vf-u-display-none");
- } // now that we've processed all the meta properties, insert our rendered breadcrumbs
-
+ }
+ // now that we've processed all the meta properties, insert our rendered breadcrumbs
emblBreadcrumbTarget[0].innerHTML = emblBreadcrumbPrimary.outerHTML + relatedLabel.outerHTML + emblBreadcrumbRelated.outerHTML;
}
+
/**
* Get the EMBL taxonomy json from the ContentHub
* @example emblGetTaxonomy()
* @param {string} [url] - URL to pull the taxonomy from
*/
-
-
function emblGetTaxonomy(url) {
/* eslint-disable no-redeclare */
var url = url || "https://www.embl.org/api/v1/pattern.json?pattern=embl-ontology&source=contenthub";
@@ -2408,7 +2289,6 @@ function emblGetTaxonomy(url) {
// Do the usual XHR stuff
var req = new XMLHttpRequest();
req.open("GET", url);
-
req.onload = function () {
// This is called even on 404 etc
// so check the status
@@ -2420,28 +2300,28 @@ function emblGetTaxonomy(url) {
// which will hopefully be a meaningful error
reject(Error(req.statusText));
}
- }; // Handle network errors
-
+ };
+ // Handle network errors
req.onerror = function () {
reject(Error("Error loading ontology"));
- }; // Make the request
-
+ };
+ // Make the request
req.send();
});
}
+
/**
* Receive a string and convert any non a-z character
* @example emblBreadcrumbRemoveDiacritics('Spaßß')
* @param {str} - a name or such
* @todo this might be better as a general vf utility
*/
-
-
function emblBreadcrumbRemoveDiacritics(str) {
- str = str || ""; // https://github.com/backbone-paginator/backbone.paginator/blob/a579796a30e583c4dfa09e0a86e4abd21e0b5b56/plugins/diacritic.js
+ str = str || "";
+ // https://github.com/backbone-paginator/backbone.paginator/blob/a579796a30e583c4dfa09e0a86e4abd21e0b5b56/plugins/diacritic.js
var defaultDiacriticsRemovalMap = [{
"base": "A",
"letters": /[\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F]/g
@@ -2695,16 +2575,16 @@ function emblBreadcrumbRemoveDiacritics(str) {
"base": "z",
"letters": /[\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763]/g
}];
-
for (var i = 0; i < defaultDiacriticsRemovalMap.length; i++) {
str = str.replace(defaultDiacriticsRemovalMap[i].letters, defaultDiacriticsRemovalMap[i].base);
- } // remove all commas, apostrophes, etc
- // @todo, this should be done by an optional paramater
-
+ }
+ // remove all commas, apostrophes, etc
+ // @todo, this should be done by an optional paramater
str = str.replace(/[^a-zA-Z0-9 ]/, "");
return str;
}
+
/**
* Receive a term and its context and create a breadcrumb
* @example emblBreadcrumbAppend(breadcrumbTarget,term,facet,type)
@@ -2713,58 +2593,54 @@ function emblBreadcrumbRemoveDiacritics(str) {
* @param {string} [facet] - the facet of the taxonomy (`who`, `what` or `where`)
* @param {string} [type] - if this is a `primary` or `related` path
*/
-
-
function emblBreadcrumbAppend(breadcrumbTarget, termName, facet, type) {
// console.log('Processing breadcrumb for:', termName + ', ' + facet + ', ' + type);
+
function getCurrentTerm(termName) {
var termObject; // store the match
-
if (termName === "EMBL") termName = "All EMBL sites"; // hack as we're not using IDs
+
// if a term has not been passed, attempt to use the primary term's parent information
// @todo: add a flag to explicitly "dontLookup" or "doLookup"
-
if (termName == "notSet") {
termName = ""; // we'll either find a positive termObject or not show anything
// console.log('here',primaryBreadcrumb.parents)
-
if (primaryBreadcrumb.parents[facet]) {
termName = primaryBreadcrumb.parents[facet];
}
- } // if using a `string/NameOfThing` value, not accordingly
-
+ }
+ // if using a `string/NameOfThing` value, not accordingly
if (termName.indexOf("string/") >= 0) {
console.warn("embl-js-breadcumbs-lookup: using a passed string value to make breadcrumbs " + termName);
termName = termName.replace("string/", "");
- } // scan through all terms and find a match, if any
-
+ }
+ // scan through all terms and find a match, if any
function emblBreadcumbLookup(termName) {
// @todo: if a UUID meta property is set, use that
+
// if it's UUID match we use that
termObject = emblBreadcumbLookupByUuid(termName);
-
if (typeof termObject != "undefined") {
return; //exit
- } // We prefer profiles
-
+ }
+ // We prefer profiles
Array.prototype.forEach.call(Object.keys(emblTaxonomy.terms), function (termId) {
var term = emblTaxonomy.terms[termId];
-
if (term.type == "profile") {
if (term.name === termName) {
termObject = term;
return; //exit
}
}
- }); // If no profile found, match other types of taxonomy entries
+ });
+ // If no profile found, match other types of taxonomy entries
if (typeof termObject === "undefined") {
Array.prototype.forEach.call(Object.keys(emblTaxonomy.terms), function (termId) {
var term = emblTaxonomy.terms[termId];
-
if (term.type != "profile") {
if (term.name === termName) {
termObject = term;
@@ -2772,27 +2648,27 @@ function emblBreadcrumbAppend(breadcrumbTarget, termName, facet, type) {
}
}
});
- } // If there's still no match, see if we can find a matching display name
+ }
+
+ // If there's still no match, see if we can find a matching display name
// @todo: this is an easy win but creates messy matching, but maybe that's ok if you're not using UUID
// There's a risk of multiple "training" entries
- // We prefer profiles
-
+ // We prefer profiles
Array.prototype.forEach.call(Object.keys(emblTaxonomy.terms), function (termId) {
var term = emblTaxonomy.terms[termId];
-
if (term.type == "profile") {
if (term.name_display === termName) {
termObject = term;
return; //exit
}
}
- }); // If no profile found, match other types of taxonomy entries
+ });
+ // If no profile found, match other types of taxonomy entries
if (typeof termObject === "undefined") {
Array.prototype.forEach.call(Object.keys(emblTaxonomy.terms), function (termId) {
var term = emblTaxonomy.terms[termId];
-
if (term.type != "profile") {
if (term.name_display === termName) {
termObject = term;
@@ -2801,19 +2677,19 @@ function emblBreadcrumbAppend(breadcrumbTarget, termName, facet, type) {
}
});
}
- } // don't scan for junk matches
-
+ }
+ // don't scan for junk matches
if (termName != "notSet" && termName != "" && termName != "none") {
emblBreadcumbLookup(termName);
- } // Validation and protection
- // we never want to return undefined
-
+ }
+ // Validation and protection
+ // we never want to return undefined
if (termObject == undefined || termObject == null) {
// console.warn('embl-js-breadcumbs-lookup: No matching breadcrumb found for `' + termName + '`; Will formulate a URL.');
- termObject = {};
+ termObject = {};
if (facet == "who") {
// if we're linking to people generate a person URL
termObject.url = "https://www.embl.org/people/person/" + emblBreadcrumbRemoveDiacritics(termName).replace(/[\W_]+/g, " ").replace(/\s+/g, "-").toLowerCase();
@@ -2828,17 +2704,15 @@ function emblBreadcrumbAppend(breadcrumbTarget, termName, facet, type) {
} else if (typeof termObject.url == "undefined") {
// if entry was found but no link specified, generate a url for a search
var urlFacet = "";
-
if (termObject.primary != undefined) {
// prepare a search facet if available
urlFacet = "&taxonomyFacet=" + termObject.primary;
}
-
termObject.url = "https://www.embl.org/search/#stq=" + termObject.name + urlFacet + "&origin=breadcrumbTaxonomy";
}
-
return termObject;
}
+
/**
* Take a term and get its parent term UUID
* todo: this lookup is, perhaps, flawed as it gives us each ancestor, irregardless
@@ -2849,8 +2723,6 @@ function emblBreadcrumbAppend(breadcrumbTarget, termName, facet, type) {
* @param {string} [facet] - who, what, where
* @param {object} [lastParent] - term object to prevent recursion, optional
*/
-
-
function getBreadcrumbParentTerm(parents, facet, lastParent) {
// var parentTodos = {
// // 1: 'Respect the parent term context: who/what/where'
@@ -2862,36 +2734,31 @@ function emblBreadcrumbAppend(breadcrumbTarget, termName, facet, type) {
/* eslint-disable no-redeclare */
var lastParent = lastParent || {}; // track last insertion to prevent recursion
-
/* eslint-enable no-redeclare */
if (parents == undefined || parents == null) {
// no parent breadcrumb preset, exiting
return;
}
-
function insertParent(activeParent) {
if (activeParent == undefined || activeParent == null) {
console.warn("embl-js-breadcumbs-lookup: No matching parent found; Stopping parent lookup.");
return;
}
-
activeParent.url = activeParent.url || "#no_url_specified";
-
if (activeParent.name.indexOf(" root term") > 0) {
// if we've reached a root term, abort lookups and don't insert a root term as a crumb
return;
}
-
if (activeParent.primary == facet) {
// only insert crumb if it respects the original term context: who/what/where
if (activeParent.uuid != lastParent.uuid) {
// no recursive output
emblBreadcrumbPrimary.innerHTML = formatBreadcrumb(activeParent.name_display, activeParent.url, false) + emblBreadcrumbPrimary.innerHTML;
}
- } // get parents of parent
-
+ }
+ // get parents of parent
if (activeParent.parents) {
if (activeParent.uuid != lastParent.uuid) {
lastParent = activeParent;
@@ -2903,9 +2770,7 @@ function emblBreadcrumbAppend(breadcrumbTarget, termName, facet, type) {
}
}
}
-
var activeParent;
-
if (parents[facet]) {
// if a parent has structured who/what/where parents
activeParent = emblTaxonomy.terms[parents[facet]];
@@ -2919,9 +2784,9 @@ function emblBreadcrumbAppend(breadcrumbTarget, termName, facet, type) {
insertParent(activeParent);
});
}
-
return;
}
+
/**
* Generate HTML for a new breadcrumb
* @example formatBreadcrumb(term,breadcrumbUrl)
@@ -2929,90 +2794,84 @@ function emblBreadcrumbAppend(breadcrumbTarget, termName, facet, type) {
* @param {string} [breadcrumbUrl] - a fully formed URL, or 'null' to not make a link
* @param {boolean} [current] - if the breadcrumb is the current page
*/
-
-
function formatBreadcrumb(termName, breadcrumbUrl, current) {
if (termName == "" || termName == "none") {
// if no term, do nothing
return "";
}
-
if (current) {
current = " aria-current=\"location\"";
}
-
var newBreadcrumb = "
";
return newBreadcrumb;
}
-
var currentTerm = getCurrentTerm(termName);
/* eslint-disable no-unused-vars */
-
var breadcrumbId = currentTerm.uuid,
- breadcrumbUrl = currentTerm.url,
- breadcrumbParents = currentTerm.parents,
- breadcrumbCurrent = false;
+ breadcrumbUrl = currentTerm.url,
+ breadcrumbParents = currentTerm.parents,
+ breadcrumbCurrent = false;
/* eslint-enable no-unused-vars */
- // narrow down to the first matching element
+ // narrow down to the first matching element
breadcrumbTarget = breadcrumbTarget[0];
-
if (type == "primary") {
// save it
- primaryBreadcrumb = currentTerm; // don't show path of breadcrumb if it is the current path
+ primaryBreadcrumb = currentTerm;
+ // don't show path of breadcrumb if it is the current path
if (new URL(breadcrumbUrl).pathname == window.location.pathname) {
breadcrumbUrl = null;
- } // in this context the active page is always "current"
-
+ }
- breadcrumbCurrent = true; // add breadcrumb
+ // in this context the active page is always "current"
+ breadcrumbCurrent = true;
- emblBreadcrumbPrimary.innerHTML += formatBreadcrumb(currentTerm.name_display, breadcrumbUrl, breadcrumbCurrent); // fetch parents for primary path
+ // add breadcrumb
+ emblBreadcrumbPrimary.innerHTML += formatBreadcrumb(currentTerm.name_display, breadcrumbUrl, breadcrumbCurrent);
+ // fetch parents for primary path
getBreadcrumbParentTerm(breadcrumbParents, facet);
} else if (type == "related") {
// add breadcrumb
emblBreadcrumbRelated.innerHTML += formatBreadcrumb(currentTerm.name_display, breadcrumbUrl, breadcrumbCurrent);
}
}
-
function emblBreadcrumbs() {
// We start the breadcrumbs by first getting the EMBL taxonomy.
// todo: some sort of caching here, perhaps we write to local storage.
// todo: abstract this out into its own `embl-taxonomy` component?
emblGetTaxonomy().then(function (response) {
- emblTaxonomy = JSON.parse(response); // Preprocess the emblTaxonomy for some cleanup tasks
+ emblTaxonomy = JSON.parse(response);
+ // Preprocess the emblTaxonomy for some cleanup tasks
Array.prototype.forEach.call(Object.keys(emblTaxonomy.terms), function (termId) {
- var term = emblTaxonomy.terms[termId]; // If `name_display` is not set, use the internal name
-
- if (term.name_display === "") term.name_display = term.name; // handle null URL
-
+ var term = emblTaxonomy.terms[termId];
+ // If `name_display` is not set, use the internal name
+ if (term.name_display === "") term.name_display = term.name;
+ // handle null URL
if (term.url === "") term.url = "#no_url_specified";
- }); // Invoke embl-content-meta-properties function to pull tags from page
+ });
+ // Invoke embl-content-meta-properties function to pull tags from page
emblBreadcrumbsLookup(emblContentMetaProperties_Read());
}, function (error) {
console.warn("Failed to get EMBL ontology", error);
var emblBreadcrumbTarget = document.querySelectorAll("[data-embl-js-breadcrumbs-lookup]");
-
if (emblBreadcrumbTarget.length > 0) {
emblBreadcrumbTarget[0].innerHTML = "";
}
});
-} // Prepend polyfill for IE
-// Source: https://github.com/jserz/js_piece/blob/master/DOM/ParentNode/prepend()/prepend().md
-
+}
+// Prepend polyfill for IE
+// Source: https://github.com/jserz/js_piece/blob/master/DOM/ParentNode/prepend()/prepend().md
(function (arr) {
arr.forEach(function (item) {
/* eslint-disable no-prototype-builtins */
@@ -3020,15 +2879,13 @@ function emblBreadcrumbs() {
return;
}
/* eslint-enable no-prototype-builtins */
-
-
Object.defineProperty(item, "prepend", {
configurable: true,
enumerable: true,
writable: true,
value: function prepend() {
var argArr = Array.prototype.slice.call(arguments),
- docFrag = document.createDocumentFragment();
+ docFrag = document.createDocumentFragment();
argArr.forEach(function (argItem) {
var isNode = argItem instanceof Node;
docFrag.appendChild(isNode ? argItem : document.createTextNode(String(argItem)));
@@ -3037,7 +2894,9 @@ function emblBreadcrumbs() {
}
});
});
-})([Element.prototype, Document.prototype, DocumentFragment.prototype]); // Run it on default
+})([Element.prototype, Document.prototype, DocumentFragment.prototype]);
+
+// Run it on default
// emblBreadcrumbs();
/*
@@ -3047,8 +2906,6 @@ function emblBreadcrumbs() {
* Import this as a quick way to get *everything*,
*
*/
-
-
vfBanner();
vfMastheadSetStyle();
var vfGaTrackOptions = {
@@ -3063,5 +2920,6 @@ vfGaIndicateLoaded(vfGaTrackOptions);
vfTabs();
vfNavigationOnThisPage();
emblContentHub();
-emblBreadcrumbs(); // if you use embl-content-hub-loader, it will automatically invoke emblNotifications
+emblBreadcrumbs();
+// if you use embl-content-hub-loader, it will automatically invoke emblNotifications
// emblNotifications();
\ No newline at end of file