| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 | 
							- const _ = require('lodash')
 
- const cheerio = require('cheerio')
 
- const uslug = require('uslug')
 
- const pageHelper = require('../../../helpers/page')
 
- const URL = require('url').URL
 
- const mustacheRegExp = /(\{|{?){2}(.+?)(\}|}?){2}/i
 
- /* global WIKI */
 
- module.exports = {
 
-   async render() {
 
-     const $ = cheerio.load(this.input, {
 
-       decodeEntities: true
 
-     })
 
-     if ($.root().children().length < 1) {
 
-       return ''
 
-     }
 
-     // --------------------------------
 
-     // STEP: PRE
 
-     // --------------------------------
 
-     for (let child of _.reject(this.children, ['step', 'post'])) {
 
-       const renderer = require(`../${_.kebabCase(child.key)}/renderer.js`)
 
-       await renderer.init($, child.config)
 
-     }
 
-     // --------------------------------
 
-     // Detect internal / external links
 
-     // --------------------------------
 
-     let internalRefs = []
 
-     const reservedPrefixes = /^\/[a-z]\//i
 
-     const exactReservedPaths = /^\/[a-z]$/i
 
-     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, e-mail addresses, and telephone numbers
 
-       if (!href || href.length < 1 || href.indexOf('#') === 0 ||
 
-         href.indexOf('mailto:') === 0 || href.indexOf('tel:') === 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) || exactReservedPaths.test(href)) {
 
-           $(elm).addClass(`is-system-link`)
 
-         } else if (href.indexOf('.') >= 0) {
 
-           $(elm).addClass(`is-asset-link`)
 
-         } else {
 
-           let pagePath = null
 
-           // -> Add locale prefix if using namespacing
 
-           if (WIKI.config.lang.namespacing) {
 
-             // -> Reformat paths
 
-             if (href.indexOf('/') !== 0) {
 
-               if (this.config.absoluteLinks) {
 
-                 href = `/${this.page.localeCode}/${href}`
 
-               } else {
 
-                 href = (this.page.path === 'home') ? `/${this.page.localeCode}/${href}` : `/${this.page.localeCode}/${this.page.path}/${href}`
 
-               }
 
-             } else if (href.charAt(3) !== '/') {
 
-               href = `/${this.page.localeCode}${href}`
 
-             }
 
-             try {
 
-               const parsedUrl = new URL(`http://x${href}`)
 
-               pagePath = pageHelper.parsePath(parsedUrl.pathname)
 
-             } catch (err) {
 
-               return
 
-             }
 
-           } else {
 
-             // -> Reformat paths
 
-             if (href.indexOf('/') !== 0) {
 
-               if (this.config.absoluteLinks) {
 
-                 href = `/${href}`
 
-               } else {
 
-                 href = (this.page.path === 'home') ? `/${href}` : `/${this.page.path}/${href}`
 
-               }
 
-             }
 
-             try {
 
-               const parsedUrl = new URL(`http://x${href}`)
 
-               pagePath = pageHelper.parsePath(parsedUrl.pathname)
 
-             } catch (err) {
 
-               return
 
-             }
 
-           }
 
-           // -> Save internal references
 
-           internalRefs.push({
 
-             localeCode: pagePath.locale,
 
-             path: pagePath.path
 
-           })
 
-           $(elm).addClass(`is-internal-link`)
 
-         }
 
-       } else {
 
-         $(elm).addClass(`is-external-link`)
 
-         if (this.config.openExternalLinkNewTab) {
 
-           $(elm).attr('target', '_blank')
 
-           $(elm).attr('rel', this.config.relAttributeExternalLink)
 
-         }
 
-       }
 
-       // -> 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')
 
-         let hrefObj = {}
 
-         try {
 
-           const parsedUrl = new URL(`http://x${href}`)
 
-           hrefObj = pageHelper.parsePath(parsedUrl.pathname)
 
-         } catch (err) {
 
-           return
 
-         }
 
-         if (_.some(results, r => {
 
-           return r.localeCode === hrefObj.locale && 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'))
 
-       }
 
-     }
 
-     // --------------------------------
 
-     // Add header handles
 
-     // --------------------------------
 
-     let headers = []
 
-     $('h1,h2,h3,h4,h5,h6').each((i, elm) => {
 
-       let headerSlug = uslug($(elm).text())
 
-       // -> If custom ID is defined, try to use that instead
 
-       if ($(elm).attr('id')) {
 
-         headerSlug = $(elm).attr('id')
 
-       }
 
-       // -> Cannot start with a number (CSS selector limitation)
 
-       if (headerSlug.match(/^\d/)) {
 
-         headerSlug = `h-${headerSlug}`
 
-       }
 
-       // -> Make sure header is unique
 
-       if (headers.indexOf(headerSlug) >= 0) {
 
-         let isUnique = false
 
-         let hIdx = 1
 
-         while (!isUnique) {
 
-           const headerSlugTry = `${headerSlug}-${hIdx}`
 
-           if (headers.indexOf(headerSlugTry) < 0) {
 
-             isUnique = true
 
-             headerSlug = headerSlugTry
 
-           }
 
-           hIdx++
 
-         }
 
-       }
 
-       // -> Add anchor
 
-       $(elm).attr('id', headerSlug).addClass('toc-header')
 
-       $(elm).prepend(`<a class="toc-anchor" href="#${headerSlug}">¶</a> `)
 
-       headers.push(headerSlug)
 
-     })
 
-     // --------------------------------
 
-     // Wrap non-empty root text nodes
 
-     // --------------------------------
 
-     $('body').contents().toArray().forEach(item => {
 
-       if (item && item.type === 'text' && item.parent.name === 'body' && item.data !== `\n` && item.data !== `\r`) {
 
-         $(item).wrap('<div></div>')
 
-       }
 
-     })
 
-     // --------------------------------
 
-     // Escape mustache expresions
 
-     // --------------------------------
 
-     function iterateMustacheNode (node) {
 
-       const list = $(node).contents().toArray()
 
-       list.forEach(item => {
 
-         if (item && item.type === 'text') {
 
-           const rawText = $(item).text().replace(/\r?\n|\r/g, '')
 
-           if (mustacheRegExp.test(rawText)) {
 
-             $(item).parent().attr('v-pre', true)
 
-           }
 
-         } else {
 
-           iterateMustacheNode(item)
 
-         }
 
-       })
 
-     }
 
-     iterateMustacheNode($.root())
 
-     $('pre').each((idx, elm) => {
 
-       $(elm).attr('v-pre', true)
 
-     })
 
-     // --------------------------------
 
-     // STEP: POST
 
-     // --------------------------------
 
-     let output = decodeEscape($.html('body').replace('<body>', '').replace('</body>', ''))
 
-     for (let child of _.sortBy(_.filter(this.children, ['step', 'post']), ['order'])) {
 
-       const renderer = require(`../${_.kebabCase(child.key)}/renderer.js`)
 
-       output = await renderer.init(output, child.config)
 
-     }
 
-     return output
 
-   }
 
- }
 
- function decodeEscape (string) {
 
-   return string.replace(/&#x([0-9a-f]{1,6});/ig, (entity, code) => {
 
-     code = parseInt(code, 16)
 
-     // Don't unescape ASCII characters, assuming they're encoded for a good reason
 
-     if (code < 0x80) return entity
 
-     return String.fromCodePoint(code)
 
-   })
 
- }
 
 
  |