const _ = require('lodash') const cheerio = require('cheerio') /* global WIKI */ module.exports = { async render() { const $ = cheerio.load(this.input) if ($.root().children().length < 1) { return '' } for (let child of this.children) { const renderer = require(`../${_.kebabCase(child.key)}/renderer.js`) renderer.init($, child.config) } // -------------------------------- // Detect internal / external links // -------------------------------- let internalRefs = [] const reservedPrefixes = /^\/[a-z]\//gi const isHostSet = WIKI.config.host.length > 7 && WIKI.config.host !== 'http://' if (!isHostSet) { WIKI.logger.warn('Host is not set. You must set the Site Host under General in the Administration Area!') } $('a').each((i, elm) => { let href = $(elm).attr('href') // -> Ignore empty / anchor links if (!href || href.length < 1 || href.indexOf('#') === 0 || href.indexOf('mailto:') === 0) { return } // -> Strip host from local links if (isHostSet && href.indexOf(WIKI.config.host) === 0) { href = href.replace(WIKI.config.host, '') } // -> Assign local / external tag if (href.indexOf('://') < 0) { // -> Remove trailing slash if (_.endsWith('/')) { href = href.slice(0, -1) } // -> Check for system prefix if (!reservedPrefixes.test(href)) { $(elm).addClass(`is-internal-link`) // -> Reformat paths if (href.indexOf('/') !== 0) { href = `/${this.page.localeCode}/${this.page.path}/${href}` } else if (href.charAt(3) !== '/') { href = `/${this.page.localeCode}${href}` } // -> Save internal references internalRefs.push({ localeCode: href.substring(1, 3), path: _.head(href.substring(4).split('#')) }) } else { $(elm).addClass(`is-system-link`) } } else { $(elm).addClass(`is-external-link`) } // -> Update element $(elm).attr('href', href) }) // -------------------------------- // Detect internal link states // -------------------------------- const pastLinks = await this.page.$relatedQuery('links') if (internalRefs.length > 0) { // -> Find matching pages const results = await WIKI.models.pages.query().column('id', 'path', 'localeCode').where(builder => { internalRefs.forEach((ref, idx) => { if (idx < 1) { builder.where(ref) } else { builder.orWhere(ref) } }) }) // -> Apply tag to internal links for found pages $('a.is-internal-link').each((i, elm) => { const href = $(elm).attr('href') const hrefObj = { localeCode: href.substring(1, 3), path: _.head(href.substring(4).split('#')) } if (_.some(results, r => { return r.localeCode === hrefObj.localeCode && r.path === hrefObj.path })) { $(elm).addClass(`is-valid-page`) } else { $(elm).addClass(`is-invalid-page`) } }) // -> Add missing links const missingLinks = _.differenceWith(internalRefs, pastLinks, (nLink, pLink) => { return nLink.localeCode === pLink.localeCode && nLink.path === pLink.path }) if (missingLinks.length > 0) { if (WIKI.config.db.type === 'postgres') { await WIKI.models.pageLinks.query().insert(missingLinks.map(lnk => ({ pageId: this.page.id, path: lnk.path, localeCode: lnk.localeCode }))) } else { for (const lnk of missingLinks) { await WIKI.models.pageLinks.query().insert({ pageId: this.page.id, path: lnk.path, localeCode: lnk.localeCode }) } } } } // -> Remove outdated links if (pastLinks) { const outdatedLinks = _.differenceWith(pastLinks, internalRefs, (nLink, pLink) => { return nLink.localeCode === pLink.localeCode && nLink.path === pLink.path }) if (outdatedLinks.length > 0) { await WIKI.models.pageLinks.query().delete().whereIn('id', _.map(outdatedLinks, 'id')) } } return $.html('body').replace('', '').replace('', '') } }