lib/outlinkCollector.js
/** @ignore */
let __outlinksSet__;
/** @ignore */
const ignoredSchemes = [
'about:',
'data:',
'mailto:',
'javascript:',
'js:',
'{',
'*',
'ftp:',
'tel:',
];
/** @ignore */
const goodSchemes = { 'http:': true, 'https:': true };
/** @ignore */
const outlinkSelector = 'a[href], area[href]';
/** @ignore */
let outLinkURLParser;
/** @ignore */
let didInit = false;
/**
* @ignore
*/
function initOutlinkCollection() {
didInit = true;
outLinkURLParser = new URL('about:blank');
if (window.$wbOutlinkSet$ == null) {
__outlinksSet__ = new Set();
Object.defineProperty(window, '$wbOutlinkSet$', {
value: __outlinksSet__,
enumerable: false,
});
} else {
window.$wbOutlinkSet$.clear();
__outlinksSet__ = window.$wbOutlinkSet$;
}
if (typeof window.$wbOutlinks$ === 'undefined') {
Object.defineProperty(window, '$wbOutlinks$', {
get() {
const outlinks = Array.from(__outlinksSet__);
__outlinksSet__.clear();
return outlinks;
},
set() {},
enumerable: false,
});
}
}
/**
* @ignore
*/
function shouldIgnoreLink(test) {
for (let i = 0; i < ignoredSchemes.length; ++i) {
if (test.startsWith(ignoredSchemes[i])) {
return true;
}
}
let parsed = true;
try {
outLinkURLParser.href = test;
} catch (error) {
parsed = false;
}
return !(parsed && goodSchemes[outLinkURLParser.protocol]);
}
/**
* Add the array/nodelist of A or Anchor tags href properties the collected outlinks
* @param {Array<HTMLAnchorElement|HTMLAreaElement>|NodeList<HTMLAnchorElement|HTMLAreaElement>} toAdd - The elements with
* href properties that are to be added to the collected outlinks
*/
export function addOutLinks(toAdd) {
if (window.$WBNOOUTLINKS) {
return;
}
if (!didInit) initOutlinkCollection();
let href;
for (var i = 0; i < toAdd.length; i++) {
href = toAdd[i].href.trim();
if (href && !__outlinksSet__.has(href) && !shouldIgnoreLink(href)) {
__outlinksSet__.add(href);
}
}
}
/**
* Collects the outlinks from the document
*/
export function collectOutlinksFromDoc() {
if (window.$WBNOOUTLINKS) {
return;
}
if (!didInit) initOutlinkCollection();
addOutLinks(document.querySelectorAll(outlinkSelector));
}
/**
* Collects outlinks form the supplied element
* @param {Element|Document} queryFrom - The element to collect outlinks
* from
*/
export function collectOutlinksFrom(queryFrom) {
if (window.$WBNOOUTLINKS) {
return;
}
if (!didInit) initOutlinkCollection();
addOutLinks(queryFrom.querySelectorAll(outlinkSelector));
}
/**
* Add the URL or href value of the supplied argument
* @param {HTMLAnchorElement|HTMLAreaElement|string} elemOrString - The
* element with href property or string to add to the collected outlinks
*/
export function addOutlink(elemOrString) {
if (window.$WBNOOUTLINKS) {
return;
}
if (!didInit) initOutlinkCollection();
const href = (elemOrString.href || elemOrString).trim();
if (href && !__outlinksSet__.has(href) && !shouldIgnoreLink(href)) {
__outlinksSet__.add(href);
}
}